From a399b935bd8c06c264bfa4a9b59685d4796672a1 Mon Sep 17 00:00:00 2001 From: Guoye Zhang Date: Sun, 27 Oct 2024 23:38:18 -0700 Subject: [PATCH] Adopt Mutex where available --- Sources/HTTPTypes/HTTPFields.swift | 57 ++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/Sources/HTTPTypes/HTTPFields.swift b/Sources/HTTPTypes/HTTPFields.swift index d188df4..a20fa4c 100644 --- a/Sources/HTTPTypes/HTTPFields.swift +++ b/Sources/HTTPTypes/HTTPFields.swift @@ -12,6 +12,10 @@ // //===----------------------------------------------------------------------===// +#if canImport(Synchronization) +import Synchronization +#endif // canImport(Synchronization) + /// A collection of HTTP fields. It is used in `HTTPRequest` and `HTTPResponse`, and can also be /// used as HTTP trailer fields. /// @@ -21,13 +25,19 @@ /// `HTTPFields` adheres to modern HTTP semantics. In particular, the "Cookie" request header field /// is split into separate header fields by default. public struct HTTPFields: Sendable, Hashable { - private final class _Storage: @unchecked Sendable, Hashable { + private class _Storage: @unchecked Sendable, Hashable { var fields: [(field: HTTPField, next: UInt16)] = [] var index: [String: (first: UInt16, last: UInt16)]? = [:] - let lock = LockStorage.create(value: ()) + + required init() { + } + + func withLock(_ body: () throws -> Result) rethrows -> Result { + fatalError() + } var ensureIndex: [String: (first: UInt16, last: UInt16)] { - self.lock.withLockedValue { _ in + self.withLock { if let index = self.index { return index } @@ -45,10 +55,10 @@ public struct HTTPFields: Sendable, Hashable { } } - func copy() -> _Storage { - let newStorage = _Storage() + func copy() -> Self { + let newStorage = Self() newStorage.fields = self.fields - self.lock.withLockedValue { _ in + self.withLock { newStorage.index = self.index } return newStorage @@ -99,7 +109,40 @@ public struct HTTPFields: Sendable, Hashable { } } - private var _storage = _Storage() +#if canImport(Synchronization) + @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) + private final class _StorageWithMutex: _Storage, @unchecked Sendable { + let mutex = Mutex(()) + + override func withLock(_ body: () throws -> Result) rethrows -> Result { + try self.mutex.withLock { _ in + try body() + } + } + } +#endif // canImport(Synchronization) + + private final class _StorageWithNIOLock: _Storage, @unchecked Sendable { + let lock = LockStorage.create(value: ()) + + override func withLock(_ body: () throws -> Result) rethrows -> Result { + try self.lock.withLockedValue { _ in + try body() + } + } + } + + private var _storage = { +#if canImport(Synchronization) + if #available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) { + _StorageWithMutex() + } else { + _StorageWithNIOLock() + } +#else // canImport(Synchronization) + _StorageWithNIOLock() +#endif // canImport(Synchronization) + }() /// Create an empty list of HTTP fields public init() {}