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

Code before:
    func hexDumpShort() -> String {
        var hexString = ""
        hexString.reserveCapacity(self.readableBytes*3)

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

        return String(hexString.dropLast())
    }

    /// Return a `String` of hexadecimal digits of bytes in the Buffer.,
    /// in a format that's compatible with `xxd -r -p`, but clips the output to the max length of `limit` bytes.
    /// If the dump contains more than the `limit` bytes, this function will return the first `limit/2`
    /// and the last `limit/2` of that, replacing the rest with `...`, i.e. `01 02 03 ... 09 11 12`.
    ///
    /// - parameters:
    ///     - limit: The maximum amount of bytes presented in the dump.
    func hexDumpShort(limit: Int) -> String {
        // If the length of the resulting hex dump is smaller than the maximum allowed dump length,
        // return the full dump. Otherwise, dump the first and last pieces of the buffer, then concatenate them.
        if readableBytes <= limit {
            return self.hexDumpShort()
        } else {
            let startHex = self.getSlice(at: 0, length: limit/2)!.hexDumpShort()
            let endHex  = self.getSlice(at: self.readableBytes - limit/2, length: limit/2)!.hexDumpShort()
            return startHex + " ... " + endHex
        }
    }

    /// Returns a `String` of hexadecimal digits of bytes in the Buffer,
    /// with formatting compatible with output of `hexdump -C`.
    func hexDumpLong() -> String {
        var result = ""

        var buffer = self
        var lineOffset = 0

        while buffer.readableBytes > 0 {
            let slice = buffer.readSlice(length: min(16, buffer.readableBytes))!
            let lineLength = slice.readableBytes

            result += "\(String(byte: lineOffset, padding: 8))  "

            // Start with a xxd-format hexdump that we already have, then pad it
            // and insert a space in the middle.
            var lineHex = slice.hexDumpShort()
            lineHex.append(String(repeating: " ", count: 49 - lineHex.count))
            lineHex.insert(" ", at: lineHex.index(lineHex.startIndex, offsetBy: 24))
            result += lineHex


Review comment (suggestion):
This start index isn't right here; the reader index isn't guaranteed to be at zero. This should be `readerIndex` instead. However, we can avoid using `getSlice`  at all here (and having to manually specify indexes):

```swift
var buffer = self
let front = buffer.readSlice(length: limit / 2)!
buffer.moveReaderIndex(forwardBy: buffer.readableBytes - limit / 2)
let back = buffer.readSlice(length: buffer.readableBytes)!
let startHex = front.hexDumpShort()
let endHex = back.hexDumpShort() 
// ...
```

Code after:
        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())
    }

    /// Return a `String` of space delimited hexadecimal digits of the readable bytes in the buffer,
    /// in a format that's compatible with `xxd -r -p`, but clips the output to the max length of `maxBytes` bytes.
    /// If the dump contains more than the `maxBytes` bytes, this function will return the first `maxBytes/2`
    /// and the last `maxBytes/2` of that, replacing the rest with `...`, i.e. `01 02 03 ... 09 11 12`.
    ///
    /// - parameters:
    ///     - maxBytes: The maximum amount of bytes presented in the dump.
    private func hexDumpPlain(maxBytes: Int) -> String {