|
| 1 | +// Source: Point-Free, Swift Composable Architecture, RuntimeWarnings.swift |
| 2 | +// https://github.com/pointfreeco/swift-composable-architecture/blob/399bc83dcfc7bdcee99f7f6cc0a687ca29e8494b/Sources/ComposableArchitecture/Internal/RuntimeWarnings.swift |
| 3 | +// |
| 4 | +// Based on: Point-Free, Unobtrusive runtime warnings for libraries (2022-01-03) |
| 5 | +// https://www.pointfree.co/blog/posts/70-unobtrusive-runtime-warnings-for-libraries |
| 6 | + |
| 7 | +#if DEBUG |
| 8 | + import os |
| 9 | + import XCTestDynamicOverlay |
| 10 | + |
| 11 | + // NB: Xcode runtime warnings offer a much better experience than traditional assertions and |
| 12 | + // breakpoints, but Apple provides no means of creating custom runtime warnings ourselves. |
| 13 | + // To work around this, we hook into SwiftUI's runtime issue delivery mechanism, instead. |
| 14 | + // |
| 15 | + // Feedback filed: https://gist.github.com/stephencelis/a8d06383ed6ccde3e5ef5d1b3ad52bbc |
| 16 | + private let rw = ( |
| 17 | + dso: { () -> UnsafeMutableRawPointer in |
| 18 | + let count = _dyld_image_count() |
| 19 | + for i in 0..<count { |
| 20 | + if let name = _dyld_get_image_name(i) { |
| 21 | + let swiftString = String(cString: name) |
| 22 | + if swiftString.hasSuffix("/SwiftUI") { |
| 23 | + if let header = _dyld_get_image_header(i) { |
| 24 | + return UnsafeMutableRawPointer(mutating: UnsafeRawPointer(header)) |
| 25 | + } |
| 26 | + } |
| 27 | + } |
| 28 | + } |
| 29 | + return UnsafeMutableRawPointer(mutating: #dsohandle) |
| 30 | + }(), |
| 31 | + log: OSLog(subsystem: "com.apple.runtime-issues", category: "ComposableArchitecture") |
| 32 | + ) |
| 33 | +#endif |
| 34 | + |
| 35 | +@_transparent |
| 36 | +@inline(__always) |
| 37 | +func runtimeWarning( |
| 38 | + _ message: @autoclosure () -> StaticString, |
| 39 | + _ args: @autoclosure () -> [CVarArg] = [], |
| 40 | + file: StaticString? = nil, |
| 41 | + line: UInt? = nil |
| 42 | +) { |
| 43 | + #if DEBUG |
| 44 | + let message = message() |
| 45 | + if _XCTIsTesting { |
| 46 | + if let file = file, let line = line { |
| 47 | + XCTFail(String(format: "\(message)", arguments: args()), file: file, line: line) |
| 48 | + } else { |
| 49 | + XCTFail(String(format: "\(message)", arguments: args())) |
| 50 | + } |
| 51 | + } else { |
| 52 | + unsafeBitCast( |
| 53 | + os_log as (OSLogType, UnsafeRawPointer, OSLog, StaticString, CVarArg...) -> Void, |
| 54 | + to: ((OSLogType, UnsafeRawPointer, OSLog, StaticString, [CVarArg]) -> Void).self |
| 55 | + )(.fault, rw.dso, rw.log, message, args()) |
| 56 | + } |
| 57 | + #endif |
| 58 | +} |
0 commit comments