Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
//
2
//  Protected.swift
3
//
4
//  Copyright (c) 2014-2020 Alamofire Software Foundation (http://alamofire.org/)
5
//
6
//  Permission is hereby granted, free of charge, to any person obtaining a copy
7
//  of this software and associated documentation files (the "Software"), to deal
8
//  in the Software without restriction, including without limitation the rights
9
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
//  copies of the Software, and to permit persons to whom the Software is
11
//  furnished to do so, subject to the following conditions:
12
//
13
//  The above copyright notice and this permission notice shall be included in
14
//  all copies or substantial portions of the Software.
15
//
16
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
//  THE SOFTWARE.
23
//
24
 
25
import Foundation
26
 
27
private protocol Lock {
28
    func lock()
29
    func unlock()
30
}
31
 
32
extension Lock {
33
    /// Executes a closure returning a value while acquiring the lock.
34
    ///
35
    /// - Parameter closure: The closure to run.
36
    ///
37
    /// - Returns:           The value the closure generated.
38
    func around<T>(_ closure: () throws -> T) rethrows -> T {
39
        lock(); defer { unlock() }
40
        return try closure()
41
    }
42
 
43
    /// Execute a closure while acquiring the lock.
44
    ///
45
    /// - Parameter closure: The closure to run.
46
    func around(_ closure: () throws -> Void) rethrows {
47
        lock(); defer { unlock() }
48
        try closure()
49
    }
50
}
51
 
52
#if os(Linux) || os(Windows)
53
 
54
extension NSLock: Lock {}
55
 
56
#endif
57
 
58
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
59
/// An `os_unfair_lock` wrapper.
60
final class UnfairLock: Lock {
61
    private let unfairLock: os_unfair_lock_t
62
 
63
    init() {
64
        unfairLock = .allocate(capacity: 1)
65
        unfairLock.initialize(to: os_unfair_lock())
66
    }
67
 
68
    deinit {
69
        unfairLock.deinitialize(count: 1)
70
        unfairLock.deallocate()
71
    }
72
 
73
    fileprivate func lock() {
74
        os_unfair_lock_lock(unfairLock)
75
    }
76
 
77
    fileprivate func unlock() {
78
        os_unfair_lock_unlock(unfairLock)
79
    }
80
}
81
#endif
82
 
83
/// A thread-safe wrapper around a value.
84
@propertyWrapper
85
@dynamicMemberLookup
86
final class Protected<T> {
87
    #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
88
    private let lock = UnfairLock()
89
    #elseif os(Linux) || os(Windows)
90
    private let lock = NSLock()
91
    #endif
92
    private var value: T
93
 
94
    init(_ value: T) {
95
        self.value = value
96
    }
97
 
98
    /// The contained value. Unsafe for anything more than direct read or write.
99
    var wrappedValue: T {
100
        get { lock.around { value } }
101
        set { lock.around { value = newValue } }
102
    }
103
 
104
    var projectedValue: Protected<T> { self }
105
 
106
    init(wrappedValue: T) {
107
        value = wrappedValue
108
    }
109
 
110
    /// Synchronously read or transform the contained value.
111
    ///
112
    /// - Parameter closure: The closure to execute.
113
    ///
114
    /// - Returns:           The return value of the closure passed.
115
    func read<U>(_ closure: (T) throws -> U) rethrows -> U {
116
        try lock.around { try closure(self.value) }
117
    }
118
 
119
    /// Synchronously modify the protected value.
120
    ///
121
    /// - Parameter closure: The closure to execute.
122
    ///
123
    /// - Returns:           The modified value.
124
    @discardableResult
125
    func write<U>(_ closure: (inout T) throws -> U) rethrows -> U {
126
        try lock.around { try closure(&self.value) }
127
    }
128
 
129
    subscript<Property>(dynamicMember keyPath: WritableKeyPath<T, Property>) -> Property {
130
        get { lock.around { value[keyPath: keyPath] } }
131
        set { lock.around { value[keyPath: keyPath] = newValue } }
132
    }
133
 
134
    subscript<Property>(dynamicMember keyPath: KeyPath<T, Property>) -> Property {
135
        lock.around { value[keyPath: keyPath] }
136
    }
137
}
138
 
139
extension Protected where T == Request.MutableState {
140
    /// Attempts to transition to the passed `State`.
141
    ///
142
    /// - Parameter state: The `State` to attempt transition to.
143
    ///
144
    /// - Returns:         Whether the transition occurred.
145
    func attemptToTransitionTo(_ state: Request.State) -> Bool {
146
        lock.around {
147
            guard value.state.canTransitionTo(state) else { return false }
148
 
149
            value.state = state
150
 
151
            return true
152
        }
153
    }
154
 
155
    /// Perform a closure while locked with the provided `Request.State`.
156
    ///
157
    /// - Parameter perform: The closure to perform while locked.
158
    func withState(perform: (Request.State) -> Void) {
159
        lock.around { perform(value.state) }
160
    }
161
}