diff --git a/Sources/SwiftNetwork/Protocols/Frame.swift b/Sources/SwiftNetwork/Protocols/Frame.swift index f4b8500..16b5017 100644 --- a/Sources/SwiftNetwork/Protocols/Frame.swift +++ b/Sources/SwiftNetwork/Protocols/Frame.swift @@ -134,6 +134,7 @@ public struct Frame: ~Copyable { return effectiveBufferLength - (startOffset + endOffset) } + @inline(__always) public var span: Span? { @_lifetime(borrow self) get { @@ -151,6 +152,7 @@ public struct Frame: ~Copyable { } } + @inline(__always) public var bytes: RawSpan? { @_lifetime(borrow self) get { @@ -167,6 +169,7 @@ public struct Frame: ~Copyable { } } + @inline(__always) public var mutableSpan: MutableSpan? { @_lifetime(&self) mutating get { @@ -187,6 +190,7 @@ public struct Frame: ~Copyable { } } + @inline(__always) var allBytes: RawSpan? { guard isValid else { return nil } switch buffer { diff --git a/Sources/SwiftNetwork/Utilities/Deserializer.swift b/Sources/SwiftNetwork/Utilities/Deserializer.swift index 95bb0dc..7f48d2d 100644 --- a/Sources/SwiftNetwork/Utilities/Deserializer.swift +++ b/Sources/SwiftNetwork/Utilities/Deserializer.swift @@ -79,7 +79,7 @@ public struct Deserializer Bool { - internalResult.isValid && remaining >= length + (currentSpanByteCount - cursor) >= length } mutating func invalidate(_ error: DeserializationError) throws(DeserializationError) -> Never { @@ -147,27 +160,37 @@ public struct Deserializer(_ value: inout T) throws(DeserializationError) { let length = MemoryLayout.size precondition(length <= 16) + if scratchSpace == nil { + // Lazy initialize on first use + scratchSpace = .init(repeating: 0) + } var filled = 0 while filled < length { let available = min(remaining, length - filled) for i in 0..( _ value: inout T, networkByteOrder: Bool @@ -195,6 +219,7 @@ public struct Deserializer(_ value: inout T) throws(DeserializationError) { let length = MemoryLayout.size guard hasRoom(length) else { @@ -202,12 +227,13 @@ public struct Deserializer( _ value: inout T? ) throws(DeserializationError) { @@ -217,6 +243,7 @@ public struct Deserializer( _ value: inout T, networkByteOrder: Bool @@ -228,6 +255,7 @@ public struct Deserializer( _ value: inout T?, networkByteOrder: Bool @@ -249,7 +277,7 @@ public struct Deserializer.size) + moveCursorUnchecked(MemoryLayout.size) return (value, 1) case 1: var raw: UInt16 = 0 @@ -308,7 +336,7 @@ public struct Deserializer Void - ) -> DeserializationResult where Factory == SingleSpanFactory { - deserialize(SingleSpanFactory(bytes), builder) + ) -> DeserializationResult where Factory == EmptySpanFactory { + var deserializer = Deserializer(span) + do { + try builder(&deserializer) + } catch { + // Error already recorded in internalResult via invalidate + } + return deserializer.finalResult } public static func deserialize( _ buffer: Span, _ builder: (_ buffer: inout Deserializer) throws(DeserializationError) -> Void - ) -> DeserializationResult where Factory == SingleSpanFactory { + ) -> DeserializationResult where Factory == EmptySpanFactory { deserialize(buffer.bytes, builder) } public static func deserialize( _ bytes: [UInt8], _ builder: (_ buffer: inout Deserializer) throws(DeserializationError) -> Void - ) -> DeserializationResult where Factory == SingleSpanFactory { + ) -> DeserializationResult where Factory == EmptySpanFactory { deserialize(bytes.span.bytes, builder) } static func deserialize( _ bytes: inout [UInt8], _ builder: (_ buffer: inout Deserializer) throws(DeserializationError) -> Void - ) -> DeserializationResult where Factory == SingleSpanFactory { + ) -> DeserializationResult where Factory == EmptySpanFactory { let result = deserialize(bytes.span.bytes, builder) if case .success(let parsedBytes, _) = result { bytes = Array(bytes[parsedBytes...]) @@ -797,7 +831,7 @@ public struct Deserializer Void - ) -> DeserializationResult where Factory == SingleSpanFactory { + ) -> DeserializationResult where Factory == EmptySpanFactory { var result: DeserializationResult = .success if let bytes = frame.bytes { result = deserialize(bytes, builder) diff --git a/Sources/SwiftNetwork/Utilities/SerializationHelpers.swift b/Sources/SwiftNetwork/Utilities/SerializationHelpers.swift index eced5ac..094fab2 100644 --- a/Sources/SwiftNetwork/Utilities/SerializationHelpers.swift +++ b/Sources/SwiftNetwork/Utilities/SerializationHelpers.swift @@ -25,29 +25,22 @@ public protocol DeserializerSpanFactory: ~Copyable, ~Escapable { var availableByteCount: Int { get } } -/// A factory that stores a single span. +/// A factory that stores no spans. /// /// Use this factory when initializing a `Deserializer` directly from a `RawSpan`. @_spi(ProtocolProvider) @available(Network 0.1.0, *) -public struct SingleSpanFactory: ~Escapable, DeserializerSpanFactory { - private var span: RawSpan - private var consumed: Bool = false - - @_lifetime(copy span) - init(_ span: RawSpan) { - self.span = span - } +public struct EmptySpanFactory: ~Escapable, DeserializerSpanFactory { + @_lifetime(immortal) + init() {} @_lifetime(&self) public mutating func nextSpan() -> RawSpan? { - guard !consumed else { return nil } - consumed = true - return span + nil } public var availableByteCount: Int { - span.byteCount + 0 } } diff --git a/Sources/SwiftNetwork/Utilities/StreamDeserializer.swift b/Sources/SwiftNetwork/Utilities/StreamDeserializer.swift index 8e562d3..e6c1d4f 100644 --- a/Sources/SwiftNetwork/Utilities/StreamDeserializer.swift +++ b/Sources/SwiftNetwork/Utilities/StreamDeserializer.swift @@ -462,7 +462,7 @@ extension StreamDeserializer where T: ~Copyable, Factory == FrameArraySpanFactor } @available(Network 0.1.0, *) -extension StreamDeserializer where T: ~Copyable, Factory == SingleSpanFactory { +extension StreamDeserializer where T: ~Copyable, Factory == EmptySpanFactory { public mutating func handleSpan(_ span: RawSpan) throws(DeserializationError) -> T? { try handleInputInternal( { builder, value in @@ -523,5 +523,5 @@ public typealias FrameArrayStreamDeserializer = StreamDeserializer< - T, T.StateMachineStepIdentifier, SingleSpanFactory + T, T.StateMachineStepIdentifier, EmptySpanFactory >