Skip to content

Commit

Permalink
Adds Int(buffer:) initializer to FixedWidthInteger types (#3047)
Browse files Browse the repository at this point in the history
### Motivation:

Makes it possible to make integers out of ByteBuffers directly with an
initializer. I.e. `UInt32(buffer: ByteBuffer(bytes: [0, 1, 2, 3]))`.
Closes #3012.

### Modifications:

- Adds the `Int(buffer:)` initializer in `ByteBuffer-int.swift`
- Adds tests in `ByteBufferTest.swift`. _Holy hell this file is huge._
- Note that `Int(buffer:)` will crash if the buffer does not have enough
bytes in it to represent the desired integer type.
- It also does _not_ expose endianness and uses `Endianness.host`, to
keep the public API clean and simple. It's a convenience initializer, so
I thought keeping it minimal is a good idea.

### Result:

Nicer direct initializer for integers from ByteBuffers.

---------

Co-authored-by: Johannes Weiss <[email protected]>
Co-authored-by: Cory Benfield <[email protected]>
  • Loading branch information
3 people authored Jan 17, 2025
1 parent 8536193 commit 456ca25
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 0 deletions.
16 changes: 16 additions & 0 deletions Sources/NIOCore/ByteBuffer-int.swift
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ extension ByteBuffer {
}

extension FixedWidthInteger {

/// Returns the next power of two.
@inlinable
func nextPowerOf2() -> Self {
Expand All @@ -134,6 +135,21 @@ extension FixedWidthInteger {

return 1 << ((Self.bitWidth - 1) - self.leadingZeroBitCount)
}

/// Initialize an integer from a byte buffer of exactly the right size.
/// The bytes will be read using the host system's endianness.
///
/// - Parameters:
/// - buffer: The ByteBuffer to read from
/// - endianness: The endianness to use when reading the integer, defaults to the host system's endianness.
@inlinable
public init?(buffer: ByteBuffer, endianness: Endianness = .host) {
var buffer = buffer
guard let value = buffer.readInteger(endianness: endianness, as: Self.self), buffer.readableBytes == 0 else {
return nil
}
self = value
}
}

extension UInt32 {
Expand Down
23 changes: 23 additions & 0 deletions Tests/NIOCoreTests/ByteBufferTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3499,6 +3499,29 @@ extension ByteBufferTest {

}

// MARK: - Int / FixedWidthInteger init
extension ByteBufferTest {
func testCreateIntegersFromByteBuffer() {
let uint32BufferLE = ByteBuffer(bytes: [0x04, 0x03, 0x02, 0x01])
let uint32BufferBE = ByteBuffer(bytes: [0x01, 0x02, 0x03, 0x04])
let tooSmallInt32Buffer = ByteBuffer(bytes: [0x01, 0x02, 0x03])

XCTAssertEqual(Int32(buffer: uint32BufferLE, endianness: .little), 0x0102_0304)
XCTAssertEqual(Int32(buffer: uint32BufferBE, endianness: .big), 0x0102_0304)
XCTAssertNil(Int32(buffer: tooSmallInt32Buffer))

let uint64BufferLE = ByteBuffer(bytes: [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01])
let uint64BufferBE = ByteBuffer(bytes: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08])
let tooSmallInt64Buffer = ByteBuffer(bytes: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07])
let tooBigInt64Buffer = ByteBuffer(bytes: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09])

XCTAssertEqual(Int64(buffer: uint64BufferLE, endianness: .little), 0x0102_0304_0506_0708)
XCTAssertEqual(Int64(buffer: uint64BufferBE, endianness: .big), 0x0102_0304_0506_0708)
XCTAssertNil(Int64(buffer: tooSmallInt64Buffer))
XCTAssertNil(Int64(buffer: tooBigInt64Buffer))
}
}

// MARK: - DispatchData init
extension ByteBufferTest {

Expand Down

0 comments on commit 456ca25

Please sign in to comment.