diff --git a/Sources/NIOCore/ByteBuffer-int.swift b/Sources/NIOCore/ByteBuffer-int.swift index 87e0c9abb5..6cb5eba7d9 100644 --- a/Sources/NIOCore/ByteBuffer-int.swift +++ b/Sources/NIOCore/ByteBuffer-int.swift @@ -116,6 +116,7 @@ extension ByteBuffer { } extension FixedWidthInteger { + /// Returns the next power of two. @inlinable func nextPowerOf2() -> Self { @@ -134,6 +135,23 @@ 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. + /// + /// - Returns: The integer value read from the buffer, or nil if the buffer size did not match the integer type. + @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 { diff --git a/Tests/NIOCoreTests/ByteBufferTest.swift b/Tests/NIOCoreTests/ByteBufferTest.swift index 6be0ce37a6..91e0ac0df0 100644 --- a/Tests/NIOCoreTests/ByteBufferTest.swift +++ b/Tests/NIOCoreTests/ByteBufferTest.swift @@ -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 {