Skip to content

Instantly share code, notes, and snippets.

View swhitty's full-sized avatar

Simon Whitty swhitty

View GitHub Profile
@swhitty
swhitty / UniqueChanges.swift
Last active January 29, 2024 07:01
PropertyWrapper that can be applied to `Equatable` properties of `ObservableObject` to notify observers of unique changes.
/// PropertyWrapper that can be applied to `Equatable` properties of `ObservableObject` to notify observers of unique changes
@propertyWrapper
struct UniqueChanges<Element: Equatable> {
init(wrappedValue: Element) {
self._wrappedValue = wrappedValue
}
@available(*, unavailable, message: "@UniqueChanges can only be applied to types that conform to `ObservableObject`")
var wrappedValue: Element {
@swhitty
swhitty / Mutex.swift
Last active October 14, 2025 15:20
Backports the Swift 6 type Mutex<Value> to all Apple platforms that support OSAllocatedUnfairLock
// Backports the Swift 6 type Mutex<Value> to all Darwin platforms via OSAllocatedUnfairLock.
// Lightweight version of https://github.com/swhitty/swift-mutex
// Feel free to use any part of this gist.
import struct os.OSAllocatedUnfairLock
// Backports the Swift 6.0 Mutex API
@available(iOS, introduced: 16.0, deprecated: 18.0, message: "use Mutex from Synchronization module")
@available(macOS, introduced: 13.0, deprecated: 15.0, message: "use Mutex from Synchronization module")
public struct Mutex<Value: ~Copyable>: @unchecked Sendable, ~Copyable {
@swhitty
swhitty / junit.swift
Last active November 5, 2025 05:52
Script to convert Xcode 16 results JSON in to Junit XML
#!/usr/bin/swift
import Foundation
let resultsJSON = CommandLine.arguments.count > 1 ? URL(filePath: CommandLine.arguments[1]) : nil
guard let resultsJSON else {
print("usage: ./junit.swift <test_results.json>")
exit(70)
}
public extension Task where Failure == Never {
/// Create and immediately start running a new detached task on the @MainActor.
///
/// If the current actor is @MainActor, the spawned task immediately takes over
/// execution in a synchronous manner, before returning to the calling method at the
/// first suspension point.
///
/// If the current actor is not @MainActor then behaviour is the similar to using `Task { }`
///