summaryrefslogtreecommitdiffhomepage
path: root/ios/Operations/InputInjectionBuilder.swift
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2022-09-25 16:34:23 +0200
committerAndrej Mihajlov <and@mullvad.net>2022-09-26 16:35:38 +0200
commitf389956c2cd884df142adbf00ff2ac7e2f69c2b2 (patch)
tree5f7d4869324760eb4ba0107c0356edc89efd1457 /ios/Operations/InputInjectionBuilder.swift
parent2e83b1ca27ff243a615ff10c94c20840b38dfd45 (diff)
downloadmullvadvpn-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.swift96
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()
+ }
+ }
+}