Add a lock around Future.result
And redefine Future.isSealed in terms of Future.result, rather than storing it separately.
This commit is contained in:
parent
500947f098
commit
680ea122fc
@ -1,30 +1,30 @@
|
||||
//
|
||||
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2022 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public final class Future<Value> {
|
||||
public typealias ResultType = Swift.Result<Value, Error>
|
||||
public private(set) var isSealed = false
|
||||
public private(set) var result: ResultType?
|
||||
|
||||
private let lock = UnfairLock()
|
||||
private var resultUnsynchronized: ResultType?
|
||||
private var observersUnsynchronized = [(ResultType) -> Void]()
|
||||
|
||||
public init() {}
|
||||
|
||||
public convenience init(value: Value) {
|
||||
self.init()
|
||||
sealResult(.success(value))
|
||||
self.resultUnsynchronized = .success(value)
|
||||
}
|
||||
|
||||
public convenience init(error: Error) {
|
||||
self.init()
|
||||
sealResult(.failure(error))
|
||||
self.resultUnsynchronized = .failure(error)
|
||||
}
|
||||
|
||||
private var observers = [(ResultType) -> Void]()
|
||||
private let observerLock = UnfairLock()
|
||||
public func observe(on queue: DispatchQueue? = nil, block: @escaping (ResultType) -> Void) {
|
||||
observerLock.withLock {
|
||||
lock.withLock {
|
||||
func execute(_ result: ResultType) {
|
||||
// If a queue is not specified, try and run on the main
|
||||
// queue. Eventually we'll want to switch this default,
|
||||
@ -35,20 +35,19 @@ public final class Future<Value> {
|
||||
}
|
||||
}
|
||||
|
||||
if let result = result {
|
||||
if let result = resultUnsynchronized {
|
||||
execute(result)
|
||||
return
|
||||
}
|
||||
observers.append(execute)
|
||||
observersUnsynchronized.append(execute)
|
||||
}
|
||||
}
|
||||
private func sealResult(_ result: ResultType) {
|
||||
observerLock.withLock {
|
||||
guard !isSealed else { return }
|
||||
self.result = result
|
||||
self.isSealed = true
|
||||
observers.forEach { $0(result) }
|
||||
observers.removeAll()
|
||||
lock.withLock {
|
||||
guard self.resultUnsynchronized == nil else { return }
|
||||
self.resultUnsynchronized = result
|
||||
observersUnsynchronized.forEach { $0(result) }
|
||||
observersUnsynchronized.removeAll()
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,6 +69,14 @@ public final class Future<Value> {
|
||||
public func reject(_ error: Error) {
|
||||
sealResult(.failure(error))
|
||||
}
|
||||
|
||||
public var result: ResultType? {
|
||||
return lock.withLock { self.resultUnsynchronized }
|
||||
}
|
||||
|
||||
public var isSealed: Bool {
|
||||
return lock.withLock { self.resultUnsynchronized != nil }
|
||||
}
|
||||
}
|
||||
|
||||
public extension Future where Value == Void {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user