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

Code before:
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

extension ByteBuffer {

    /// Describes a ByteBuffer hexDump format.
    /// Can be either xxd output compatible, or hexdump compatible.
    public struct HexDumpFormat {
        enum Value {
            case xxdCompatible(maxLength: Int? = nil)
            case hexDumpCompatible(maxLength: Int? = nil)
        }

        var value: Value
        init(_ value: Value) { self.value = value }

        /// A hex dump format compatible with `xxd` CLI utility.
        public static let xxdCompatible = Self(.xxdCompatible(maxLength: nil))

        /// A hex dump format compatible with `hexdump` command line utility.
        public static let hexDumpCompatible = Self(.hexDumpCompatible(maxLength: nil))

        /// A hex dump format compatible with `xxd`, clipped to `maxLength` bytes dumped.
        /// This format will dump first maxLength / 2 bytes, and the last maxLength / 2 bytes, replacing the rest with " ... ".
        public static func xxdCompatible(maxLength: Int) -> Self {
            Self(.xxdCompatible(maxLength: maxLength))
        }

        /// A hex dump format compatible with `hexdump` command line tool.
        /// This format will dump first maxLength / 2 bytes, and the last maxLength / 2 bytes, with a placeholder in between.
        public static func hexDumpCompatible(maxLength: Int) -> Self {
            Self(.hexDumpCompatible(maxLength: maxLength))
        }
    }

    /// Return a `String` of hexadecimal digits of bytes in the Buffer,
    /// in a format that's compatible with `xxd -r -p`.
    /// `hexDumpShort()` always dumps all readable bytes, i.e. from `readerIndex` to `writerIndex`,
    /// so you should set those indices to desired location to get the offset and length that you need to dump.
    func hexDumpShort() -> String {
        var hexString = ""
        hexString.reserveCapacity(self.readableBytes * 3)

        for byte in self.readableBytesView {
            hexString += String(byte: byte, padding: 2)
            hexString += " "
        }

        return String(hexString.dropLast())
    }

Review comment (suggestion):
I think we should use `maxBytes` instead of `maxLength`;  you could mistake length for being the length of the output. 

Code after:
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

extension ByteBuffer {

    /// Describes a ByteBuffer hexDump format.
    /// Can be either xxd output compatible, or hexdump compatible.
    public struct HexDumpFormat: Hashable, Sendable {

        enum Value: Hashable {
            case plain(maxBytes: Int? = nil)
            case detailed(maxBytes: Int? = nil)
        }

        let value: Value
        init(_ value: Value) { self.value = value }

        /// A plain hex dump format compatible with `xxd` CLI utility.
        public static let plain = Self(.plain(maxBytes: nil))

        /// A hex dump format compatible with `hexdump` command line utility.
        public static let detailed = Self(.detailed(maxBytes: nil))

        /// A detailed hex dump format compatible with `xxd`, clipped to `maxBytes` bytes dumped.
        /// This format will dump first `maxBytes / 2` bytes, and the last `maxBytes / 2` bytes, replacing the rest with " ... ".
        public static func plain(maxBytes: Int) -> Self {
            Self(.plain(maxBytes: maxBytes))
        }

        /// A hex dump format compatible with `hexdump` command line tool.
        /// This format will dump first `maxBytes / 2` bytes, and the last `maxBytes / 2` bytes, with a placeholder in between.
        public static func detailed(maxBytes: Int) -> Self {
            Self(.detailed(maxBytes: maxBytes))
        }
    }

    /// Return a `String` of space separated hexadecimal digits of the readable bytes in the buffer,
    /// in a format that's compatible with `xxd -r -p`.
    /// `hexDumpPlain()` always dumps all readable bytes, i.e. from `readerIndex` to `writerIndex`,
    /// so you should set those indices to desired location to get the offset and length that you need to dump.
    private func hexDumpPlain() -> String {
        var hexString = ""
        hexString.reserveCapacity(self.readableBytes * 3)

        for byte in self.readableBytesView {
            hexString += String(byte, radix: 16, padding: 2)
            hexString += " "
        }

        return String(hexString.dropLast())