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

Code before:

        case .compact(let maxBytes):
            if let maxBytes = maxBytes {
                return self.hexDumpCompact(maxBytes: maxBytes)
            } else {
                return self.hexDumpCompact()
            }

        case .detailed(let maxBytes):
            if let maxBytes = maxBytes {
                return self.hexDumpDetailed(maxBytes: maxBytes)
            } else {
                return self.hexdumpDetailed()
            }
        }
    }
}

enum HexDecodingError: Error {
    case invalidHexLength
    case invalidCharacter
}

extension UInt8 {
    fileprivate var isASCIIWhitespace: Bool {
        [UInt8(ascii: "\n"), UInt8(ascii: "\t"), UInt8(ascii: "\n"), UInt8(ascii: "\r"), UInt8(ascii: " ")].contains(
            self
        )
    }

    fileprivate var asciiHexNibble: UInt8? {
        get throws {
            switch self {
            case UInt8(ascii: "0")...UInt8(ascii: "9"):
                return self - UInt8(ascii: "0")
            case UInt8(ascii: "a")...UInt8(ascii: "f"):
                return self - UInt8(ascii: "a") + 10
            case UInt8(ascii: "A")...UInt8(ascii: "F"):
                return self - UInt8(ascii: "A") + 10
            default:
                throw HexDecodingError.invalidCharacter
            }
        }
    }
}

extension Substring.UTF8View {
    @usableFromInline
    mutating func popNextHexByte() throws -> UInt8? {
        while let nextByte = self.first, nextByte.isASCIIWhitespace {
            self = self.dropFirst()

Review comment (refactor):
We don't need the duplicate.

```suggestion
        [UInt8(ascii: "\t"), UInt8(ascii: "\n"), UInt8(ascii: "\r"), UInt8(ascii: " ")].contains(
```

Code after:

        case .compact(let maxBytes):
            if let maxBytes = maxBytes {
                return self.hexDumpCompact(maxBytes: maxBytes)
            } else {
                return self.hexDumpCompact()
            }

        case .detailed(let maxBytes):
            if let maxBytes = maxBytes {
                return self.hexDumpDetailed(maxBytes: maxBytes)
            } else {
                return self.hexdumpDetailed()
            }
        }
    }

    /// An error that is thrown when an invalid hex encoded string was attempted to be written to a ByteBuffer.
    public struct HexDecodingError: Error, Equatable {
        private let kind: HexDecodingErrorKind

        private enum HexDecodingErrorKind {
            /// The hex encoded string was not of the expected even length.
            case invalidHexLength
            /// An invalid hex character was found in the hex encoded string.
            case invalidCharacter
        }

        public static let invalidHexLength = HexDecodingError(kind: .invalidHexLength)
        public static let invalidCharacter = HexDecodingError(kind: .invalidCharacter)
    }
}

extension UInt8 {
    fileprivate var isASCIIWhitespace: Bool {
        [UInt8(ascii: "\n"), UInt8(ascii: "\t"), UInt8(ascii: "\r"), UInt8(ascii: " ")].contains(
            self
        )
    }

    fileprivate var asciiHexNibble: UInt8 {
        get throws {
            switch self {
            case UInt8(ascii: "0")...UInt8(ascii: "9"):
                return self - UInt8(ascii: "0")
            case UInt8(ascii: "a")...UInt8(ascii: "f"):
                return self - UInt8(ascii: "a") + 10
            case UInt8(ascii: "A")...UInt8(ascii: "F"):
                return self - UInt8(ascii: "A") + 10
            default:
                throw ByteBuffer.HexDecodingError.invalidCharacter