// Copyright 2022-present 650 Industries. All rights reserved. /** An exception that may have been caused by another error. */ public protocol ChainableException: Error, AnyObject { /** The direct cause of the exception. */ var cause: Error? { get set } /** The first error that started the chain of exceptions. */ var rootCause: Error? { get } /** Sets the direct cause of the exception and returns itself. */ func causedBy(_ error: Error?) -> Self /** Tells whether any of the cause in chain is of given type. */ func isCausedBy(_ errorType: ErrorType.Type) -> Bool } public extension ChainableException { var rootCause: Error? { if let cause = cause as? ChainableException { return cause.rootCause ?? cause } return cause } @discardableResult func causedBy(_ error: Error?) -> Self { cause = error ?? cause return self } func isCausedBy(_ errorType: ErrorType.Type) -> Bool { if cause is ErrorType { return true } if let cause = cause as? ChainableException { return cause.isCausedBy(errorType) } return false } }