Skip to content

Instantly share code, notes, and snippets.

@swhitty
Last active May 29, 2021 02:33
Show Gist options
  • Save swhitty/2f170d31a5b1385807d409d32acd3a9b to your computer and use it in GitHub Desktop.
Save swhitty/2f170d31a5b1385807d409d32acd3a9b to your computer and use it in GitHub Desktop.
import Foundation
/// Property wrapper that protects the wrapped value with `NSLock`.
/// Non trivial read/writes should access via `projectedValue` which acquires lock
/// and runs the supplied closure against it.
///
/// ```
/// @Locked var count: Int
/// $count { $0 = doSomething($0) }
/// ```
@propertyWrapper
public struct Locked<Value> {
/// Projects generic function that is performed with acquired lock.
public let projectedValue: Unlock
public init(wrappedValue initialValue: Value) {
self.projectedValue = Unlock(wrappedValue: initialValue)
}
public var wrappedValue: Value {
get { projectedValue { $0 } }
set { projectedValue { $0 = newValue } }
}
}
extension Locked {
public final class Unlock {
private let lock = NSLock()
private var value: Value
fileprivate init(wrappedValue initialValue: Value) {
self.value = initialValue
}
/// Allows `Unlock` instances to be called as functions. SE-0253.
/// - Parameter transform: Closure is performed when lock is acquired. `wrappedValue` can be mutated
/// - Returns: Forwards returned value from transform closure
@discardableResult
public func callAsFunction<U>(_ transform: (inout Value) throws -> U) rethrows -> U {
lock.lock()
defer { lock.unlock() }
return try transform(&value)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment