import Foundation private protocol Lock { func lock() func unlock() } extension Lock { /// Executes a closure returning a value while acquiring the lock. /// /// - Parameter closure: The closure to run. /// /// - Returns: The value the closure generated. func around(_ closure: () -> T) -> T { lock() defer { unlock() } return closure() } /// Execute a closure while acquiring the lock. /// /// - Parameter closure: The closure to run. func around(_ closure: () -> Void) { lock() defer { unlock() } closure() } } /// An `os_unfair_lock` wrapper. final class UnfairLock: Lock { private let unfairLock: os_unfair_lock_t init() { unfairLock = .allocate(capacity: 1) unfairLock.initialize(to: os_unfair_lock()) } deinit { unfairLock.deinitialize(count: 1) unfairLock.deallocate() } fileprivate func lock() { os_unfair_lock_lock(unfairLock) } fileprivate func unlock() { os_unfair_lock_unlock(unfairLock) } } /// A thread-safe wrapper around a value. @propertyWrapper @dynamicMemberLookup final class Protected { private let lock = UnfairLock() private var value: T init(_ value: T) { self.value = value } /// The contained value. Unsafe for anything more than direct read or write. var wrappedValue: T { get { lock.around { value } } set { lock.around { value = newValue } } } var projectedValue: Protected { self } init(wrappedValue: T) { value = wrappedValue } /// Synchronously read or transform the contained value. /// /// - Parameter closure: The closure to execute. /// /// - Returns: The return value of the closure passed. func read(_ closure: (T) -> U) -> U { lock.around { closure(self.value) } } /// Synchronously modify the protected value. /// /// - Parameter closure: The closure to execute. /// /// - Returns: The modified value. @discardableResult func write(_ closure: (inout T) -> U) -> U { lock.around { closure(&self.value) } } subscript(dynamicMember keyPath: WritableKeyPath) -> Property { get { lock.around { value[keyPath: keyPath] } } set { lock.around { value[keyPath: keyPath] = newValue } } } } extension Protected where T: RangeReplaceableCollection { /// Adds a new element to the end of this protected collection. /// /// - Parameter newElement: The `Element` to append. func append(_ newElement: T.Element) { write { (ward: inout T) in ward.append(newElement) } } /// Adds the elements of a sequence to the end of this protected collection. /// /// - Parameter newElements: The `Sequence` to append. func append(contentsOf newElements: S) where S.Element == T.Element { write { (ward: inout T) in ward.append(contentsOf: newElements) } } /// Add the elements of a collection to the end of the protected collection. /// /// - Parameter newElements: The `Collection` to append. func append(contentsOf newElements: C) where C.Element == T.Element { write { (ward: inout T) in ward.append(contentsOf: newElements) } } } extension Protected where T == Data? { /// Adds the contents of a `Data` value to the end of the protected `Data`. /// /// - Parameter data: The `Data` to be appended. func append(_ data: Data) { write { (ward: inout T) in ward?.append(data) } } }