68 lines
1.6 KiB
Swift
68 lines
1.6 KiB
Swift
import Foundation
|
|
|
|
@dynamicMemberLookup
|
|
final class ReadWriteLockIsolated<Value>: @unchecked Sendable {
|
|
private var _value: Value
|
|
private let lock: UnsafeMutablePointer<pthread_rwlock_t> = .create()
|
|
|
|
init(_ value: @autoclosure @Sendable () throws -> Value) rethrows {
|
|
self._value = try value()
|
|
}
|
|
|
|
deinit {
|
|
lock.destroy()
|
|
}
|
|
|
|
subscript<Subject: Sendable>(dynamicMember keyPath: KeyPath<Value, Subject>) -> Subject {
|
|
self.lock.sync {
|
|
self._value[keyPath: keyPath]
|
|
}
|
|
}
|
|
|
|
func withValue<T>(
|
|
_ operation: (inout Value) throws -> T
|
|
) rethrows -> T {
|
|
try self.lock.sync {
|
|
var value = self._value
|
|
defer { self._value = value }
|
|
return try operation(&value)
|
|
}
|
|
}
|
|
|
|
func setValue(_ newValue: @autoclosure @Sendable () throws -> Value) rethrows {
|
|
try self.lock.sync {
|
|
self._value = try newValue()
|
|
}
|
|
}
|
|
}
|
|
|
|
extension ReadWriteLockIsolated where Value: Sendable {
|
|
var value: Value {
|
|
self.lock.sync {
|
|
self._value
|
|
}
|
|
}
|
|
}
|
|
|
|
extension UnsafeMutablePointer where Pointee == pthread_rwlock_t {
|
|
fileprivate static func create() -> Self {
|
|
// allocate on the heap to create a stable pointer
|
|
let lock = Self.allocate(capacity: 1)
|
|
lock.initialize(to: pthread_rwlock_t())
|
|
pthread_rwlock_init(lock, nil)
|
|
return lock
|
|
}
|
|
|
|
fileprivate func destroy() {
|
|
pthread_rwlock_destroy(self)
|
|
self.deinitialize(count: 1)
|
|
self.deallocate()
|
|
}
|
|
|
|
fileprivate func sync<R>(work: () throws -> R) rethrows -> R {
|
|
pthread_rwlock_wrlock(self)
|
|
defer { pthread_rwlock_unlock(self) }
|
|
return try work()
|
|
}
|
|
}
|