1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
//
// TransformOperation.swift
// AsyncOperationQueueTest
//
// Created by pronebird on 31/05/2022.
//
import Foundation
final class TransformOperation<Input, Output, Failure: Error>:
ResultOperation<Output, Failure>,
InputOperation
{
typealias ExecutionBlock = (Input, TransformOperation<Input, Output, Failure>) -> Void
typealias ThrowingExecutionBlock = (Input) throws -> Output
typealias InputBlock = () -> Input?
private let nslock = NSLock()
private(set) var input: Input? {
get {
nslock.lock()
defer { nslock.unlock() }
return _input
}
set {
nslock.lock()
_input = newValue
nslock.unlock()
}
}
private var _input: Input?
private var inputBlock: InputBlock?
private var executionBlock: ExecutionBlock?
private var cancellationBlocks: [() -> Void] = []
init(
dispatchQueue: DispatchQueue? = nil,
input: Input? = nil,
block: ExecutionBlock? = nil
)
{
_input = input
executionBlock = block
super.init(dispatchQueue: dispatchQueue)
}
init(
dispatchQueue: DispatchQueue? = nil,
input: Input? = nil,
throwingBlock: @escaping ThrowingExecutionBlock
)
{
_input = input
executionBlock = Self.wrapThrowingBlock(throwingBlock)
super.init(dispatchQueue: dispatchQueue)
}
override func main() {
let inputValue = inputBlock?()
input = inputValue
guard let inputValue = inputValue, let executionBlock = executionBlock else {
finish(completion: .cancelled)
return
}
executionBlock(inputValue, self)
}
override func operationDidCancel() {
let blocks = cancellationBlocks
cancellationBlocks.removeAll()
for block in blocks {
block()
}
}
override func operationDidFinish() {
cancellationBlocks.removeAll()
executionBlock = nil
}
// MARK: - Block handlers
func setExecutionBlock(_ block: @escaping ExecutionBlock) {
dispatchQueue.async {
assert(!self.isExecuting && !self.isFinished)
self.executionBlock = block
}
}
func setExecutionBlock(_ block: @escaping ThrowingExecutionBlock) {
setExecutionBlock(Self.wrapThrowingBlock(block))
}
func addCancellationBlock(_ block: @escaping () -> Void) {
dispatchQueue.async {
if self.isCancelled {
block()
} else {
self.cancellationBlocks.append(block)
}
}
}
// MARK: - Input injection
func setInputBlock(_ block: @escaping () -> Input?) {
dispatchQueue.async {
self.inputBlock = block
}
}
private class func wrapThrowingBlock(_ executionBlock: @escaping ThrowingExecutionBlock) -> ExecutionBlock {
return { input, operation in
do {
let value = try executionBlock(input)
operation.finish(completion: .success(value))
} catch {
let castedError = error as! Failure
operation.finish(completion: .failure(castedError))
}
}
}
}
|