diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2022-09-25 16:34:23 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2022-09-26 16:35:38 +0200 |
| commit | f389956c2cd884df142adbf00ff2ac7e2f69c2b2 (patch) | |
| tree | 5f7d4869324760eb4ba0107c0356edc89efd1457 /ios/Operations/ResultBlockOperation.swift | |
| parent | 2e83b1ca27ff243a615ff10c94c20840b38dfd45 (diff) | |
| download | mullvadvpn-f389956c2cd884df142adbf00ff2ac7e2f69c2b2.tar.xz mullvadvpn-f389956c2cd884df142adbf00ff2ac7e2f69c2b2.zip | |
Move AsyncOperation into Operations static library and add separate tests
Diffstat (limited to 'ios/Operations/ResultBlockOperation.swift')
| -rw-r--r-- | ios/Operations/ResultBlockOperation.swift | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/ios/Operations/ResultBlockOperation.swift b/ios/Operations/ResultBlockOperation.swift new file mode 100644 index 0000000000..483731360a --- /dev/null +++ b/ios/Operations/ResultBlockOperation.swift @@ -0,0 +1,120 @@ +// +// ResultBlockOperation.swift +// MullvadVPN +// +// Created by pronebird on 12/05/2022. +// Copyright © 2022 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +public final class ResultBlockOperation<Success, Failure: Error>: ResultOperation< + Success, + Failure +> { + public typealias ExecutionBlock = (ResultBlockOperation<Success, Failure>) -> Void + public typealias ThrowingExecutionBlock = () throws -> Success + + private var executionBlock: ExecutionBlock? + private var cancellationBlocks: [() -> Void] = [] + + public convenience init( + dispatchQueue: DispatchQueue? = nil, + executionBlock: ExecutionBlock? = nil + ) { + self.init( + dispatchQueue: dispatchQueue, + executionBlock: executionBlock, + completionQueue: nil, + completionHandler: nil + ) + } + + public convenience init( + dispatchQueue: DispatchQueue? = nil, + executionBlock: @escaping ThrowingExecutionBlock + ) { + self.init( + dispatchQueue: dispatchQueue, + executionBlock: Self.wrapThrowingBlock(executionBlock), + completionQueue: nil, + completionHandler: nil + ) + } + + public init( + dispatchQueue: DispatchQueue?, + executionBlock: ExecutionBlock?, + completionQueue: DispatchQueue?, + completionHandler: CompletionHandler? + ) { + self.executionBlock = executionBlock + + super.init( + dispatchQueue: dispatchQueue, + completionQueue: completionQueue, + completionHandler: completionHandler + ) + } + + override public func main() { + let block = executionBlock + executionBlock = nil + + block?(self) + } + + override public func operationDidCancel() { + let blocks = cancellationBlocks + cancellationBlocks.removeAll() + + for block in blocks { + block() + } + } + + override public func operationDidFinish() { + cancellationBlocks.removeAll() + executionBlock = nil + } + + public func setExecutionBlock( + _ block: @escaping (ResultBlockOperation<Success, Failure>) + -> Void + ) { + dispatchQueue.async { + assert(!self.isExecuting && !self.isFinished) + self.executionBlock = block + } + } + + public func setExecutionBlock(_ block: @escaping ThrowingExecutionBlock) { + setExecutionBlock(Self.wrapThrowingBlock(block)) + } + + public func addCancellationBlock(_ block: @escaping () -> Void) { + dispatchQueue.async { + if self.isCancelled { + block() + } else { + self.cancellationBlocks.append(block) + } + } + } + + private class func wrapThrowingBlock(_ executionBlock: @escaping ThrowingExecutionBlock) + -> ExecutionBlock + { + return { operation in + do { + let value = try executionBlock() + + operation.finish(completion: .success(value)) + } catch { + let castedError = error as! Failure + + operation.finish(completion: .failure(castedError)) + } + } + } +} |
