Skip to content

Instantly share code, notes, and snippets.

@victor-pavlychko
Last active June 13, 2019 16:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save victor-pavlychko/d037745acfe2abd074132477c383a79d to your computer and use it in GitHub Desktop.
Save victor-pavlychko/d037745acfe2abd074132477c383a79d to your computer and use it in GitHub Desktop.
import Foundation
public struct ErrorSourceReference {
public let file: StaticString
public let line: Int
public var location: String {
return "\(file):\(line)"
}
public let function: StaticString
@_transparent
public init(file: StaticString = #file, line: Int = #line, function: StaticString = #function) {
self.file = file
self.line = line
self.function = function
}
}
extension ErrorSourceReference {
public var description: String {
return "`\(function)` at `\(location)`"
}
}
public struct ErrorCallStackSymbols {
#if DEBUG || targetEnvironment(simulator)
public static var isCallStackReportingEnabled = true
#else
public static var isCallStackReportingEnabled = false
#endif
public let callStackSymbols: [String]
@_transparent
public init() {
if type(of: self).isCallStackReportingEnabled {
self.callStackSymbols = Thread.callStackSymbols
} else {
self.callStackSymbols = []
}
}
}
extension ErrorCallStackSymbols: CustomStringConvertible {
public var description: String {
return callStackSymbols.joined(separator: "\n")
}
}
public struct GenericError: Error {
public let message: String?
public let wrapped: Error?
public let sourceReference: ErrorSourceReference
public let callStackSymbols: ErrorCallStackSymbols
public init(_ message: String? = nil, wrapping wrapped: Error? = nil, file: StaticString = #file, line: Int = #line, function: StaticString = #function) {
self.message = message
self.wrapped = wrapped
self.sourceReference = .init(file: file, line: line, function: function)
self.callStackSymbols = .init()
}
}
extension GenericError: CustomStringConvertible {
public var description: String {
let message = self.message ?? "Error"
return "\(message) in \(sourceReference)"
}
}
extension Error {
@_transparent
public func withSourceReference(file: StaticString = #file, line: Int = #line, function: StaticString = #function) -> Error {
return GenericError(wrapping: self, file: file, line: line, function: function)
}
}
extension GenericError: CustomDebugStringConvertible {
public var debugDescription: String {
var lines: [String] = [
description,
]
if !callStackSymbols.callStackSymbols.isEmpty {
lines.append(contentsOf: [
"",
"Call Stack Symbols:",
callStackSymbols.description,
])
}
if let wrapped = wrapped {
lines.append(contentsOf: [
"",
"Underlying Error:",
wrapped.localizedDescription
.components(separatedBy: .newlines)
.map { "> \($0)" }
.joined(separator: "\n")
])
}
return lines
.compactMap { $0 }
.joined(separator: "\n")
}
}
extension GenericError: LocalizedError {
public var errorDescription: String? {
return debugDescription
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment