Skip to content

Commit

Permalink
Add runtimeWarn() as public function (#51)
Browse files Browse the repository at this point in the history
* Add runtimeWarn() as public function

Unfortunately without XCTest support

* fix failing tests by hard-coding the language to english
  • Loading branch information
melle committed Sep 11, 2023
1 parent 46b1198 commit 1a129f2
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 5 deletions.
24 changes: 24 additions & 0 deletions FoundationExtensions-Package.xctestplan
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"configurations" : [
{
"id" : "C7A8428F-1827-4A1D-9DEC-D6E40D9EAFEE",
"name" : "Test Scheme Action",
"options" : {
"language" : "en"
}
}
],
"defaultOptions" : {

},
"testTargets" : [
{
"target" : {
"containerPath" : "container:",
"identifier" : "FoundationExtensionsTests",
"name" : "FoundationExtensionsTests"
}
}
],
"version" : 1
}
24 changes: 19 additions & 5 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,29 @@ import PackageDescription

let package = Package(
name: "FoundationExtensions",
platforms: [.iOS(.v12), .macOS(.v10_15), .tvOS(.v13), .watchOS(.v6)],
platforms: [.iOS(.v13), .macOS(.v10_15), .tvOS(.v13), .watchOS(.v6)],
products: [
.library(name: "FoundationExtensions", targets: ["FoundationExtensions"]),
.library(name: "FoundationExtensionsDynamic", type: .dynamic, targets: ["FoundationExtensions"])
],
dependencies: [],
dependencies: [
],
targets: [
.target(name: "FoundationExtensions", dependencies: []),
.target(name: "FoundationExtensionsDynamic", dependencies: []),
.testTarget(name: "FoundationExtensionsTests", dependencies: ["FoundationExtensions"])
.target(
name: "FoundationExtensions",
dependencies: [
]
),
.target(
name: "FoundationExtensionsDynamic",
dependencies: [
]
),
.testTarget(
name: "FoundationExtensionsTests",
dependencies: [
"FoundationExtensions"
]
)
]
)
76 changes: 76 additions & 0 deletions Sources/FoundationExtensions/Runtime/RuntimeWarning.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) 2021 Point-Free, Inc.
//
// RuntimeWarning adopted from from https://www.pointfree.co/blog/posts/70-unobtrusive-runtime-warnings-for-libraries and
// https://github.com/pointfreeco/swift-composable-architecture/blob/main/Sources/ComposableArchitecture/Internal/RuntimeWarnings.swift

import Foundation

extension Notification.Name {
public static let foundationExtensionsRuntimeWarning = Self("FoundationExtensions.runtimeWarning")
}

@_transparent
@inline(__always)
public func runtimeWarning(
_ message: @autoclosure () -> String,
category: String? = "FoundationExtensions"
) {
#if DEBUG
let message = message()
NotificationCenter.default.post(
name: .foundationExtensionsRuntimeWarning,
object: nil,
userInfo: ["message": message]
)
let category = category ?? "Runtime Warning"
#if canImport(os)
os_log(
.fault,
dso: dso,
log: OSLog(subsystem: "com.apple.runtime-issues", category: category),
"%@",
message
)
#else
fputs("\(formatter.string(from: Date())) [\(category)] \(message)\n", stderr)
#endif
#endif
}


#if DEBUG

#if canImport(os)
import os

// NB: Xcode runtime warnings offer a much better experience than traditional assertions and
// breakpoints, but Apple provides no means of creating custom runtime warnings ourselves.
// To work around this, we hook into SwiftUI's runtime issue delivery mechanism, instead.
//
// Feedback filed: https://gist.github.com/stephencelis/a8d06383ed6ccde3e5ef5d1b3ad52bbc
@usableFromInline
let dso = { () -> UnsafeMutableRawPointer in
let count = _dyld_image_count()
for i in 0..<count {
if let name = _dyld_get_image_name(i) {
let swiftString = String(cString: name)
if swiftString.hasSuffix("/SwiftUI") {
if let header = _dyld_get_image_header(i) {
return UnsafeMutableRawPointer(mutating: UnsafeRawPointer(header))
}
}
}
}
return UnsafeMutableRawPointer(mutating: #dsohandle)
}()
#else
import Foundation

@usableFromInline
let formatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:MM:SS.sssZ"
return formatter
}()
#endif
#endif

0 comments on commit 1a129f2

Please sign in to comment.