AutorÃa | Ultima modificación | Ver Log |
//// Protected.swift//// Copyright (c) 2014-2020 Alamofire Software Foundation (http://alamofire.org/)//// Permission is hereby granted, free of charge, to any person obtaining a copy// of this software and associated documentation files (the "Software"), to deal// in the Software without restriction, including without limitation the rights// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell// copies of the Software, and to permit persons to whom the Software is// furnished to do so, subject to the following conditions://// The above copyright notice and this permission notice shall be included in// all copies or substantial portions of the Software.//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN// THE SOFTWARE.//import Foundationprivate 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<T>(_ closure: () throws -> T) rethrows -> T {lock(); defer { unlock() }return try closure()}/// Execute a closure while acquiring the lock.////// - Parameter closure: The closure to run.func around(_ closure: () throws -> Void) rethrows {lock(); defer { unlock() }try closure()}}#if os(Linux) || os(Windows)extension NSLock: Lock {}#endif#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)/// An `os_unfair_lock` wrapper.final class UnfairLock: Lock {private let unfairLock: os_unfair_lock_tinit() {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)}}#endif/// A thread-safe wrapper around a value.@propertyWrapper@dynamicMemberLookupfinal class Protected<T> {#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)private let lock = UnfairLock()#elseif os(Linux) || os(Windows)private let lock = NSLock()#endifprivate var value: Tinit(_ 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<T> { 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<U>(_ closure: (T) throws -> U) rethrows -> U {try lock.around { try closure(self.value) }}/// Synchronously modify the protected value.////// - Parameter closure: The closure to execute.////// - Returns: The modified value.@discardableResultfunc write<U>(_ closure: (inout T) throws -> U) rethrows -> U {try lock.around { try closure(&self.value) }}subscript<Property>(dynamicMember keyPath: WritableKeyPath<T, Property>) -> Property {get { lock.around { value[keyPath: keyPath] } }set { lock.around { value[keyPath: keyPath] = newValue } }}subscript<Property>(dynamicMember keyPath: KeyPath<T, Property>) -> Property {lock.around { value[keyPath: keyPath] }}}extension Protected where T == Request.MutableState {/// Attempts to transition to the passed `State`.////// - Parameter state: The `State` to attempt transition to.////// - Returns: Whether the transition occurred.func attemptToTransitionTo(_ state: Request.State) -> Bool {lock.around {guard value.state.canTransitionTo(state) else { return false }value.state = statereturn true}}/// Perform a closure while locked with the provided `Request.State`.////// - Parameter perform: The closure to perform while locked.func withState(perform: (Request.State) -> Void) {lock.around { perform(value.state) }}}