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/InputInjectionBuilder.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/InputInjectionBuilder.swift')
| -rw-r--r-- | ios/Operations/InputInjectionBuilder.swift | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/ios/Operations/InputInjectionBuilder.swift b/ios/Operations/InputInjectionBuilder.swift new file mode 100644 index 0000000000..ad2f329024 --- /dev/null +++ b/ios/Operations/InputInjectionBuilder.swift @@ -0,0 +1,96 @@ +// +// InputInjectionBuilder.swift +// MullvadVPN +// +// Created by pronebird on 09/06/2022. +// Copyright © 2022 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +public protocol OperationInputContext { + associatedtype Input + + func reduce() -> Input? +} + +public final class InputInjectionBuilder<OperationType, Context> + where OperationType: InputOperation +{ + public typealias InputBlock = (inout Context) -> Void + + private let operation: OperationType + private var context: Context + private var inputBlocks: [InputBlock] = [] + + public init(operation: OperationType, context: Context) { + self.operation = operation + self.context = context + } + + public func inject<T>( + from dependency: T, + assignOutputTo keyPath: WritableKeyPath<Context, T.Output?> + ) -> Self + where T: OutputOperation + { + return inject(from: dependency) { context, output in + context[keyPath: keyPath] = output + } + } + + public func inject<T>( + from dependency: T, + via block: @escaping (inout Context, T.Output) -> Void + ) -> Self + where T: OutputOperation + { + inputBlocks.append { context in + if let output = dependency.output { + block(&context, output) + } + } + + operation.addDependency(dependency) + + return self + } + + public func injectCompletion<T, Success, Failure>( + from dependency: T, + via block: @escaping (inout Context, T.Completion) -> Void + ) -> Self + where T: ResultOperation<Success, Failure> + { + inputBlocks.append { context in + if let completion = dependency.completion { + block(&context, completion) + } + } + + operation.addDependency(dependency) + + return self + } + + public func reduce(_ reduceBlock: @escaping (Context) -> OperationType.Input?) { + operation.setInputBlock { + for inputBlock in self.inputBlocks { + inputBlock(&self.context) + } + + return reduceBlock(self.context) + } + } +} + +public extension InputInjectionBuilder + where Context: OperationInputContext, + Context.Input == OperationType.Input +{ + func reduce() { + reduce { context in + return context.reduce() + } + } +} |
