Last active
August 21, 2020 14:00
-
-
Save rnapier/39007fd0fee47ca6966aafa86775ca46 to your computer and use it in GitHub Desktop.
AssertionFailure as a type
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// | |
/// Boring setup. See below for the good parts | |
/// | |
public class Logger { | |
public static let root = Logger(subsystem: .none, parent: nil) | |
public let subsystem: Subsystem | |
public let parent: Logger? | |
public init(subsystem: Subsystem, parent: Logger? = .root) { | |
self.subsystem = subsystem | |
self.parent = parent | |
} | |
// Fatals should go through something else like fatalError. | |
fileprivate func fatal(_ message: String, error: Error?, data: [String: Any] = [:], file: String = #file, line: Int = #line, function: String = #function) { | |
// Do what you want here | |
print("Logging: \(message)") | |
// All the gory internals of the logger.... | |
// logInternal(message, data: add(error: error, to: data), level: .fatal, file: file, line: line, function: function) | |
// flush() | |
} | |
} | |
public struct Subsystem: Equatable, CustomStringConvertible { | |
public let name: String | |
public init(name: String) { | |
self.name = name | |
} | |
public var description: String { return name } | |
} | |
extension Subsystem { | |
public static var none: Subsystem { return Subsystem(name: "") } | |
} | |
public let Log = Logger.root | |
/// End boring setup. | |
/// | |
/// The Good Parts | |
/// | |
// WARNING: Constructing AssertionFailure calls assertionFailure() | |
struct AssertionFailure: Error { | |
let message: String | |
let file: StaticString | |
let line: Int | |
init(message: String, file: StaticString, line: Int) { | |
Swift.assertionFailure(message, file: file, line: UInt(line)) | |
self.message = message | |
self.file = file | |
self.line = line | |
} | |
} | |
extension Logger { | |
@discardableResult | |
public func assertionFailure(_ message: String = "", error: Error? = nil, data: [String: Any] = [:], file: StaticString = #file, line: Int = #line, function: String = #function) | |
-> Error { | |
// First, log it (and flush all the destinations) | |
fatal(message, error: error, data: data, file: String(describing: file), line: line) | |
// And then either crash (assertionFailure) or return it as an Error (which can be thrown) | |
return AssertionFailure(message: message, file: file, line: line) | |
} | |
} | |
// We can throw AssertionFailures | |
throw Log.assertionFailure("Bad") | |
// Or use them as Error values | |
completion(.failure(Log.assertionFailure("Bad"))) | |
// But also, they can be used without a logging system | |
throw AssertionFailure(message: "Bad") | |
// Probably possible to wrap `assert` in here somehow more directly. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment