///|
suberror Cause {
  /// A leaf node: wraps a non-`Cause` source `Error`.
  Cause(msg~ : String, source~ : Error, loc~ : SourceLoc)
  /// A chain link: wraps a `Cause` and another error.
  Causes(msg~ : String, err~ : Error, source~ : Cause, loc~ : SourceLoc)
} derive(Debug)

///|
pub impl Show for Cause with fn output(self, logger) {
  fn cause_to_string(msg : String, source : Error, loc : SourceLoc) {
    if !msg.is_empty() {
      logger.write_string("'\{msg}' ")
    }
    logger.write_string("at \{loc}")
    match source {
      Failure => ()
      _ => logger.write_string(" caused by `\{source}`")
    }
  }
  match self {
    Cause(msg~, source~, loc~) => {
      logger.write_string("Error ")
      cause_to_string(msg, source, loc)
    }
    Causes(msg~, err~, source~, loc~) => {
      logger.write_string("Error ")
      cause_to_string(msg, err, loc)
      for cause = source {
        logger.write_string("\n  |> error ")
        match cause {
          Cause(msg~, source~, loc~) => break cause_to_string(msg, source, loc)
          Causes(msg~, err~, source~, loc~) => {
            cause_to_string(msg, err, loc)
            continue source
          }
        }
      }
    }
  }
}