Skip to content

Commit

Permalink
refactor ObservationToken
Browse files Browse the repository at this point in the history
  • Loading branch information
grdsdev committed Oct 10, 2024
1 parent e38e702 commit a18e671
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 39 deletions.
7 changes: 6 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,12 @@ let package = Package(
],
resources: [.process("Resources")]
),
.target(name: "Functions", dependencies: ["Helpers"]),
.target(
name: "Functions",
dependencies: [
"Helpers",
]
),
.testTarget(
name: "FunctionsTests",
dependencies: [
Expand Down
39 changes: 19 additions & 20 deletions Sources/Functions/FunctionsClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,36 @@ public final class FunctionsClient: Sendable {
/// The Region to invoke the functions in.
let region: String?

private let http: any HTTPClientType

struct MutableState {
/// Headers to be included in the requests.
var headers = HTTPHeaders()
}

private let http: any HTTPClientType
private let mutableState = LockIsolated(MutableState())

var headers: HTTPHeaders {
mutableState.headers
}

init(
url: URL,
headers: [String: String],
region: String?,
http: any HTTPClientType
) {
self.url = url
self.region = region
self.http = http

mutableState.withValue {
$0.headers = HTTPHeaders(headers)
if $0.headers["X-Client-Info"] == nil {
$0.headers["X-Client-Info"] = "functions-swift/\(version)"
}
}
}

/// Initializes a new instance of `FunctionsClient`.
///
/// - Parameters:
Expand All @@ -60,24 +77,6 @@ public final class FunctionsClient: Sendable {
self.init(url: url, headers: headers, region: region, http: http)
}

init(
url: URL,
headers: [String: String],
region: String?,
http: any HTTPClientType
) {
self.url = url
self.region = region
self.http = http

mutableState.withValue {
$0.headers = HTTPHeaders(headers)
if $0.headers["X-Client-Info"] == nil {
$0.headers["X-Client-Info"] = "functions-swift/\(version)"
}
}
}

/// Initializes a new instance of `FunctionsClient`.
///
/// - Parameters:
Expand Down
42 changes: 24 additions & 18 deletions Sources/Helpers/EventEmitter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@
import ConcurrencyExtras
import Foundation

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

package init(_ onCancel: (@Sendable () -> Void)? = nil) {
_onCancel.setValue(onCancel)
public var isCancelled: Bool {
_isCancelled.withValue { $0 }
}

package init(onCancel: @escaping @Sendable () -> Void = {}) {
self.onCancel = onCancel
}

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

public func cancel() {
_onCancel.withValue {
if $0 == nil {
return
}

$0?()
$0 = nil
_isCancelled.withValue { isCancelled in
guard !isCancelled else { return }
defer { isCancelled = true }
onCancel()
}
}

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

public static func == (lhs: ObservationToken, rhs: ObservationToken) -> Bool {
ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
lhs === rhs
}

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

extension ObservationToken {
public func store(in collection: inout some RangeReplaceableCollection<ObservationToken>) {
collection.append(self)
}

public func store(in set: inout Set<ObservationToken>) {
set.insert(self)
}
Expand All @@ -53,7 +59,7 @@ extension ObservationToken {
package final class EventEmitter<Event: Sendable>: Sendable {
public typealias Listener = @Sendable (Event) -> Void

private let listeners = LockIsolated<[ObjectIdentifier: Listener]>([:])
private let listeners = LockIsolated<[(key: ObjectIdentifier, listener: Listener)]>([])
private let _lastEvent: LockIsolated<Event>
package var lastEvent: Event { _lastEvent.value }

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

token._onCancel.setValue { [weak self] in
token.onCancel = { [weak self] in
self?.listeners.withValue {
$0[key] = nil
$0.removeAll { $0.key == key }
}
}

listeners.withValue {
$0[key] = listener
$0.append((key, listener))
}

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

if let token {
listeners[ObjectIdentifier(token)]?(event)
listeners.first { $0.key == ObjectIdentifier(token) }?.listener(event)
} else {
for listener in listeners.values {
for (_, listener) in listeners {
listener(event)
}
}
Expand Down

0 comments on commit a18e671

Please sign in to comment.