summaryrefslogtreecommitdiffhomepage
path: root/ios/MullvadVPN
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2022-03-23 14:42:08 +0100
committerAndrej Mihajlov <and@mullvad.net>2022-03-31 14:39:43 +0200
commitd71995c950f87e0866862bc2c6191d2e2e59deb8 (patch)
tree4c741062a0cacf05a62ce36c77bc66d81ed55f52 /ios/MullvadVPN
parenta0735ca20791a33b4f0ac613f3488959cf07c93a (diff)
downloadmullvadvpn-d71995c950f87e0866862bc2c6191d2e2e59deb8.tar.xz
mullvadvpn-d71995c950f87e0866862bc2c6191d2e2e59deb8.zip
Add ResultOperation
Diffstat (limited to 'ios/MullvadVPN')
-rw-r--r--ios/MullvadVPN/Operations/ResultOperation.swift77
1 files changed, 77 insertions, 0 deletions
diff --git a/ios/MullvadVPN/Operations/ResultOperation.swift b/ios/MullvadVPN/Operations/ResultOperation.swift
new file mode 100644
index 0000000000..ba2cd59c4e
--- /dev/null
+++ b/ios/MullvadVPN/Operations/ResultOperation.swift
@@ -0,0 +1,77 @@
+//
+// ResultOperation.swift
+// MullvadVPN
+//
+// Created by pronebird on 23/03/2022.
+// Copyright © 2022 Mullvad VPN AB. All rights reserved.
+//
+
+import Foundation
+
+/// Base class for operations producing result.
+class ResultOperation<Success, Failure: Error>: AsyncOperation {
+ typealias Completion = OperationCompletion<Success, Failure>
+ typealias CompletionHandler = (Completion) -> Void
+
+ private let stateLock = NSLock()
+ private var completionValue: Completion?
+ private let completionQueue: DispatchQueue?
+ private var completionHandler: CompletionHandler?
+
+ var completion: Completion? {
+ stateLock.lock()
+ defer { stateLock.unlock() }
+ return completionValue
+ }
+
+ init(completionQueue: DispatchQueue?, completionHandler: CompletionHandler?) {
+ self.completionQueue = completionQueue
+ self.completionHandler = completionHandler
+
+ super.init()
+ }
+
+ override func finish() {
+ // Propagate cancellation if finish() is called directly from start().
+ if isCancelled {
+ finish(completion: .cancelled)
+ } else {
+ preconditionFailure("Use finish(completion:) to finish operation.")
+ }
+ }
+
+ func finish(completion: Completion) {
+ stateLock.lock()
+
+ // Bail if operation is already finishing.
+ guard completionValue == nil else {
+ stateLock.unlock()
+ return
+ }
+
+ // Store completion value.
+ completionValue = completion
+
+ // Copy completion handler.
+ let completionHandler: CompletionHandler? = self.completionHandler
+
+ // Unset completion handler.
+ self.completionHandler = nil
+
+ stateLock.unlock()
+
+ let block = {
+ // Call completion handler.
+ completionHandler?(completion)
+
+ // Finish operation.
+ super.finish()
+ }
+
+ if let completionQueue = completionQueue {
+ completionQueue.async(execute: block)
+ } else {
+ block()
+ }
+ }
+}