From 107356bfb171f00ac58c789388e028ce65e212ac Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Wed, 10 Dec 2025 17:38:14 +0100 Subject: [PATCH 1/3] Move to Spans from unsafe pointers in the API --- Package.swift | 9 + Sources/W3CTraceContext/Docs.docc/index.md | 5 - Sources/W3CTraceContext/Hex.swift | 55 +++-- Sources/W3CTraceContext/SpanID.swift | 192 +++++++-------- Sources/W3CTraceContext/TraceContext.swift | 30 +-- Sources/W3CTraceContext/TraceID.swift | 230 ++++++++---------- Sources/W3CTraceContext/TraceState.swift | 4 +- Tests/W3CTraceContextTests/SpanID+Stubs.swift | 2 +- Tests/W3CTraceContextTests/SpanIDTests.swift | 52 ++-- Tests/W3CTraceContextTests/TestUtils.swift | 25 ++ .../TraceContextTests.swift | 8 +- .../W3CTraceContextTests/TraceID+Stubs.swift | 2 +- Tests/W3CTraceContextTests/TraceIDTests.swift | 53 ++-- 13 files changed, 327 insertions(+), 340 deletions(-) create mode 100644 Tests/W3CTraceContextTests/TestUtils.swift diff --git a/Package.swift b/Package.swift index 42d6583..fe0f754 100644 --- a/Package.swift +++ b/Package.swift @@ -6,10 +6,19 @@ let swiftSettings: [SwiftSetting] = [ .enableUpcomingFeature("MemberImportVisibility"), .enableUpcomingFeature("InternalImportsByDefault"), .enableUpcomingFeature("NonisolatedNonsendingByDefault"), + + // https://forums.swift.org/t/experimental-support-for-lifetime-dependencies-in-swift-6-2-and-beyond/78638 + .enableExperimentalFeature("Lifetimes"), ] let package = Package( name: "swift-w3c-trace-context", + platforms: [ + .macOS(.v10_15), + .iOS(.v13), + .tvOS(.v13), + .watchOS(.v6), + ], products: [ .library(name: "W3CTraceContext", targets: ["W3CTraceContext"]), ], diff --git a/Sources/W3CTraceContext/Docs.docc/index.md b/Sources/W3CTraceContext/Docs.docc/index.md index f4adc9f..ab451d5 100644 --- a/Sources/W3CTraceContext/Docs.docc/index.md +++ b/Sources/W3CTraceContext/Docs.docc/index.md @@ -17,8 +17,3 @@ context propagation, implementing the [W3C Trace Context](https://www.w3.org/TR/ - ``TraceID`` - ``TraceFlags`` - ``TraceState`` - -### Decoding headers - -- ``TraceParentDecodingError`` -- ``TraceStateDecodingError`` diff --git a/Sources/W3CTraceContext/Hex.swift b/Sources/W3CTraceContext/Hex.swift index 672ba21..1839d92 100644 --- a/Sources/W3CTraceContext/Hex.swift +++ b/Sources/W3CTraceContext/Hex.swift @@ -26,10 +26,10 @@ enum Hex { /// /// - Parameters: /// - ascii: The ASCII bytes to convert. - /// - target: The pointer to store the converted bytes into. + /// - target: The mutable span to store the converted bytes into. static func convert( _ ascii: T, - toBytes target: UnsafeMutableRawBufferPointer + toBytes target: inout MutableSpan ) where T: RandomAccessCollection, T.Element == UInt8 { assert(ascii.count / 2 == target.count, "Target needs half as much space as ascii") @@ -37,28 +37,41 @@ enum Hex { var targetIndex = 0 while let major = source.next(), let minor = source.next() { - var byte: UInt8 = 0 + let byte = convert(major: major, minor: minor) + target[targetIndex] = byte + targetIndex += 1 + } + } - switch major { - case UInt8(ascii: "0") ... UInt8(ascii: "9"): - byte = (major - UInt8(ascii: "0")) << 4 - case UInt8(ascii: "a") ... UInt8(ascii: "f"): - byte = (major - UInt8(ascii: "a") + 10) << 4 - default: - preconditionFailure() - } + /// Convert the given two ASCII characters into bytes stored in the given target. + /// + /// - Parameters: + /// - major: The major ASCII character. + /// - minor: The minor ASCII character. + static func convert( + major: UInt8, + minor: UInt8, + ) -> UInt8 { + var byte: UInt8 = 0 - switch minor { - case UInt8(ascii: "0") ... UInt8(ascii: "9"): - byte |= (minor - UInt8(ascii: "0")) - case UInt8(ascii: "a") ... UInt8(ascii: "f"): - byte |= (minor - UInt8(ascii: "a") + 10) - default: - preconditionFailure() - } + switch major { + case UInt8(ascii: "0") ... UInt8(ascii: "9"): + byte = (major - UInt8(ascii: "0")) << 4 + case UInt8(ascii: "a") ... UInt8(ascii: "f"): + byte = (major - UInt8(ascii: "a") + 10) << 4 + default: + preconditionFailure() + } - target[targetIndex] = byte - targetIndex += 1 + switch minor { + case UInt8(ascii: "0") ... UInt8(ascii: "9"): + byte |= (minor - UInt8(ascii: "0")) + case UInt8(ascii: "a") ... UInt8(ascii: "f"): + byte |= (minor - UInt8(ascii: "a") + 10) + default: + preconditionFailure() } + + return byte } } diff --git a/Sources/W3CTraceContext/SpanID.swift b/Sources/W3CTraceContext/SpanID.swift index 0e36e92..b112b21 100644 --- a/Sources/W3CTraceContext/SpanID.swift +++ b/Sources/W3CTraceContext/SpanID.swift @@ -15,26 +15,36 @@ /// /// [W3C TraceContext: parent-id](https://www.w3.org/TR/trace-context-1/#parent-id) public struct SpanID: Sendable { + + @usableFromInline + internal var _bytes: Bytes + /// The 8 bytes making up the span ID. - public let bytes: Bytes + public var bytes: Bytes { + _bytes + } /// Create a span ID from 8 bytes. /// /// - Parameter bytes: The 8 bytes making up the span ID. public init(bytes: Bytes) { - self.bytes = bytes + self._bytes = bytes } /// Create a random span ID using the given random number generator. /// /// - Parameter randomNumberGenerator: The random number generator used to create random bytes for the span ID. /// - Returns: A random span ID. - public static func random(using randomNumberGenerator: inout some RandomNumberGenerator) -> SpanID { - var bytes: SpanID.Bytes = .null - bytes.withUnsafeMutableBytes { ptr in - ptr.storeBytes(of: randomNumberGenerator.next().bigEndian, as: UInt64.self) + public static func random( + using randomNumberGenerator: inout some RandomNumberGenerator + ) -> SpanID { + var id = SpanID.null + id.withMutableSpan { mutableSpan in + mutableSpan.withUnsafeMutableBytes { ptr in + ptr.storeBytes(of: randomNumberGenerator.next().bigEndian, as: UInt64.self) + } } - return SpanID(bytes: bytes) + return id } /// Create a random span ID. @@ -46,124 +56,108 @@ public struct SpanID: Sendable { } } -extension SpanID: Equatable {} +extension SpanID: Equatable { + public static func == (lhs: Self, rhs: Self) -> Bool { + lhs.withSpan { lSpan in + rhs.withSpan { rSpan in + for index in 0 ..< 8 { + let lValue = lSpan[index] + let rValue = rSpan[index] + let elementEquals = lValue == rValue + guard elementEquals else { + return false + } + } + return true + } + } + } +} -extension SpanID: Hashable {} +extension SpanID: Hashable { + public func hash(into hasher: inout Hasher) { + withSpan { span in + for index in span.indices { + hasher.combine(span[index]) + } + } + } +} extension SpanID: Identifiable { public var id: Self { self } } -extension SpanID: CustomStringConvertible { - /// A 16 character hex string representation of the span ID. - public var description: String { - "\(bytes)" - } -} - // MARK: - Bytes - extension SpanID { - /// An 8-byte array. - public struct Bytes: Collection, Equatable, Hashable, Sendable { - public static var null: Self { SpanID.Bytes((0, 0, 0, 0, 0, 0, 0, 0)) } - - @usableFromInline - var _bytes: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) - public init(_ bytes: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)) { - _bytes = bytes - } - - public subscript(position: Int) -> UInt8 { - switch position { - case 0: _bytes.0 - case 1: _bytes.1 - case 2: _bytes.2 - case 3: _bytes.3 - case 4: _bytes.4 - case 5: _bytes.5 - case 6: _bytes.6 - case 7: _bytes.7 - default: fatalError("Index out of range") - } - } + /// An 8-byte array. + public typealias Bytes = (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) - public func index(after i: Int) -> Int { - precondition(i < endIndex, "Can't advance beyond endIndex") - return i + 1 - } + /// A span ID with all zeros. + @inlinable + public static var null: Self { + SpanID(bytes: (0, 0, 0, 0, 0, 0, 0, 0)) + } +} - public var startIndex: Int { 0 } - public var endIndex: Int { 8 } +// Note: The spans below are provided in a closure, instead of returned, because as of +// Swift 6.2 we're still missing the lifetime features to spell it out correctly. +// In the future, we should add the Span/MutableSpan-returning methods and deprecate +// the closure-taking ones. +extension SpanID { - @inlinable - public func withContiguousStorageIfAvailable( - _ body: (UnsafeBufferPointer) throws -> Result - ) rethrows -> Result? { - try Swift.withUnsafeBytes(of: _bytes) { bytes in - try bytes.withMemoryRebound(to: UInt8.self, body) + /// Provides safe, read-only access to the underlying memory. + /// - Parameter body: The closure within you read the provided span. + @inlinable public func withSpan( + _ body: (borrowing Span) -> Result + ) -> Result { + withUnsafeBytes(of: _bytes) { bytes in + bytes.withMemoryRebound(to: UInt8.self) { pointer in + guard let base = pointer.baseAddress else { + return body(Span()) + } + let span = Span(_unsafeStart: base, count: 8) + return body(span) } } + } - /// Calls the given closure with a pointer to the span ID's underlying bytes. - /// - /// - Parameter body: A closure receiving an `UnsafeRawBufferPointer` to the span ID's underlying bytes. - @inlinable - public func withUnsafeBytes(_ body: (UnsafeRawBufferPointer) throws -> Result) rethrows -> Result { - try Swift.withUnsafeBytes(of: _bytes, body) - } - - /// Calls the given closure with a mutable pointer to the span ID's underlying bytes. - /// - /// - Parameter body: A closure receiving an `UnsafeMutableRawBufferPointer` to the span ID's underlying bytes. - @inlinable - public mutating func withUnsafeMutableBytes( - _ body: (UnsafeMutableRawBufferPointer) throws -> Result - ) rethrows -> Result { - try Swift.withUnsafeMutableBytes(of: &_bytes) { bytes in - try body(bytes) + /// Provides safe, mutable access to the underlying memory. + /// - Parameter body: The closure within you read the provided span. + @inlinable public mutating func withMutableSpan( + _ body: (inout MutableSpan) -> Result + ) -> Result { + withUnsafeMutableBytes(of: &_bytes) { bytes in + bytes.withMemoryRebound(to: UInt8.self) { pointer in + guard let base = pointer.baseAddress else { + var span = MutableSpan() + return body(&span) + } + var span = MutableSpan(_unsafeStart: base, count: 8) + return body(&span) } } - - public static func == (lhs: Self, rhs: Self) -> Bool { - lhs._bytes.0 == rhs._bytes.0 - && lhs._bytes.1 == rhs._bytes.1 - && lhs._bytes.2 == rhs._bytes.2 - && lhs._bytes.3 == rhs._bytes.3 - && lhs._bytes.4 == rhs._bytes.4 - && lhs._bytes.5 == rhs._bytes.5 - && lhs._bytes.6 == rhs._bytes.6 - && lhs._bytes.7 == rhs._bytes.7 - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(_bytes.0) - hasher.combine(_bytes.1) - hasher.combine(_bytes.2) - hasher.combine(_bytes.3) - hasher.combine(_bytes.4) - hasher.combine(_bytes.5) - hasher.combine(_bytes.6) - hasher.combine(_bytes.7) - } } } -extension SpanID.Bytes: CustomStringConvertible { - /// A 16 character hex string representation of the bytes. +extension SpanID: CustomStringConvertible { + + /// A 16 character hex string representation of the span ID. public var description: String { String(decoding: hexBytes, as: UTF8.self) } /// A 16 character UTF-8 hex byte array representation of the bytes. public var hexBytes: [UInt8] { - var asciiBytes = [UInt8](repeating: 0, count: 16) - for i in startIndex ..< endIndex { - let byte = self[i] - asciiBytes[2 * i] = Hex.lookup[Int(byte >> 4)] - asciiBytes[2 * i + 1] = Hex.lookup[Int(byte & 0x0F)] + withSpan { span in + var asciiBytes = [UInt8](repeating: 0, count: 16) + for index in span.indices { + let byte = span[index] + asciiBytes[2 * index] = Hex.lookup[Int(byte >> 4)] + asciiBytes[2 * index + 1] = Hex.lookup[Int(byte & 0x0F)] + } + return asciiBytes } - return asciiBytes } } diff --git a/Sources/W3CTraceContext/TraceContext.swift b/Sources/W3CTraceContext/TraceContext.swift index 0d3b3e6..c7fd5ff 100644 --- a/Sources/W3CTraceContext/TraceContext.swift +++ b/Sources/W3CTraceContext/TraceContext.swift @@ -68,11 +68,11 @@ public struct TraceContext: Sendable { // trace ID - var traceIDBytes = TraceID.Bytes.null - withUnsafeMutableBytes(of: &traceIDBytes) { ptr in - Hex.convert(traceParent[3 ..< 35], toBytes: ptr) + var traceID = TraceID.null + traceID.withMutableSpan { span in + Hex.convert(traceParent[3 ..< 35], toBytes: &span) } - if traceIDBytes == .null { + if traceID == .null { throw TraceParentDecodingError( .invalidTraceID(String(decoding: traceParent[3 ..< 35], as: UTF8.self)) ) @@ -80,11 +80,11 @@ public struct TraceContext: Sendable { // span ID - var spanIDBytes = SpanID.Bytes.null - spanIDBytes.withUnsafeMutableBytes { ptr in - Hex.convert(traceParent[36 ..< 52], toBytes: ptr) + var spanID = SpanID.null + spanID.withMutableSpan { span in + Hex.convert(traceParent[36 ..< 52], toBytes: &span) } - if spanIDBytes == .null { + if spanID == .null { throw TraceParentDecodingError( .invalidSpanID(String(decoding: traceParent[36 ..< 52], as: UTF8.self)) ) @@ -92,10 +92,10 @@ public struct TraceContext: Sendable { // flags - var traceFlagsRawValue: UInt8 = 0 - withUnsafeMutableBytes(of: &traceFlagsRawValue) { ptr in - Hex.convert(traceParent[53 ..< 55], toBytes: ptr) - } + let traceFlagsRawValue = Hex.convert( + major: traceParent[53], + minor: traceParent[54] + ) let flags = TraceFlags(rawValue: traceFlagsRawValue) let state: TraceState = if let traceStateHeaderValue, !traceStateHeaderValue.isEmpty { @@ -105,8 +105,8 @@ public struct TraceContext: Sendable { } self = TraceContext( - traceID: TraceID(bytes: traceIDBytes), - spanID: SpanID(bytes: spanIDBytes), + traceID: traceID, + spanID: spanID, flags: flags, state: state ) @@ -136,7 +136,7 @@ public struct TraceContext: Sendable { extension TraceContext: Hashable {} /// An error thrown while decoding a malformed trace parent header. -public struct TraceParentDecodingError: Error { +package struct TraceParentDecodingError: Error { package let reason: Reason init(_ reason: Reason) { diff --git a/Sources/W3CTraceContext/TraceID.swift b/Sources/W3CTraceContext/TraceID.swift index ede2cff..c3668b8 100644 --- a/Sources/W3CTraceContext/TraceID.swift +++ b/Sources/W3CTraceContext/TraceID.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift W3C TraceContext open source project // -// Copyright (c) 2024 the Swift W3C TraceContext project authors +// Copyright (c) 2024-2025 the Swift W3C TraceContext project authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information @@ -15,29 +15,39 @@ /// /// [W3C TraceContext: trace-id](https://www.w3.org/TR/trace-context-1/#trace-id) public struct TraceID: Sendable { + + @usableFromInline + internal var _bytes: Bytes + /// The 16 bytes making up the trace ID. - public let bytes: Bytes + public var bytes: Bytes { + _bytes + } /// Create a trace ID from 16 bytes. /// /// - Parameter bytes: The 16 bytes making up the trace ID. public init(bytes: Bytes) { - self.bytes = bytes + self._bytes = bytes } /// Create a random trace ID using the given random number generator. /// /// - Parameter randomNumberGenerator: The random number generator used to create random bytes for the trace ID. /// - Returns: A random trace ID. - public static func random(using randomNumberGenerator: inout some RandomNumberGenerator) -> TraceID { - var bytes: TraceID.Bytes = .null - bytes.withUnsafeMutableBytes { ptr in - let rand1 = randomNumberGenerator.next() - let rand2 = randomNumberGenerator.next() - ptr.storeBytes(of: rand1.bigEndian, toByteOffset: 0, as: UInt64.self) - ptr.storeBytes(of: rand2.bigEndian, toByteOffset: 8, as: UInt64.self) + public static func random( + using randomNumberGenerator: inout some RandomNumberGenerator + ) -> TraceID { + var id = TraceID.null + id.withMutableSpan { mutableSpan in + mutableSpan.withUnsafeMutableBytes { ptr in + let rand1 = randomNumberGenerator.next() + let rand2 = randomNumberGenerator.next() + ptr.storeBytes(of: rand1.bigEndian, toByteOffset: 0, as: UInt64.self) + ptr.storeBytes(of: rand2.bigEndian, toByteOffset: 8, as: UInt64.self) + } } - return TraceID(bytes: bytes) + return id } /// Create a random trace ID. @@ -49,141 +59,97 @@ public struct TraceID: Sendable { } } -extension TraceID: Equatable {} +extension TraceID: Equatable { + public static func == (lhs: Self, rhs: Self) -> Bool { + lhs.withSpan { lSpan in + rhs.withSpan { rSpan in + for index in 0 ..< 16 { + let lValue = lSpan[index] + let rValue = rSpan[index] + let elementEquals = lValue == rValue + guard elementEquals else { + return false + } + } + return true + } + } + } +} -extension TraceID: Hashable {} +extension TraceID: Hashable { + public func hash(into hasher: inout Hasher) { + withSpan { span in + for index in span.indices { + hasher.combine(span[index]) + } + } + } +} extension TraceID: Identifiable { public var id: Self { self } } -extension TraceID: CustomStringConvertible { - /// A 32-character hex string representation of the trace ID. - public var description: String { - "\(bytes)" - } -} - // MARK: - Bytes extension TraceID { + /// A 16-byte array. - public struct Bytes: Collection, Equatable, Hashable, Sendable { - public static var null: Self { TraceID.Bytes((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) } - - @usableFromInline - var _bytes: ( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 - ) - - public init(_ bytes: ( - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, - UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 - )) { - _bytes = bytes - } - - public subscript(position: Int) -> UInt8 { - switch position { - case 0: _bytes.0 - case 1: _bytes.1 - case 2: _bytes.2 - case 3: _bytes.3 - case 4: _bytes.4 - case 5: _bytes.5 - case 6: _bytes.6 - case 7: _bytes.7 - case 8: _bytes.8 - case 9: _bytes.9 - case 10: _bytes.10 - case 11: _bytes.11 - case 12: _bytes.12 - case 13: _bytes.13 - case 14: _bytes.14 - case 15: _bytes.15 - default: fatalError("Index out of range") - } - } + public typealias Bytes = ( + UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, + UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 + ) + + /// A trace ID with all zeros. + @inlinable + public static var null: Self { + TraceID(bytes: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) + } +} - public func index(after i: Int) -> Int { - precondition(i < endIndex, "Can't advance beyond endIndex") - return i + 1 - } - public var startIndex: Int { 0 } - public var endIndex: Int { 16 } +// Note: The spans below are provided in a closure, instead of returned, because as of +// Swift 6.2 we're still missing the lifetime features to spell it out correctly. +// In the future, we should add the Span/MutableSpan-returning methods and deprecate +// the closure-taking ones. +extension TraceID { - @inlinable - public func withContiguousStorageIfAvailable( - _ body: (UnsafeBufferPointer) throws -> Result - ) rethrows -> Result? { - try Swift.withUnsafeBytes(of: _bytes) { bytes in - try bytes.withMemoryRebound(to: UInt8.self, body) + /// Provides safe, read-only access to the underlying memory. + /// - Parameter body: The closure within you read the provided span. + @inlinable public func withSpan( + _ body: (borrowing Span) -> Result + ) -> Result { + withUnsafeBytes(of: _bytes) { bytes in + bytes.withMemoryRebound(to: UInt8.self) { pointer in + guard let base = pointer.baseAddress else { + return body(Span()) + } + let span = Span(_unsafeStart: base, count: 16) + return body(span) } } + } - /// Calls the given closure with a pointer to the trace ID's underlying bytes. - /// - Parameter body: A closure receiving an `UnsafeRawBufferPointer` to the trace ID's underlying bytes. - @inlinable - public func withUnsafeBytes( - _ body: (UnsafeRawBufferPointer) throws -> Result - ) rethrows -> Result { - try Swift.withUnsafeBytes(of: _bytes, body) - } - - /// Calls the given closure with a mutable pointer to the trace ID's underlying bytes. - /// - Parameter body: A closure receiving an `UnsafeMutableRawBufferPointer` to the trace ID's underlying bytes. - @inlinable - public mutating func withUnsafeMutableBytes( - _ body: (UnsafeMutableRawBufferPointer) throws -> Result - ) rethrows -> Result { - try Swift.withUnsafeMutableBytes(of: &_bytes) { bytes in - try body(bytes) + /// Provides safe, mutable access to the underlying memory. + /// - Parameter body: The closure within you read the provided span. + @inlinable public mutating func withMutableSpan( + _ body: (inout MutableSpan) -> Result + ) -> Result { + withUnsafeMutableBytes(of: &_bytes) { bytes in + bytes.withMemoryRebound(to: UInt8.self) { pointer in + guard let base = pointer.baseAddress else { + var span = MutableSpan() + return body(&span) + } + var span = MutableSpan(_unsafeStart: base, count: 16) + return body(&span) } } - - public static func == (lhs: Self, rhs: Self) -> Bool { - lhs._bytes.0 == rhs._bytes.0 && - lhs._bytes.1 == rhs._bytes.1 && - lhs._bytes.2 == rhs._bytes.2 && - lhs._bytes.3 == rhs._bytes.3 && - lhs._bytes.4 == rhs._bytes.4 && - lhs._bytes.5 == rhs._bytes.5 && - lhs._bytes.6 == rhs._bytes.6 && - lhs._bytes.7 == rhs._bytes.7 && - lhs._bytes.8 == rhs._bytes.8 && - lhs._bytes.9 == rhs._bytes.9 && - lhs._bytes.10 == rhs._bytes.10 && - lhs._bytes.11 == rhs._bytes.11 && - lhs._bytes.12 == rhs._bytes.12 && - lhs._bytes.13 == rhs._bytes.13 && - lhs._bytes.14 == rhs._bytes.14 && - lhs._bytes.15 == rhs._bytes.15 - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(_bytes.0) - hasher.combine(_bytes.1) - hasher.combine(_bytes.2) - hasher.combine(_bytes.3) - hasher.combine(_bytes.4) - hasher.combine(_bytes.5) - hasher.combine(_bytes.6) - hasher.combine(_bytes.7) - hasher.combine(_bytes.8) - hasher.combine(_bytes.9) - hasher.combine(_bytes.10) - hasher.combine(_bytes.11) - hasher.combine(_bytes.12) - hasher.combine(_bytes.13) - hasher.combine(_bytes.14) - hasher.combine(_bytes.15) - } } } -extension TraceID.Bytes: CustomStringConvertible { +extension TraceID: CustomStringConvertible { /// A 32-character hex string representation of the bytes. public var description: String { String(decoding: hexBytes, as: UTF8.self) @@ -191,12 +157,14 @@ extension TraceID.Bytes: CustomStringConvertible { /// A 32-character UTF-8 hex byte array representation of the bytes. public var hexBytes: [UInt8] { - var asciiBytes = [UInt8](repeating: 0, count: 32) - for i in startIndex ..< endIndex { - let byte = self[i] - asciiBytes[2 * i] = Hex.lookup[Int(byte >> 4)] - asciiBytes[2 * i + 1] = Hex.lookup[Int(byte & 0x0F)] + withSpan { span in + var asciiBytes = [UInt8](repeating: 0, count: 32) + for index in span.indices { + let byte = span[index] + asciiBytes[2 * index] = Hex.lookup[Int(byte >> 4)] + asciiBytes[2 * index + 1] = Hex.lookup[Int(byte & 0x0F)] + } + return asciiBytes } - return asciiBytes } } diff --git a/Sources/W3CTraceContext/TraceState.swift b/Sources/W3CTraceContext/TraceState.swift index 9b878fb..f09372f 100644 --- a/Sources/W3CTraceContext/TraceState.swift +++ b/Sources/W3CTraceContext/TraceState.swift @@ -229,11 +229,11 @@ extension TraceState { } /// Errors thrown while decoding a malformed trace state header. -public struct TraceStateDecodingError: Error, CustomDebugStringConvertible { +package struct TraceStateDecodingError: Error, CustomDebugStringConvertible { package let reason: Reason package let headerValue: String - public var debugDescription: String { + package var debugDescription: String { switch reason { case .malformedCharacterInVendor(let characterIndex): let index = characterIndex.utf16Offset(in: headerValue) diff --git a/Tests/W3CTraceContextTests/SpanID+Stubs.swift b/Tests/W3CTraceContextTests/SpanID+Stubs.swift index 8412ca9..15f8834 100644 --- a/Tests/W3CTraceContextTests/SpanID+Stubs.swift +++ b/Tests/W3CTraceContextTests/SpanID+Stubs.swift @@ -15,5 +15,5 @@ import W3CTraceContext extension SpanID { /// A stubbed `SpanID` with bytes from one to eight. - static let oneToEight = SpanID(bytes: .init((1, 2, 3, 4, 5, 6, 7, 8))) + static let oneToEight = SpanID(bytes: (1, 2, 3, 4, 5, 6, 7, 8)) } diff --git a/Tests/W3CTraceContextTests/SpanIDTests.swift b/Tests/W3CTraceContextTests/SpanIDTests.swift index 500bcc2..d6da38c 100644 --- a/Tests/W3CTraceContextTests/SpanIDTests.swift +++ b/Tests/W3CTraceContextTests/SpanIDTests.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift W3C TraceContext open source project // -// Copyright (c) 2024 the Swift W3C TraceContext project authors +// Copyright (c) 2024-2025 the Swift W3C TraceContext project authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information @@ -15,15 +15,15 @@ import W3CTraceContext import XCTest final class SpanIDTests: XCTestCase { - func test_bytes_returnsEightByteArrayRepresentation() { + func test_initFromBytes() { let spanID = SpanID.oneToEight - XCTAssertEqual(Array(spanID.bytes), [1, 2, 3, 4, 5, 6, 7, 8]) + XCTAssertEqual(spanID, SpanID(bytes: (1, 2, 3, 4, 5, 6, 7, 8))) } func test_equatableConformance() { - let spanID1 = SpanID(bytes: .init((1, 2, 3, 4, 5, 6, 7, 8))) - let spanID2 = SpanID(bytes: .init((1, 2, 3, 4, 5, 6, 7, 0))) + let spanID1 = SpanID(bytes: (1, 2, 3, 4, 5, 6, 7, 8)) + let spanID2 = SpanID(bytes: (1, 2, 3, 4, 5, 6, 7, 0)) XCTAssertEqual(spanID1, spanID1) XCTAssertEqual(spanID2, spanID2) @@ -37,7 +37,7 @@ final class SpanIDTests: XCTestCase { } func test_description_returnsHexStringRepresentation() { - let spanID = SpanID(bytes: .init((0, 10, 20, 50, 100, 150, 200, 255))) + let spanID = SpanID(bytes: (0, 10, 20, 50, 100, 150, 200, 255)) XCTAssertEqual("\(spanID)", "000a14326496c8ff") } @@ -46,10 +46,10 @@ final class SpanIDTests: XCTestCase { var generator = IncrementingRandomNumberGenerator() let spanID1 = SpanID.random(using: &generator) - XCTAssertEqual(spanID1, SpanID(bytes: .init((0, 0, 0, 0, 0, 0, 0, 0)))) + XCTAssertEqual(spanID1, SpanID(bytes: (0, 0, 0, 0, 0, 0, 0, 0))) let spanID2 = SpanID.random(using: &generator) - XCTAssertEqual(spanID2, SpanID(bytes: .init((0, 0, 0, 0, 0, 0, 0, 1)))) + XCTAssertEqual(spanID2, SpanID(bytes: (0, 0, 0, 0, 0, 0, 0, 1))) } func test_random_withDefaultNumberGenerator_returnsRandomSpanIDs() { @@ -60,32 +60,24 @@ final class SpanIDTests: XCTestCase { // MARK: - Bytes - func test_spanIDBytes_withUnsafeBytes_invokesClosureWithPointerToBytes() { - let bytes = SpanID.Bytes((0, 10, 20, 50, 100, 150, 200, 255)) - - let byteArray = bytes.withUnsafeBytes { ptr in - Array(ptr) + @available(macOS 26.0, iOS 26.0, tvOS 26.0, watchOS 26.0, visionOS 26.0, *) + func test_bytes_span() { + let id = SpanID(bytes: (0, 10, 20, 50, 100, 150, 200, 255)) + let expectedBytes: [UInt8] = [0, 10, 20, 50, 100, 150, 200, 255] + id.withSpan { idSpan in + XCTAssertEqualUInt8Spans(idSpan, expectedBytes.span) } - XCTAssertEqual(byteArray, [0, 10, 20, 50, 100, 150, 200, 255]) } - func test_spanIDBytes_withUnsafeMutableBytes_allowsMutatingBytesViaClosure() { - var bytes = SpanID.Bytes((0, 10, 20, 50, 100, 150, 200, 255)) - - bytes.withUnsafeMutableBytes { ptr in - ptr.storeBytes(of: 42, as: UInt8.self) + @available(macOS 26.0, iOS 26.0, tvOS 26.0, watchOS 26.0, visionOS 26.0, *) + func test_bytes_mutableSpan() { + var id = SpanID(bytes: (0, 10, 20, 50, 100, 150, 200, 255)) + id.withMutableSpan { idSpan in + idSpan[0] = 42 } - - XCTAssertEqual(Array(bytes), [42, 10, 20, 50, 100, 150, 200, 255]) - } - - func test_withContiguousStorageIfAvailable_invokesClosureWithPointerToBytes() { - let bytes = SpanID.Bytes((0, 10, 20, 50, 100, 150, 200, 255)) - - let byteArray = bytes.withContiguousStorageIfAvailable { ptr in - Array(ptr) + let expectedBytes: [UInt8] = [42, 10, 20, 50, 100, 150, 200, 255] + id.withSpan { idSpan in + XCTAssertEqualUInt8Spans(idSpan, expectedBytes.span) } - - XCTAssertEqual(byteArray, [0, 10, 20, 50, 100, 150, 200, 255]) } } diff --git a/Tests/W3CTraceContextTests/TestUtils.swift b/Tests/W3CTraceContextTests/TestUtils.swift new file mode 100644 index 0000000..d64ab95 --- /dev/null +++ b/Tests/W3CTraceContextTests/TestUtils.swift @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift W3C TraceContext open source project +// +// Copyright (c) 2025 the Swift W3C TraceContext project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +import XCTest + +func XCTAssertEqualUInt8Spans( + _ lhs: Span, + _ rhs: Span, + file: StaticString = #filePath, + line: UInt = #line +) { + for index in lhs.indices { + XCTAssertEqual(lhs[index], rhs[index], "Index: \(index)", file: file, line: line) + } +} diff --git a/Tests/W3CTraceContextTests/TraceContextTests.swift b/Tests/W3CTraceContextTests/TraceContextTests.swift index 19e3c2c..7ff6ca9 100644 --- a/Tests/W3CTraceContextTests/TraceContextTests.swift +++ b/Tests/W3CTraceContextTests/TraceContextTests.swift @@ -21,8 +21,8 @@ final class TraceContextTests: XCTestCase { ) XCTAssertEqual(traceContext, TraceContext( - traceID: TraceID(bytes: .init((10, 247, 101, 25, 22, 205, 67, 221, 132, 72, 235, 33, 28, 128, 49, 156))), - spanID: SpanID(bytes: .init((183, 173, 107, 113, 105, 32, 51, 49))), + traceID: TraceID(bytes: (10, 247, 101, 25, 22, 205, 67, 221, 132, 72, 235, 33, 28, 128, 49, 156)), + spanID: SpanID(bytes: (183, 173, 107, 113, 105, 32, 51, 49)), flags: .sampled, state: TraceState() )) @@ -35,8 +35,8 @@ final class TraceContextTests: XCTestCase { ) XCTAssertEqual(traceContext, TraceContext( - traceID: TraceID(bytes: .init((10, 247, 101, 25, 22, 205, 67, 221, 132, 72, 235, 33, 28, 128, 49, 156))), - spanID: SpanID(bytes: .init((183, 173, 107, 113, 105, 32, 51, 49))), + traceID: TraceID(bytes: (10, 247, 101, 25, 22, 205, 67, 221, 132, 72, 235, 33, 28, 128, 49, 156)), + spanID: SpanID(bytes: (183, 173, 107, 113, 105, 32, 51, 49)), flags: .sampled, state: TraceState([ (.simple("foo"), "bar"), diff --git a/Tests/W3CTraceContextTests/TraceID+Stubs.swift b/Tests/W3CTraceContextTests/TraceID+Stubs.swift index 3a969cc..75ce164 100644 --- a/Tests/W3CTraceContextTests/TraceID+Stubs.swift +++ b/Tests/W3CTraceContextTests/TraceID+Stubs.swift @@ -15,5 +15,5 @@ import W3CTraceContext extension TraceID { /// A stubbed `TraceID` with bytes from one to sixteen. - static let oneToSixteen = TraceID(bytes: .init((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16))) + static let oneToSixteen = TraceID(bytes: (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)) } diff --git a/Tests/W3CTraceContextTests/TraceIDTests.swift b/Tests/W3CTraceContextTests/TraceIDTests.swift index 57d85a6..d9ccc9a 100644 --- a/Tests/W3CTraceContextTests/TraceIDTests.swift +++ b/Tests/W3CTraceContextTests/TraceIDTests.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift W3C TraceContext open source project // -// Copyright (c) 2024 the Swift W3C TraceContext project authors +// Copyright (c) 2024-2025 the Swift W3C TraceContext project authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information @@ -15,16 +15,15 @@ import W3CTraceContext import XCTest final class TraceIDTests: XCTestCase { - func test_bytes_returnsSixteenByteArrayRepresentation() { + func test_initFromBytes() { let traceID = TraceID.oneToSixteen - let array = Array(traceID.bytes) - XCTAssertEqual(array, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]) + XCTAssertEqual(traceID, TraceID(bytes: (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16))) } func test_equatableConformance() { - let traceID1 = TraceID(bytes: .init((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16))) - let traceID2 = TraceID(bytes: .init((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0))) + let traceID1 = TraceID(bytes: (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)) + let traceID2 = TraceID(bytes: (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0)) XCTAssertEqual(traceID1, traceID1) XCTAssertEqual(traceID2, traceID2) @@ -38,7 +37,7 @@ final class TraceIDTests: XCTestCase { } func test_description_returnsHexStringRepresentation() { - let traceID = TraceID(bytes: .init((0, 10, 20, 30, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 255))) + let traceID = TraceID(bytes: (0, 10, 20, 30, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 255)) XCTAssertEqual("\(traceID)", "000a141e283c5064788ca0b4c8dcf0ff") } @@ -47,10 +46,10 @@ final class TraceIDTests: XCTestCase { var generator = IncrementingRandomNumberGenerator() let traceID1 = TraceID.random(using: &generator) - XCTAssertEqual(traceID1, TraceID(bytes: .init((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)))) + XCTAssertEqual(traceID1, TraceID(bytes: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1))) let traceID2 = TraceID.random(using: &generator) - XCTAssertEqual(traceID2, TraceID(bytes: .init((0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3)))) + XCTAssertEqual(traceID2, TraceID(bytes: (0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3))) } func test_random_withDefaultNumberGenerator_returnsRandomSpanIDs() { @@ -61,32 +60,24 @@ final class TraceIDTests: XCTestCase { // MARK: - Bytes - func test_traceIDBytes_withUnsafeBytes_invokesClosureWithPointerToBytes() { - let bytes = TraceID.Bytes((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)) - - let byteArray = bytes.withUnsafeBytes { ptr in - Array(ptr) + @available(macOS 26.0, iOS 26.0, tvOS 26.0, watchOS 26.0, visionOS 26.0, *) + func test_bytes_span() { + let id = TraceID(bytes: (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)) + let expectedBytes: [UInt8] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] + id.withSpan { idSpan in + XCTAssertEqualUInt8Spans(idSpan, expectedBytes.span) } - XCTAssertEqual(byteArray, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]) } - func test_traceIDBytes_withUnsafeMutableBytes_allowsMutatingBytesViaClosure() { - var bytes = TraceID.Bytes((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)) - - bytes.withUnsafeMutableBytes { ptr in - ptr.storeBytes(of: 42, as: UInt8.self) + @available(macOS 26.0, iOS 26.0, tvOS 26.0, watchOS 26.0, visionOS 26.0, *) + func test_bytes_mutableSpan() { + var id = TraceID(bytes: (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)) + id.withMutableSpan { idSpan in + idSpan[0] = 42 } - - XCTAssertEqual(Array(bytes), [42, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]) - } - - func test_withContiguousStorageIfAvailable_invokesClosureWithPointerToBytes() { - let bytes = TraceID.Bytes((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)) - - let byteArray = bytes.withContiguousStorageIfAvailable { ptr in - Array(ptr) + let expectedBytes: [UInt8] = [42, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] + id.withSpan { idSpan in + XCTAssertEqualUInt8Spans(idSpan, expectedBytes.span) } - - XCTAssertEqual(byteArray, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]) } } From 9f1a9ac6559b4839ff17f2e15bc4e43464d90816 Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Wed, 10 Dec 2025 17:44:02 +0100 Subject: [PATCH 2/3] Fix soundness that checks for the format of license headers - can't handle a year range --- Sources/W3CTraceContext/TraceID.swift | 2 +- Tests/W3CTraceContextTests/SpanIDTests.swift | 2 +- Tests/W3CTraceContextTests/TraceIDTests.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/W3CTraceContext/TraceID.swift b/Sources/W3CTraceContext/TraceID.swift index c3668b8..27bc585 100644 --- a/Sources/W3CTraceContext/TraceID.swift +++ b/Sources/W3CTraceContext/TraceID.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift W3C TraceContext open source project // -// Copyright (c) 2024-2025 the Swift W3C TraceContext project authors +// Copyright (c) 2024 the Swift W3C TraceContext project authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information diff --git a/Tests/W3CTraceContextTests/SpanIDTests.swift b/Tests/W3CTraceContextTests/SpanIDTests.swift index d6da38c..c2dd347 100644 --- a/Tests/W3CTraceContextTests/SpanIDTests.swift +++ b/Tests/W3CTraceContextTests/SpanIDTests.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift W3C TraceContext open source project // -// Copyright (c) 2024-2025 the Swift W3C TraceContext project authors +// Copyright (c) 2024 the Swift W3C TraceContext project authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information diff --git a/Tests/W3CTraceContextTests/TraceIDTests.swift b/Tests/W3CTraceContextTests/TraceIDTests.swift index d9ccc9a..6521703 100644 --- a/Tests/W3CTraceContextTests/TraceIDTests.swift +++ b/Tests/W3CTraceContextTests/TraceIDTests.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift W3C TraceContext open source project // -// Copyright (c) 2024-2025 the Swift W3C TraceContext project authors +// Copyright (c) 2024 the Swift W3C TraceContext project authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information From 3bc89fdd4947a6d4f9e4597f6a1afeba4e31ac79 Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Wed, 10 Dec 2025 17:57:10 +0100 Subject: [PATCH 3/3] Formatting fixes --- Sources/W3CTraceContext/SpanID.swift | 9 +++------ Sources/W3CTraceContext/TraceContext.swift | 2 +- Sources/W3CTraceContext/TraceID.swift | 10 +++------- Tests/W3CTraceContextTests/TestUtils.swift | 2 +- scripts/validate_license_headers.sh | 2 +- 5 files changed, 9 insertions(+), 16 deletions(-) diff --git a/Sources/W3CTraceContext/SpanID.swift b/Sources/W3CTraceContext/SpanID.swift index b112b21..9e1a95e 100644 --- a/Sources/W3CTraceContext/SpanID.swift +++ b/Sources/W3CTraceContext/SpanID.swift @@ -15,9 +15,8 @@ /// /// [W3C TraceContext: parent-id](https://www.w3.org/TR/trace-context-1/#parent-id) public struct SpanID: Sendable { - @usableFromInline - internal var _bytes: Bytes + var _bytes: Bytes /// The 8 bytes making up the span ID. public var bytes: Bytes { @@ -28,7 +27,7 @@ public struct SpanID: Sendable { /// /// - Parameter bytes: The 8 bytes making up the span ID. public init(bytes: Bytes) { - self._bytes = bytes + _bytes = bytes } /// Create a random span ID using the given random number generator. @@ -89,8 +88,8 @@ extension SpanID: Identifiable { } // MARK: - Bytes -extension SpanID { +extension SpanID { /// An 8-byte array. public typealias Bytes = (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) @@ -106,7 +105,6 @@ extension SpanID { // In the future, we should add the Span/MutableSpan-returning methods and deprecate // the closure-taking ones. extension SpanID { - /// Provides safe, read-only access to the underlying memory. /// - Parameter body: The closure within you read the provided span. @inlinable public func withSpan( @@ -142,7 +140,6 @@ extension SpanID { } extension SpanID: CustomStringConvertible { - /// A 16 character hex string representation of the span ID. public var description: String { String(decoding: hexBytes, as: UTF8.self) diff --git a/Sources/W3CTraceContext/TraceContext.swift b/Sources/W3CTraceContext/TraceContext.swift index c7fd5ff..7e96860 100644 --- a/Sources/W3CTraceContext/TraceContext.swift +++ b/Sources/W3CTraceContext/TraceContext.swift @@ -93,7 +93,7 @@ public struct TraceContext: Sendable { // flags let traceFlagsRawValue = Hex.convert( - major: traceParent[53], + major: traceParent[53], minor: traceParent[54] ) let flags = TraceFlags(rawValue: traceFlagsRawValue) diff --git a/Sources/W3CTraceContext/TraceID.swift b/Sources/W3CTraceContext/TraceID.swift index 27bc585..9a24067 100644 --- a/Sources/W3CTraceContext/TraceID.swift +++ b/Sources/W3CTraceContext/TraceID.swift @@ -15,9 +15,8 @@ /// /// [W3C TraceContext: trace-id](https://www.w3.org/TR/trace-context-1/#trace-id) public struct TraceID: Sendable { - @usableFromInline - internal var _bytes: Bytes + var _bytes: Bytes /// The 16 bytes making up the trace ID. public var bytes: Bytes { @@ -28,7 +27,7 @@ public struct TraceID: Sendable { /// /// - Parameter bytes: The 16 bytes making up the trace ID. public init(bytes: Bytes) { - self._bytes = bytes + _bytes = bytes } /// Create a random trace ID using the given random number generator. @@ -94,13 +93,12 @@ extension TraceID: Identifiable { // MARK: - Bytes extension TraceID { - /// A 16-byte array. public typealias Bytes = ( UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 ) - + /// A trace ID with all zeros. @inlinable public static var null: Self { @@ -108,13 +106,11 @@ extension TraceID { } } - // Note: The spans below are provided in a closure, instead of returned, because as of // Swift 6.2 we're still missing the lifetime features to spell it out correctly. // In the future, we should add the Span/MutableSpan-returning methods and deprecate // the closure-taking ones. extension TraceID { - /// Provides safe, read-only access to the underlying memory. /// - Parameter body: The closure within you read the provided span. @inlinable public func withSpan( diff --git a/Tests/W3CTraceContextTests/TestUtils.swift b/Tests/W3CTraceContextTests/TestUtils.swift index d64ab95..94737fe 100644 --- a/Tests/W3CTraceContextTests/TestUtils.swift +++ b/Tests/W3CTraceContextTests/TestUtils.swift @@ -14,7 +14,7 @@ import XCTest func XCTAssertEqualUInt8Spans( - _ lhs: Span, + _ lhs: Span, _ rhs: Span, file: StaticString = #filePath, line: UInt = #line diff --git a/scripts/validate_license_headers.sh b/scripts/validate_license_headers.sh index 5d527c6..14b1388 100755 --- a/scripts/validate_license_headers.sh +++ b/scripts/validate_license_headers.sh @@ -31,7 +31,7 @@ here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" function replace_acceptable_years() { # this needs to replace all acceptable forms with 'YEARS' - sed -e 's/202[4]/YEARS/' + sed -e 's/202[4,5]/YEARS/' } printf "=> Checking license headers\n"