From 9a2758b823afa88a21bbcbb9d557a2e2f49786e7 Mon Sep 17 00:00:00 2001 From: Cory Benfield Date: Thu, 11 Sep 2025 16:25:28 +0100 Subject: [PATCH 1/2] Replace rethrows with typed throws in ByteBuffer Motivation: Users who want to use typed throws would benefit from us propagating the thrown error type through our APIs. Most of our surface doesn't allow for that because it relies on standard library APIs that haven't been updated, but we can do it for ByteBuffer which is entirely ours. Modifications: - Adopt typed rethrows in ByteBuffer Result: Users have an easier time working with ByteBuffer --- Sources/NIOCore/ByteBuffer-aux.swift | 28 +++++----- ...ByteBuffer-binaryEncodedLengthPrefix.swift | 6 +-- Sources/NIOCore/ByteBuffer-core.swift | 52 +++++++++---------- Sources/NIOCore/ByteBuffer-views.swift | 8 +-- .../Docs.docc/ByteBuffer-lengthPrefix.md | 6 +-- 5 files changed, 50 insertions(+), 50 deletions(-) diff --git a/Sources/NIOCore/ByteBuffer-aux.swift b/Sources/NIOCore/ByteBuffer-aux.swift index e95ab8f37d..e6ead593b2 100644 --- a/Sources/NIOCore/ByteBuffer-aux.swift +++ b/Sources/NIOCore/ByteBuffer-aux.swift @@ -426,8 +426,8 @@ extension ByteBuffer { /// - Returns: The number of bytes read. @discardableResult @inlinable - public mutating func readWithUnsafeReadableBytes(_ body: (UnsafeRawBufferPointer) throws -> Int) rethrows -> Int { - let bytesRead = try self.withUnsafeReadableBytes({ try body($0) }) + public mutating func readWithUnsafeReadableBytes(_ body: (UnsafeRawBufferPointer) throws(ErrorType) -> Int) throws(ErrorType) -> Int { + let bytesRead = try self.withUnsafeReadableBytes({ (ptr: UnsafeRawBufferPointer) throws(ErrorType) -> Int in try body(ptr) }) self._moveReaderIndex(forwardBy: bytesRead) return bytesRead } @@ -442,10 +442,10 @@ extension ByteBuffer { /// - Returns: The number of bytes read. @discardableResult @inlinable - public mutating func readWithUnsafeMutableReadableBytes( - _ body: (UnsafeMutableRawBufferPointer) throws -> Int - ) rethrows -> Int { - let bytesRead = try self.withUnsafeMutableReadableBytes({ try body($0) }) + public mutating func readWithUnsafeMutableReadableBytes( + _ body: (UnsafeMutableRawBufferPointer) throws(ErrorType) -> Int + ) throws(ErrorType) -> Int { + let bytesRead = try self.withUnsafeMutableReadableBytes({ (ptr: UnsafeMutableRawBufferPointer) throws(ErrorType) -> Int in try body(ptr) }) self._moveReaderIndex(forwardBy: bytesRead) return bytesRead } @@ -619,10 +619,10 @@ extension ByteBuffer { /// - body: The closure that will accept the yielded bytes and returns the number of bytes it processed along with some other value. /// - Returns: The value `body` returned in the second tuple component. @inlinable - public mutating func readWithUnsafeMutableReadableBytes( - _ body: (UnsafeMutableRawBufferPointer) throws -> (Int, T) - ) rethrows -> T { - let (bytesRead, ret) = try self.withUnsafeMutableReadableBytes({ try body($0) }) + public mutating func readWithUnsafeMutableReadableBytes( + _ body: (UnsafeMutableRawBufferPointer) throws(ErrorType) -> (Int, T) + ) throws(ErrorType) -> T { + let (bytesRead, ret) = try self.withUnsafeMutableReadableBytes({ (ptr: UnsafeMutableRawBufferPointer) throws(ErrorType) -> (Int, T) in try body(ptr) }) self._moveReaderIndex(forwardBy: bytesRead) return ret } @@ -636,10 +636,10 @@ extension ByteBuffer { /// - body: The closure that will accept the yielded bytes and returns the number of bytes it processed along with some other value. /// - Returns: The value `body` returned in the second tuple component. @inlinable - public mutating func readWithUnsafeReadableBytes( - _ body: (UnsafeRawBufferPointer) throws -> (Int, T) - ) rethrows -> T { - let (bytesRead, ret) = try self.withUnsafeReadableBytes({ try body($0) }) + public mutating func readWithUnsafeReadableBytes( + _ body: (UnsafeRawBufferPointer) throws(ErrorType) -> (Int, T) + ) throws(ErrorType) -> T { + let (bytesRead, ret) = try self.withUnsafeReadableBytes({ (ptr: UnsafeRawBufferPointer) throws(ErrorType) -> (Int, T) in try body(ptr) }) self._moveReaderIndex(forwardBy: bytesRead) return ret } diff --git a/Sources/NIOCore/ByteBuffer-binaryEncodedLengthPrefix.swift b/Sources/NIOCore/ByteBuffer-binaryEncodedLengthPrefix.swift index cf97570d0f..f18999cd39 100644 --- a/Sources/NIOCore/ByteBuffer-binaryEncodedLengthPrefix.swift +++ b/Sources/NIOCore/ByteBuffer-binaryEncodedLengthPrefix.swift @@ -116,10 +116,10 @@ extension ByteBuffer { /// - Returns: Number of total bytes written. This is the length of the written data + the number of bytes used to write the length before it. @discardableResult @inlinable - public mutating func writeLengthPrefixed( + public mutating func writeLengthPrefixed( strategy: Strategy, - writeData: (_ buffer: inout ByteBuffer) throws -> Int - ) rethrows -> Int { + writeData: (_ buffer: inout ByteBuffer) throws(ErrorType) -> Int + ) throws(ErrorType) -> Int { /// The index at which we write the length let lengthPrefixIndex = self.writerIndex /// The space which we reserve for writing the length diff --git a/Sources/NIOCore/ByteBuffer-core.swift b/Sources/NIOCore/ByteBuffer-core.swift index add0340b77..e568241c64 100644 --- a/Sources/NIOCore/ByteBuffer-core.swift +++ b/Sources/NIOCore/ByteBuffer-core.swift @@ -682,9 +682,9 @@ public struct ByteBuffer { /// - body: The closure that will accept the yielded bytes. /// - Returns: The value returned by `body`. @inlinable - public mutating func withUnsafeMutableReadableBytes( - _ body: (UnsafeMutableRawBufferPointer) throws -> T - ) rethrows -> T { + public mutating func withUnsafeMutableReadableBytes( + _ body: (UnsafeMutableRawBufferPointer) throws(ErrorType) -> T + ) throws(ErrorType) -> T { self._copyStorageAndRebaseIfNeeded() // this is safe because we always know that readerIndex >= writerIndex let range = Range(uncheckedBounds: (lower: self.readerIndex, upper: self.writerIndex)) @@ -702,9 +702,9 @@ public struct ByteBuffer { /// - body: The closure that will accept the yielded bytes and return the number of bytes written. /// - Returns: The number of bytes written. @inlinable - public mutating func withUnsafeMutableWritableBytes( - _ body: (UnsafeMutableRawBufferPointer) throws -> T - ) rethrows -> T { + public mutating func withUnsafeMutableWritableBytes( + _ body: (UnsafeMutableRawBufferPointer) throws(ErrorType) -> T + ) throws(ErrorType) -> T { self._copyStorageAndRebaseIfNeeded() return try body(.init(rebasing: self._slicedStorageBuffer.dropFirst(self.writerIndex))) } @@ -719,14 +719,14 @@ public struct ByteBuffer { /// - Returns: The number of bytes written. @discardableResult @inlinable - public mutating func writeWithUnsafeMutableBytes( + public mutating func writeWithUnsafeMutableBytes( minimumWritableBytes: Int, - _ body: (UnsafeMutableRawBufferPointer) throws -> Int - ) rethrows -> Int { + _ body: (UnsafeMutableRawBufferPointer) throws(ErrorType) -> Int + ) throws(ErrorType) -> Int { if minimumWritableBytes > 0 { self.reserveCapacity(minimumWritableBytes: minimumWritableBytes) } - let bytesWritten = try self.withUnsafeMutableWritableBytes({ try body($0) }) + let bytesWritten = try self.withUnsafeMutableWritableBytes({ (ptr: UnsafeMutableRawBufferPointer) throws(ErrorType) -> Int in try body(ptr) }) self._moveWriterIndex(to: self._writerIndex + _toIndex(bytesWritten)) return bytesWritten } @@ -739,10 +739,10 @@ public struct ByteBuffer { ) @discardableResult @inlinable - public mutating func writeWithUnsafeMutableBytes( - _ body: (UnsafeMutableRawBufferPointer) throws -> Int - ) rethrows -> Int { - try self.writeWithUnsafeMutableBytes(minimumWritableBytes: 0, { try body($0) }) + public mutating func writeWithUnsafeMutableBytes( + _ body: (UnsafeMutableRawBufferPointer) throws(ErrorType) -> Int + ) throws(ErrorType) -> Int { + try self.writeWithUnsafeMutableBytes(minimumWritableBytes: 0, { (ptr: UnsafeMutableRawBufferPointer) throws(ErrorType) -> Int in try body(ptr) }) } /// This vends a pointer to the storage of the `ByteBuffer`. It's marked as _very unsafe_ because it might contain @@ -750,7 +750,7 @@ public struct ByteBuffer { /// /// - warning: Do not escape the pointer from the closure for later use. @inlinable - public func withVeryUnsafeBytes(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T { + public func withVeryUnsafeBytes(_ body: (UnsafeRawBufferPointer) throws(ErrorType) -> T) throws(ErrorType) -> T { try body(.init(self._slicedStorageBuffer)) } @@ -759,9 +759,9 @@ public struct ByteBuffer { /// /// - warning: Do not escape the pointer from the closure for later use. @inlinable - public mutating func withVeryUnsafeMutableBytes( - _ body: (UnsafeMutableRawBufferPointer) throws -> T - ) rethrows -> T { + public mutating func withVeryUnsafeMutableBytes( + _ body: (UnsafeMutableRawBufferPointer) throws(ErrorType) -> T + ) throws(ErrorType) -> T { self._copyStorageAndRebaseIfNeeded() // this will trigger a CoW if necessary return try body(.init(self._slicedStorageBuffer)) } @@ -774,7 +774,7 @@ public struct ByteBuffer { /// - body: The closure that will accept the yielded bytes. /// - Returns: The value returned by `body`. @inlinable - public func withUnsafeReadableBytes(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T { + public func withUnsafeReadableBytes(_ body: (UnsafeRawBufferPointer) throws(ErrorType) -> T) throws(ErrorType) -> T { // This is safe, writerIndex >= readerIndex let range = Range(uncheckedBounds: (lower: self.readerIndex, upper: self.writerIndex)) return try body(.init(rebasing: self._slicedStorageBuffer[range])) @@ -792,9 +792,9 @@ public struct ByteBuffer { /// - body: The closure that will accept the yielded bytes and the `storageManagement`. /// - Returns: The value returned by `body`. @inlinable - public func withUnsafeReadableBytesWithStorageManagement( - _ body: (UnsafeRawBufferPointer, Unmanaged) throws -> T - ) rethrows -> T { + public func withUnsafeReadableBytesWithStorageManagement( + _ body: (UnsafeRawBufferPointer, Unmanaged) throws(ErrorType) -> T + ) throws(ErrorType) -> T { let storageReference: Unmanaged = Unmanaged.passUnretained(self._storage) // This is safe, writerIndex >= readerIndex let range = Range(uncheckedBounds: (lower: self.readerIndex, upper: self.writerIndex)) @@ -803,9 +803,9 @@ public struct ByteBuffer { /// See `withUnsafeReadableBytesWithStorageManagement` and `withVeryUnsafeBytes`. @inlinable - public func withVeryUnsafeBytesWithStorageManagement( - _ body: (UnsafeRawBufferPointer, Unmanaged) throws -> T - ) rethrows -> T { + public func withVeryUnsafeBytesWithStorageManagement( + _ body: (UnsafeRawBufferPointer, Unmanaged) throws(ErrorType) -> T + ) throws(ErrorType) -> T { let storageReference: Unmanaged = Unmanaged.passUnretained(self._storage) return try body(.init(self._slicedStorageBuffer), storageReference) } @@ -1257,7 +1257,7 @@ extension ByteBuffer { /// - body: The modification operation to execute, with this `ByteBuffer` passed `inout` as an argument. /// - Returns: The return value of `body`. @inlinable - public mutating func modifyIfUniquelyOwned(_ body: (inout ByteBuffer) throws -> T) rethrows -> T? { + public mutating func modifyIfUniquelyOwned(_ body: (inout ByteBuffer) throws(ErrorType) -> T) throws(ErrorType) -> T? { if isKnownUniquelyReferenced(&self._storage) { return try body(&self) } else { diff --git a/Sources/NIOCore/ByteBuffer-views.swift b/Sources/NIOCore/ByteBuffer-views.swift index 8563a301b8..a7b6cefc06 100644 --- a/Sources/NIOCore/ByteBuffer-views.swift +++ b/Sources/NIOCore/ByteBuffer-views.swift @@ -38,8 +38,8 @@ public struct ByteBufferView: RandomAccessCollection, Sendable { } @inlinable - public func withUnsafeBytes(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R { - try self._buffer.withVeryUnsafeBytes { ptr in + public func withUnsafeBytes(_ body: (UnsafeRawBufferPointer) throws(ErrorType) -> R) throws(ErrorType) -> R { + try self._buffer.withVeryUnsafeBytes { (ptr: UnsafeRawBufferPointer) throws(ErrorType) -> R in try body( UnsafeRawBufferPointer( start: ptr.baseAddress!.advanced(by: self._range.lowerBound), @@ -98,8 +98,8 @@ public struct ByteBufferView: RandomAccessCollection, Sendable { } @inlinable - public func withContiguousStorageIfAvailable(_ body: (UnsafeBufferPointer) throws -> R) rethrows -> R? { - try self.withUnsafeBytes { bytes in + public func withContiguousStorageIfAvailable(_ body: (UnsafeBufferPointer) throws(ErrorType) -> R) throws(ErrorType) -> R? { + try self.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) throws(ErrorType) -> R in try body(bytes.bindMemory(to: UInt8.self)) } } diff --git a/Sources/NIOCore/Docs.docc/ByteBuffer-lengthPrefix.md b/Sources/NIOCore/Docs.docc/ByteBuffer-lengthPrefix.md index 57364f2857..79867b12bc 100644 --- a/Sources/NIOCore/Docs.docc/ByteBuffer-lengthPrefix.md +++ b/Sources/NIOCore/Docs.docc/ByteBuffer-lengthPrefix.md @@ -56,10 +56,10 @@ We decided to add the following API to ByteBuffer: /// - strategy: The strategy to use for encoding the length. /// - writeData: A closure that takes a buffer, writes some data to it, and returns the number of bytes written. /// - Returns: Number of total bytes written. This is the length of the written data + the number of bytes used to write the length before it. -public mutating func writeLengthPrefixed( +public mutating func writeLengthPrefixed( strategy: Strategy, - writeData: (_ buffer: inout ByteBuffer) throws -> Int -) rethrows -> Int + writeData: (_ buffer: inout ByteBuffer) throws(ErrorType) -> Int +) throws(ErrorType) -> Int ``` Users could use the function as follows: From 9b1171e1d507ed0a4a173039ce484d7de3a3a7b0 Mon Sep 17 00:00:00 2001 From: Cory Benfield Date: Fri, 12 Sep 2025 14:40:17 +0100 Subject: [PATCH 2/2] Formatting --- Sources/NIOCore/ByteBuffer-aux.swift | 20 +++++++++++++++----- Sources/NIOCore/ByteBuffer-core.swift | 21 ++++++++++++++++----- Sources/NIOCore/ByteBuffer-views.swift | 8 ++++++-- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/Sources/NIOCore/ByteBuffer-aux.swift b/Sources/NIOCore/ByteBuffer-aux.swift index e6ead593b2..69db561b2f 100644 --- a/Sources/NIOCore/ByteBuffer-aux.swift +++ b/Sources/NIOCore/ByteBuffer-aux.swift @@ -426,8 +426,12 @@ extension ByteBuffer { /// - Returns: The number of bytes read. @discardableResult @inlinable - public mutating func readWithUnsafeReadableBytes(_ body: (UnsafeRawBufferPointer) throws(ErrorType) -> Int) throws(ErrorType) -> Int { - let bytesRead = try self.withUnsafeReadableBytes({ (ptr: UnsafeRawBufferPointer) throws(ErrorType) -> Int in try body(ptr) }) + public mutating func readWithUnsafeReadableBytes( + _ body: (UnsafeRawBufferPointer) throws(ErrorType) -> Int + ) throws(ErrorType) -> Int { + let bytesRead = try self.withUnsafeReadableBytes({ (ptr: UnsafeRawBufferPointer) throws(ErrorType) -> Int in + try body(ptr) + }) self._moveReaderIndex(forwardBy: bytesRead) return bytesRead } @@ -445,7 +449,9 @@ extension ByteBuffer { public mutating func readWithUnsafeMutableReadableBytes( _ body: (UnsafeMutableRawBufferPointer) throws(ErrorType) -> Int ) throws(ErrorType) -> Int { - let bytesRead = try self.withUnsafeMutableReadableBytes({ (ptr: UnsafeMutableRawBufferPointer) throws(ErrorType) -> Int in try body(ptr) }) + let bytesRead = try self.withUnsafeMutableReadableBytes({ + (ptr: UnsafeMutableRawBufferPointer) throws(ErrorType) -> Int in try body(ptr) + }) self._moveReaderIndex(forwardBy: bytesRead) return bytesRead } @@ -622,7 +628,9 @@ extension ByteBuffer { public mutating func readWithUnsafeMutableReadableBytes( _ body: (UnsafeMutableRawBufferPointer) throws(ErrorType) -> (Int, T) ) throws(ErrorType) -> T { - let (bytesRead, ret) = try self.withUnsafeMutableReadableBytes({ (ptr: UnsafeMutableRawBufferPointer) throws(ErrorType) -> (Int, T) in try body(ptr) }) + let (bytesRead, ret) = try self.withUnsafeMutableReadableBytes({ + (ptr: UnsafeMutableRawBufferPointer) throws(ErrorType) -> (Int, T) in try body(ptr) + }) self._moveReaderIndex(forwardBy: bytesRead) return ret } @@ -639,7 +647,9 @@ extension ByteBuffer { public mutating func readWithUnsafeReadableBytes( _ body: (UnsafeRawBufferPointer) throws(ErrorType) -> (Int, T) ) throws(ErrorType) -> T { - let (bytesRead, ret) = try self.withUnsafeReadableBytes({ (ptr: UnsafeRawBufferPointer) throws(ErrorType) -> (Int, T) in try body(ptr) }) + let (bytesRead, ret) = try self.withUnsafeReadableBytes({ + (ptr: UnsafeRawBufferPointer) throws(ErrorType) -> (Int, T) in try body(ptr) + }) self._moveReaderIndex(forwardBy: bytesRead) return ret } diff --git a/Sources/NIOCore/ByteBuffer-core.swift b/Sources/NIOCore/ByteBuffer-core.swift index e568241c64..ce434877e7 100644 --- a/Sources/NIOCore/ByteBuffer-core.swift +++ b/Sources/NIOCore/ByteBuffer-core.swift @@ -726,7 +726,9 @@ public struct ByteBuffer { if minimumWritableBytes > 0 { self.reserveCapacity(minimumWritableBytes: minimumWritableBytes) } - let bytesWritten = try self.withUnsafeMutableWritableBytes({ (ptr: UnsafeMutableRawBufferPointer) throws(ErrorType) -> Int in try body(ptr) }) + let bytesWritten = try self.withUnsafeMutableWritableBytes({ + (ptr: UnsafeMutableRawBufferPointer) throws(ErrorType) -> Int in try body(ptr) + }) self._moveWriterIndex(to: self._writerIndex + _toIndex(bytesWritten)) return bytesWritten } @@ -742,7 +744,10 @@ public struct ByteBuffer { public mutating func writeWithUnsafeMutableBytes( _ body: (UnsafeMutableRawBufferPointer) throws(ErrorType) -> Int ) throws(ErrorType) -> Int { - try self.writeWithUnsafeMutableBytes(minimumWritableBytes: 0, { (ptr: UnsafeMutableRawBufferPointer) throws(ErrorType) -> Int in try body(ptr) }) + try self.writeWithUnsafeMutableBytes( + minimumWritableBytes: 0, + { (ptr: UnsafeMutableRawBufferPointer) throws(ErrorType) -> Int in try body(ptr) } + ) } /// This vends a pointer to the storage of the `ByteBuffer`. It's marked as _very unsafe_ because it might contain @@ -750,7 +755,9 @@ public struct ByteBuffer { /// /// - warning: Do not escape the pointer from the closure for later use. @inlinable - public func withVeryUnsafeBytes(_ body: (UnsafeRawBufferPointer) throws(ErrorType) -> T) throws(ErrorType) -> T { + public func withVeryUnsafeBytes( + _ body: (UnsafeRawBufferPointer) throws(ErrorType) -> T + ) throws(ErrorType) -> T { try body(.init(self._slicedStorageBuffer)) } @@ -774,7 +781,9 @@ public struct ByteBuffer { /// - body: The closure that will accept the yielded bytes. /// - Returns: The value returned by `body`. @inlinable - public func withUnsafeReadableBytes(_ body: (UnsafeRawBufferPointer) throws(ErrorType) -> T) throws(ErrorType) -> T { + public func withUnsafeReadableBytes( + _ body: (UnsafeRawBufferPointer) throws(ErrorType) -> T + ) throws(ErrorType) -> T { // This is safe, writerIndex >= readerIndex let range = Range(uncheckedBounds: (lower: self.readerIndex, upper: self.writerIndex)) return try body(.init(rebasing: self._slicedStorageBuffer[range])) @@ -1257,7 +1266,9 @@ extension ByteBuffer { /// - body: The modification operation to execute, with this `ByteBuffer` passed `inout` as an argument. /// - Returns: The return value of `body`. @inlinable - public mutating func modifyIfUniquelyOwned(_ body: (inout ByteBuffer) throws(ErrorType) -> T) throws(ErrorType) -> T? { + public mutating func modifyIfUniquelyOwned( + _ body: (inout ByteBuffer) throws(ErrorType) -> T + ) throws(ErrorType) -> T? { if isKnownUniquelyReferenced(&self._storage) { return try body(&self) } else { diff --git a/Sources/NIOCore/ByteBuffer-views.swift b/Sources/NIOCore/ByteBuffer-views.swift index a7b6cefc06..b9ea5eee20 100644 --- a/Sources/NIOCore/ByteBuffer-views.swift +++ b/Sources/NIOCore/ByteBuffer-views.swift @@ -38,7 +38,9 @@ public struct ByteBufferView: RandomAccessCollection, Sendable { } @inlinable - public func withUnsafeBytes(_ body: (UnsafeRawBufferPointer) throws(ErrorType) -> R) throws(ErrorType) -> R { + public func withUnsafeBytes( + _ body: (UnsafeRawBufferPointer) throws(ErrorType) -> R + ) throws(ErrorType) -> R { try self._buffer.withVeryUnsafeBytes { (ptr: UnsafeRawBufferPointer) throws(ErrorType) -> R in try body( UnsafeRawBufferPointer( @@ -98,7 +100,9 @@ public struct ByteBufferView: RandomAccessCollection, Sendable { } @inlinable - public func withContiguousStorageIfAvailable(_ body: (UnsafeBufferPointer) throws(ErrorType) -> R) throws(ErrorType) -> R? { + public func withContiguousStorageIfAvailable( + _ body: (UnsafeBufferPointer) throws(ErrorType) -> R + ) throws(ErrorType) -> R? { try self.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) throws(ErrorType) -> R in try body(bytes.bindMemory(to: UInt8.self)) }