Skip to content

Commit a18e671

Browse files
committed
refactor ObservationToken
1 parent e38e702 commit a18e671

File tree

3 files changed

+49
-39
lines changed

3 files changed

+49
-39
lines changed

Package.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,12 @@ let package = Package(
6666
],
6767
resources: [.process("Resources")]
6868
),
69-
.target(name: "Functions", dependencies: ["Helpers"]),
69+
.target(
70+
name: "Functions",
71+
dependencies: [
72+
"Helpers",
73+
]
74+
),
7075
.testTarget(
7176
name: "FunctionsTests",
7277
dependencies: [

Sources/Functions/FunctionsClient.swift

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,36 @@ public final class FunctionsClient: Sendable {
2121
/// The Region to invoke the functions in.
2222
let region: String?
2323

24-
private let http: any HTTPClientType
25-
2624
struct MutableState {
2725
/// Headers to be included in the requests.
2826
var headers = HTTPHeaders()
2927
}
3028

29+
private let http: any HTTPClientType
3130
private let mutableState = LockIsolated(MutableState())
3231

3332
var headers: HTTPHeaders {
3433
mutableState.headers
3534
}
3635

36+
init(
37+
url: URL,
38+
headers: [String: String],
39+
region: String?,
40+
http: any HTTPClientType
41+
) {
42+
self.url = url
43+
self.region = region
44+
self.http = http
45+
46+
mutableState.withValue {
47+
$0.headers = HTTPHeaders(headers)
48+
if $0.headers["X-Client-Info"] == nil {
49+
$0.headers["X-Client-Info"] = "functions-swift/\(version)"
50+
}
51+
}
52+
}
53+
3754
/// Initializes a new instance of `FunctionsClient`.
3855
///
3956
/// - Parameters:
@@ -60,24 +77,6 @@ public final class FunctionsClient: Sendable {
6077
self.init(url: url, headers: headers, region: region, http: http)
6178
}
6279

63-
init(
64-
url: URL,
65-
headers: [String: String],
66-
region: String?,
67-
http: any HTTPClientType
68-
) {
69-
self.url = url
70-
self.region = region
71-
self.http = http
72-
73-
mutableState.withValue {
74-
$0.headers = HTTPHeaders(headers)
75-
if $0.headers["X-Client-Info"] == nil {
76-
$0.headers["X-Client-Info"] = "functions-swift/\(version)"
77-
}
78-
}
79-
}
80-
8180
/// Initializes a new instance of `FunctionsClient`.
8281
///
8382
/// - Parameters:

Sources/Helpers/EventEmitter.swift

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,16 @@
88
import ConcurrencyExtras
99
import Foundation
1010

11-
public final class ObservationToken: Sendable, Hashable {
12-
let _onCancel = LockIsolated((@Sendable () -> Void)?.none)
11+
public final class ObservationToken: @unchecked Sendable, Hashable {
12+
private let _isCancelled = LockIsolated(false)
13+
package var onCancel: @Sendable () -> Void
1314

14-
package init(_ onCancel: (@Sendable () -> Void)? = nil) {
15-
_onCancel.setValue(onCancel)
15+
public var isCancelled: Bool {
16+
_isCancelled.withValue { $0 }
17+
}
18+
19+
package init(onCancel: @escaping @Sendable () -> Void = {}) {
20+
self.onCancel = onCancel
1621
}
1722

1823
@available(*, deprecated, renamed: "cancel")
@@ -21,13 +26,10 @@ public final class ObservationToken: Sendable, Hashable {
2126
}
2227

2328
public func cancel() {
24-
_onCancel.withValue {
25-
if $0 == nil {
26-
return
27-
}
28-
29-
$0?()
30-
$0 = nil
29+
_isCancelled.withValue { isCancelled in
30+
guard !isCancelled else { return }
31+
defer { isCancelled = true }
32+
onCancel()
3133
}
3234
}
3335

@@ -36,7 +38,7 @@ public final class ObservationToken: Sendable, Hashable {
3638
}
3739

3840
public static func == (lhs: ObservationToken, rhs: ObservationToken) -> Bool {
39-
ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
41+
lhs === rhs
4042
}
4143

4244
public func hash(into hasher: inout Hasher) {
@@ -45,6 +47,10 @@ public final class ObservationToken: Sendable, Hashable {
4547
}
4648

4749
extension ObservationToken {
50+
public func store(in collection: inout some RangeReplaceableCollection<ObservationToken>) {
51+
collection.append(self)
52+
}
53+
4854
public func store(in set: inout Set<ObservationToken>) {
4955
set.insert(self)
5056
}
@@ -53,7 +59,7 @@ extension ObservationToken {
5359
package final class EventEmitter<Event: Sendable>: Sendable {
5460
public typealias Listener = @Sendable (Event) -> Void
5561

56-
private let listeners = LockIsolated<[ObjectIdentifier: Listener]>([:])
62+
private let listeners = LockIsolated<[(key: ObjectIdentifier, listener: Listener)]>([])
5763
private let _lastEvent: LockIsolated<Event>
5864
package var lastEvent: Event { _lastEvent.value }
5965

@@ -77,14 +83,14 @@ package final class EventEmitter<Event: Sendable>: Sendable {
7783
let token = ObservationToken()
7884
let key = ObjectIdentifier(token)
7985

80-
token._onCancel.setValue { [weak self] in
86+
token.onCancel = { [weak self] in
8187
self?.listeners.withValue {
82-
$0[key] = nil
88+
$0.removeAll { $0.key == key }
8389
}
8490
}
8591

8692
listeners.withValue {
87-
$0[key] = listener
93+
$0.append((key, listener))
8894
}
8995

9096
return token
@@ -95,9 +101,9 @@ package final class EventEmitter<Event: Sendable>: Sendable {
95101
let listeners = listeners.value
96102

97103
if let token {
98-
listeners[ObjectIdentifier(token)]?(event)
104+
listeners.first { $0.key == ObjectIdentifier(token) }?.listener(event)
99105
} else {
100-
for listener in listeners.values {
106+
for (_, listener) in listeners {
101107
listener(event)
102108
}
103109
}

0 commit comments

Comments
 (0)