diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 82e0b4a..95336d4 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -58,6 +58,17 @@ jobs: runner_pool: general build_scheme: swift-http-types-Package + embedded-swift: + name: Build with Embedded Swift + uses: swiftlang/github-workflows/.github/workflows/swift_package_test.yml@0.0.9 + with: + enable_linux_checks: false + enable_macos_checks: false + enable_windows_checks: false + enable_wasm_sdk_build: true + enable_embedded_wasm_sdk_build: true + swift_flags: --target HTTPTypes + release-builds: name: Release builds uses: apple/swift-nio/.github/workflows/release_builds.yml@main diff --git a/Sources/HTTPTypes/HTTPField.swift b/Sources/HTTPTypes/HTTPField.swift index 8645aa9..7181ced 100644 --- a/Sources/HTTPTypes/HTTPField.swift +++ b/Sources/HTTPTypes/HTTPField.swift @@ -112,9 +112,9 @@ public struct HTTPField: Sendable, Hashable { /// /// - Parameter body: The closure to be invoked with the buffer. /// - Returns: Result of the `body` closure. - public func withUnsafeBytesOfValue( - _ body: (UnsafeBufferPointer) throws -> Result - ) rethrows -> Result { + public func withUnsafeBytesOfValue( + _ body: (UnsafeBufferPointer) throws(Failure) -> Result + ) throws(Failure) -> Result { try self.rawValue.withUnsafeBytes(body) } @@ -219,6 +219,8 @@ extension HTTPField: CustomStringConvertible { } } +#if !hasFeature(Embedded) + extension HTTPField: CustomPlaygroundDisplayConvertible { public var playgroundDescription: Any { self.description @@ -261,6 +263,8 @@ extension HTTPField: Codable { } } +#endif + extension HTTPField { static func isValidToken(_ token: some StringProtocol) -> Bool { !token.isEmpty diff --git a/Sources/HTTPTypes/HTTPFieldName.swift b/Sources/HTTPTypes/HTTPFieldName.swift index 550505e..d052210 100644 --- a/Sources/HTTPTypes/HTTPFieldName.swift +++ b/Sources/HTTPTypes/HTTPFieldName.swift @@ -111,6 +111,8 @@ extension HTTPField.Name: LosslessStringConvertible { } } +#if !hasFeature(Embedded) + extension HTTPField.Name: CustomPlaygroundDisplayConvertible { public var playgroundDescription: Any { self.description @@ -148,6 +150,8 @@ extension HTTPField.Name: Codable { } } +#endif + extension HTTPField.Name { static var method: Self { .init(rawName: ":method", canonicalName: ":method") } static var scheme: Self { .init(rawName: ":scheme", canonicalName: ":scheme") } diff --git a/Sources/HTTPTypes/HTTPFields.swift b/Sources/HTTPTypes/HTTPFields.swift index af22e9f..8f14a4b 100644 --- a/Sources/HTTPTypes/HTTPFields.swift +++ b/Sources/HTTPTypes/HTTPFields.swift @@ -30,9 +30,26 @@ public struct HTTPFields: Sendable, Hashable { required init() { } - func withLock(_ body: () throws -> Result) rethrows -> Result { + #if canImport(Darwin) && !hasFeature(Embedded) + func withLock(_ body: () throws(Failure) -> Result) throws(Failure) -> Result { fatalError() } + #else + #if !hasFeature(Embedded) || (os(WASI) && compiler(>=6.4)) + let mutex = Mutex(()) + #endif + + final func withLock(_ body: () throws(Failure) -> Result) throws(Failure) -> Result { + #if !hasFeature(Embedded) || (os(WASI) && compiler(>=6.4)) + try self.mutex.withLock { _ throws(Failure) in + try body() + } + #else + // Mutex not available + try body() + #endif + } + #endif var ensureIndex: [String: (first: UInt16, last: UInt16)] { self.withLock { @@ -107,23 +124,23 @@ public struct HTTPFields: Sendable, Hashable { } } + #if canImport(Darwin) && !hasFeature(Embedded) @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 + override func withLock(_ body: () throws(Failure) -> Result) throws(Failure) -> Result { + try self.mutex.withLock { _ throws(Failure) in try body() } } } - #if canImport(Darwin) 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 + override func withLock(_ body: () throws(Failure) -> Result) throws(Failure) -> Result { + try self.lock.withLockedValue { _ throws(Failure) in try body() } } @@ -131,14 +148,14 @@ public struct HTTPFields: Sendable, Hashable { #endif private var _storage = { - #if canImport(Darwin) + #if canImport(Darwin) && !hasFeature(Embedded) if #available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) { _StorageWithMutex() } else { _StorageWithNIOLock() } #else - _StorageWithMutex() + _Storage() #endif }() @@ -166,13 +183,14 @@ public struct HTTPFields: Sendable, Hashable { let fields = self.fields(for: name) if fields.first(where: { _ in true }) != nil { let separator = name == .cookie ? "; " : ", " - return fields.lazy.map(\.value).joined(separator: separator) + return fields.lazy.map { $0.value }.joined(separator: separator) } else { return nil } } set { if let newValue { + #if !hasFeature(Embedded) if #available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *), name == .cookie { @@ -182,9 +200,10 @@ public struct HTTPFields: Sendable, Hashable { }, for: name ) - } else { - self.setFields(CollectionOfOne(HTTPField(name: name, value: newValue)), for: name) + return } + #endif + self.setFields(CollectionOfOne(HTTPField(name: name, value: newValue)), for: name) } else { self.setFields(EmptyCollection(), for: name) } @@ -194,7 +213,7 @@ public struct HTTPFields: Sendable, Hashable { /// Access the field values by name as an array of strings. The order of fields is preserved. public subscript(values name: HTTPField.Name) -> [String] { get { - self.fields(for: name).map(\.value) + self.fields(for: name).map { $0.value } } set { self.setFields(newValue.lazy.map { HTTPField(name: name, value: $0) }, for: name) @@ -355,6 +374,8 @@ extension HTTPFields: RangeReplaceableCollection, RandomAccessCollection, Mutabl } } +#if !hasFeature(Embedded) + extension HTTPFields: CustomDebugStringConvertible { public var debugDescription: String { self._storage.fields.description @@ -385,6 +406,8 @@ extension HTTPFields: Codable { } } +#endif + extension Array { // `removalIndices` must be ordered. mutating func remove(at removalIndices: some Sequence) { diff --git a/Sources/HTTPTypes/HTTPParsedFields.swift b/Sources/HTTPTypes/HTTPParsedFields.swift index 33ff1c0..cd4306c 100644 --- a/Sources/HTTPTypes/HTTPParsedFields.swift +++ b/Sources/HTTPTypes/HTTPParsedFields.swift @@ -12,6 +12,8 @@ // //===----------------------------------------------------------------------===// +#if !hasFeature(Embedded) + struct HTTPParsedFields { private var method: ISOLatin1String? private var scheme: ISOLatin1String? @@ -234,3 +236,5 @@ extension HTTPFields { self = try parsedFields.trailerFields } } + +#endif diff --git a/Sources/HTTPTypes/HTTPRequest+URL.swift b/Sources/HTTPTypes/HTTPRequest+URL.swift index 502763a..7c2bc80 100644 --- a/Sources/HTTPTypes/HTTPRequest+URL.swift +++ b/Sources/HTTPTypes/HTTPRequest+URL.swift @@ -12,6 +12,8 @@ // //===----------------------------------------------------------------------===// +#if !hasFeature(Embedded) + #if canImport(FoundationEssentials) import FoundationEssentials #else // canImport(FoundationEssentials) @@ -214,3 +216,5 @@ extension URL { #endif // !canImport(FoundationEssentials) && canImport(CoreFoundation) } } + +#endif diff --git a/Sources/HTTPTypes/HTTPRequest.swift b/Sources/HTTPTypes/HTTPRequest.swift index cf70159..a8e3dbd 100644 --- a/Sources/HTTPTypes/HTTPRequest.swift +++ b/Sources/HTTPTypes/HTTPRequest.swift @@ -332,6 +332,8 @@ extension HTTPRequest: CustomDebugStringConvertible { } } +#if !hasFeature(Embedded) + extension HTTPRequest.PseudoHeaderFields: Codable { public func encode(to encoder: Encoder) throws { var container = encoder.unkeyedContainer() @@ -450,6 +452,8 @@ extension HTTPRequest: Codable { } } +#endif + extension HTTPRequest.Method { /// GET /// diff --git a/Sources/HTTPTypes/HTTPResponse.swift b/Sources/HTTPTypes/HTTPResponse.swift index 30b79cc..a41c58e 100644 --- a/Sources/HTTPTypes/HTTPResponse.swift +++ b/Sources/HTTPTypes/HTTPResponse.swift @@ -263,6 +263,8 @@ extension HTTPResponse: CustomDebugStringConvertible { } } +#if !hasFeature(Embedded) + extension HTTPResponse.PseudoHeaderFields: Codable { public func encode(to encoder: Encoder) throws { var container = encoder.unkeyedContainer() @@ -338,6 +340,8 @@ extension HTTPResponse: Codable { } } +#endif + extension HTTPResponse.Status { // MARK: 1xx diff --git a/Sources/HTTPTypes/ISOLatin1String.swift b/Sources/HTTPTypes/ISOLatin1String.swift index a5c08f7..592aaac 100644 --- a/Sources/HTTPTypes/ISOLatin1String.swift +++ b/Sources/HTTPTypes/ISOLatin1String.swift @@ -28,16 +28,18 @@ struct ISOLatin1String: Sendable, Hashable { return string } - private func withISOLatin1BytesSlowPath( - _ body: (UnsafeBufferPointer) throws -> Result - ) rethrows -> Result { + private func withISOLatin1BytesSlowPath( + _ body: (UnsafeBufferPointer) throws(Failure) -> Return + ) throws(Failure) -> Return { try withUnsafeTemporaryAllocation(of: UInt8.self, capacity: self._storage.unicodeScalars.count) { buffer in for (index, scalar) in self._storage.unicodeScalars.enumerated() { assert(scalar.value <= UInt8.max) buffer[index] = UInt8(truncatingIfNeeded: scalar.value) } - return try body(UnsafeBufferPointer(buffer)) - } + return Result { () throws(Failure) in + try body(UnsafeBufferPointer(buffer)) + } + }.get() } init(_ string: String) { @@ -71,10 +73,16 @@ struct ISOLatin1String: Sendable, Hashable { } } - func withUnsafeBytes(_ body: (UnsafeBufferPointer) throws -> Result) rethrows -> Result { + func withUnsafeBytes( + _ body: (UnsafeBufferPointer) throws(Failure) -> Return + ) throws(Failure) -> Return { if self._storage.isASCII { var string = self._storage - return try string.withUTF8(body) + return try string.withUTF8 { buffer in + Result { () throws(Failure) in + try body(buffer) + } + }.get() } else { return try self.withISOLatin1BytesSlowPath(body) } diff --git a/Sources/HTTPTypes/NIOLock.swift b/Sources/HTTPTypes/NIOLock.swift index 1df5fd7..198ca97 100644 --- a/Sources/HTTPTypes/NIOLock.swift +++ b/Sources/HTTPTypes/NIOLock.swift @@ -176,14 +176,14 @@ final class LockStorage: ManagedBuffer { } } - func withLockPrimitive(_ body: (UnsafeMutablePointer) throws -> T) rethrows -> T { - try self.withUnsafeMutablePointerToElements { lockPtr in + func withLockPrimitive(_ body: (UnsafeMutablePointer) throws(E) -> T) throws(E) -> T { + try self.withUnsafeMutablePointerToElements { lockPtr throws(E) in try body(lockPtr) } } - func withLockedValue(_ mutate: (inout Value) throws -> T) rethrows -> T { - try self.withUnsafeMutablePointers { valuePtr, lockPtr in + func withLockedValue(_ mutate: (inout Value) throws(E) -> T) throws(E) -> T { + try self.withUnsafeMutablePointers { valuePtr, lockPtr throws(E) in LockOperations.lock(lockPtr) defer { LockOperations.unlock(lockPtr) } return try mutate(&valuePtr.pointee)