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
|
//
// ResultBlockOperation.swift
// Operations
//
// 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))
}
}
}
}
|