Last active
May 29, 2021 02:33
-
-
Save swhitty/2f170d31a5b1385807d409d32acd3a9b to your computer and use it in GitHub Desktop.
This file contains hidden or 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
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