Repository: apple/swift-nio
File: Sources/NIOCore/ByteBuffer-aux.swift (Swift)

Code before:

    /// Read `length` bytes off this `ByteBuffer`, move the reader index forward by `length` bytes and return the result
    /// as `[UInt8]`.
    ///
    /// - Parameters:
    ///   - length: The number of bytes to be read from this `ByteBuffer`.
    /// - Returns: A `[UInt8]` value containing `length` bytes or `nil` if there aren't at least `length` bytes readable.
    @inlinable
    public mutating func readBytes(length: Int) -> [UInt8]? {
        guard let result = self.getBytes(at: self.readerIndex, length: length) else {
            return nil
        }
        self._moveReaderIndex(forwardBy: length)
        return result
    }

    #if compiler(>=6.2) && !canImport(Darwin)
    @inlinable
    public mutating func readInlineArray<
        let count: Int,
        IntegerType: FixedWidthInteger
    >(
        endianness: Endianness = .big,
        as: InlineArray<count, IntegerType>.Type = InlineArray<count, IntegerType>.self
    ) -> InlineArray<count, IntegerType>? {
        let length = MemoryLayout<IntegerType>.size
        let bytesRequired = length &* count

        guard self.readableBytes >= bytesRequired else {
            return nil
        }

        return self.readWithUnsafeReadableBytes {
            ptr -> (Int, InlineArray<count, IntegerType>) in
            assert(ptr.count >= bytesRequired)
            let values: InlineArray<count, IntegerType> = InlineArray { index in
                switch endianness {
                case .big:
                    return IntegerType(
                        bigEndian: ptr.load(
                            fromByteOffset: index &* length,
                            as: IntegerType.self
                        )
                    )
                case .little:
                    return IntegerType(
                        littleEndian: ptr.load(
                            fromByteOffset: index &* length,
                            as: IntegerType.self
                        )
                    )

Review comment (suggestion):
An interesting question here is whether we want to support integer types where `stride` and `size` don't match, and what it should imply.

Code after:

    /// Read `length` bytes off this `ByteBuffer`, move the reader index forward by `length` bytes and return the result
    /// as `[UInt8]`.
    ///
    /// - Parameters:
    ///   - length: The number of bytes to be read from this `ByteBuffer`.
    /// - Returns: A `[UInt8]` value containing `length` bytes or `nil` if there aren't at least `length` bytes readable.
    @inlinable
    public mutating func readBytes(length: Int) -> [UInt8]? {
        guard let result = self.getBytes(at: self.readerIndex, length: length) else {
            return nil
        }
        self._moveReaderIndex(forwardBy: length)
        return result
    }

    #if compiler(>=6.2)
    @inlinable
    @available(macOS 26, iOS 26, tvOS 26, watchOS 26, visionOS 26, *)
    public mutating func readInlineArray<
        let count: Int,
        IntegerType: FixedWidthInteger
    >(
        endianness: Endianness = .big,
        as: InlineArray<count, IntegerType>.Type = InlineArray<count, IntegerType>.self
    ) -> InlineArray<count, IntegerType>? {
        // use stride to account for padding bytes
        let stride = MemoryLayout<IntegerType>.stride
        let bytesRequired = stride * count

        guard self.readableBytes >= bytesRequired else {
            return nil
        }

        let inlineArray = InlineArray<count, IntegerType> { (outputSpan: inout OutputSpan<IntegerType>) in
            for index in 0..<count {
                // already made sure of 'self.readableBytes >= bytesRequired' above,
                // so this is safe to force-unwrap as it's guaranteed to exist
                let integer = self.getInteger(
                    // this is less than 'bytesRequired' so is safe to multiply
                    at: stride &* index,
                    endianness: endianness,
                    as: IntegerType.self
                )!
                outputSpan.append(integer)
            }
        }
        // already made sure of 'self.readableBytes >= bytesRequired' above
        self._moveReaderIndex(forwardBy: bytesRequired)
        return inlineArray
    }