Last active
November 23, 2023 03:31
-
-
Save davbeck/dcd8b6eae11a4400a867be82da29ffd7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ConcurrencyExtras | |
private struct ObservationTrackingState: Sendable { | |
var isCancelled: Bool = false | |
var updateTaskID: UUID? | |
} | |
public func withObservationTracking<T>(_ apply: @escaping () -> T) -> AsyncThrowingStream<T, any Error> { | |
let (stream, continuation) = AsyncThrowingStream.makeStream(of: T.self) | |
let lock = LockIsolated(ObservationTrackingState()) | |
continuation.onTermination = { _ in | |
lock.withValue { | |
$0.isCancelled = true | |
} | |
} | |
@Sendable func update() { | |
guard | |
lock.withValue({ state -> Bool in | |
guard !state.isCancelled else { return false } | |
state.updateTaskID = nil | |
return true | |
}) | |
else { return } | |
let value = withObservationTracking { | |
apply() | |
} onChange: { | |
let taskID = UUID() | |
guard | |
lock.withValue({ state -> Bool in | |
guard !state.isCancelled else { return false } | |
state.updateTaskID = taskID | |
return true | |
}) | |
else { return } | |
RunLoop.current.perform { | |
guard lock.updateTaskID == taskID else { return } | |
update() | |
} | |
} | |
continuation.yield(value) | |
} | |
update() | |
return stream | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment