hex
stdlib/extra/hex.hk: hexadecimal text for bytes.
The simpler of the two bytes-to-text codecs (base64 is the other): one byte becomes two characters, which leaves no grouping, no padding and no alphabet variant to choose. Rendering is lowercase, which is what a digest, a hash prefix and a hanki.lock.config.hk entry all print today; parsing is case-insensitive, since the same value arrives upper-cased from plenty of other tools.
Pure and whole-input: encode and decode are @encapsulated, and the builder each one writes into is allocated and finished inside the call with nothing mutable escaping. That leaves both callable from meta and from ordinary pure code, on both tiers. There is no streaming form.
_digits
_digits: string = "0123456789abcdef"
The lowercase digits, indexed by nibble value.
HexError
type HexError
BadDigit(int)
OddLength(int)
end
Why a hex string could not be decoded, with the byte offset at which the problem was found (the json.JsonError idiom).
encode
def encode(input: bytes) -> string
Render input as lowercase hexadecimal: two characters per byte, most significant nibble first. The empty input renders as the empty string.
encode("".to_bytes()) => ""
encode("f".to_bytes()) => "66"
encode("foo".to_bytes()) => "666f6f"
decode
def decode(text: string) -> Result<bytes, HexError>
Parse hexadecimal text back into bytes, accepting either case. An odd number of characters is OddLength and anything outside 0-9a-fA-F is BadDigit at its offset; there is no whitespace or separator tolerance, because a codec that skips characters unannounced cannot tell a formatting habit from a corrupted transfer.
decode("666f6f").unwrap_or("".to_bytes()).length => 3
decode("666F6F").unwrap_or("".to_bytes()).length => 3
decode("66g6").unwrap_or("".to_bytes()).length => 0
decode("666").unwrap_or("".to_bytes()).length => 0
_digit
def _digit(nibble: u8) -> string
The lowercase character for one nibble. A value above 15 cannot arrive, both callers masking, and yields "0" in place of a crash, which leaves this total.
_value
def _value(ch: u8) -> Option<u8>
The nibble value of one hex character, or None when it is not one. Arithmetic and no table lookup, which spares either case a scan.