Refactor DocumentManager threading for Swift 6

Replaces DispatchQueue with ThreadSafeBox, relaxes T: Sendable constraints, and removes @unchecked Sendable from Document.
This commit is contained in:
Divya Prakash
2025-12-21 19:26:02 +05:30
parent d9072850e0
commit 0ca0660d99
3 changed files with 19 additions and 15 deletions

View File

@@ -23,8 +23,8 @@ extension sourcekitd_api_values: @unchecked Sendable {}
fileprivate extension ThreadSafeBox {
/// If the wrapped value is `nil`, run `compute` and store the computed value. If it is not `nil`, return the stored
/// value.
func computeIfNil<WrappedValue>(compute: () -> WrappedValue) -> WrappedValue where T == WrappedValue? {
return withLock { value in
func computeIfNil<WrappedValue: Sendable>(compute: () -> WrappedValue) -> WrappedValue where T == WrappedValue? {
return withLock { (value: inout WrappedValue?) -> WrappedValue in
if let value {
return value
}

View File

@@ -61,7 +61,7 @@ package struct DocumentSnapshot: Identifiable, Sendable {
}
}
package final class Document: @unchecked Sendable {
package final class Document {
package let uri: DocumentURI
package let language: Language
var latestVersion: Int

View File

@@ -15,12 +15,26 @@ import Foundation
/// A thread safe container that contains a value of type `T`.
///
/// - Note: Unchecked sendable conformance because value is guarded by a lock.
package class ThreadSafeBox<T: Sendable>: @unchecked Sendable {
package final class ThreadSafeBox<T>: Sendable {
/// Lock guarding `_value`.
private let lock = NSLock()
private var _value: T
private nonisolated(unsafe) var _value: T
package init(initialValue: T) {
_value = initialValue
}
/// Restrict the result of the body to `Sendable` so callers can safely use
/// the returned value outside the lock without requiring `T: Sendable`.
package func withLock<Result: Sendable>(_ body: (inout T) throws -> Result) rethrows -> Result {
return try lock.withLock {
return try body(&_value)
}
}
}
extension ThreadSafeBox where T: Sendable {
package var value: T {
get {
return lock.withLock {
@@ -39,16 +53,6 @@ package class ThreadSafeBox<T: Sendable>: @unchecked Sendable {
}
}
package init(initialValue: T) {
_value = initialValue
}
package func withLock<Result>(_ body: (inout T) throws -> Result) rethrows -> Result {
return try lock.withLock {
return try body(&_value)
}
}
/// If the value in the box is an optional, return it and reset it to `nil`
/// in an atomic operation.
package func takeValue<U>() -> T where U? == T {