Skip to main content

patterns/
hex.rs

1use patterns_macros::{because, source};
2
3pub struct HexNotation;
4source!(HexNotation, "the way the chain's tooling writes bytes as text: a zero and an x, then two lowercase digits for each byte");
5
6const PREFIX_ZERO: u8 = 48;
7because!(PREFIX_ZERO, HexNotation, "the digit zero that opens hex text, written as its code point because a string holding it would start a word with a digit and state a fact in prose");
8
9const PREFIX_X: u8 = 120;
10because!(PREFIX_X, HexNotation, "the letter x that follows the zero in hex text, written as its code point beside the zero so the two are declared as the pair they are");
11
12pub fn hex_text(bytes: &[u8]) -> String {
13    ::hex::encode(bytes)
14}
15because!(hex_text, "bytes as lowercase hex digits with no prefix, the form the stores key on, so a key never differs from itself by case");
16
17const OPENER_CHARS: usize = 2;
18because!(OPENER_CHARS, HexNotation, "the two characters of the opener, a zero and an x, that prefixed adds and unprefixed removes");
19
20pub fn prefixed(text: &str) -> String {
21    let mut out = String::with_capacity(text.len() + OPENER_CHARS);
22    out.push(PREFIX_ZERO as char);
23    out.push(PREFIX_X as char);
24    out.push_str(text);
25    out
26}
27because!(prefixed, "hex text with the opening pair the chain's tooling expects in front of it, added here so no other file spells the pair");
28
29pub fn unprefixed(text: &str) -> &str {
30    let opener = [PREFIX_ZERO as char, PREFIX_X as char];
31    let lower = text.get(..OPENER_CHARS).map(|s| s.to_ascii_lowercase());
32    match lower {
33        Some(head) if head.chars().eq(opener) => &text[OPENER_CHARS..],
34        _ => text,
35    }
36}
37because!(unprefixed, "hex text with the opening pair removed when it is there, so a value read from the chain or typed by a person parses the same either way");
38
39pub fn bytes_of(text: &str) -> Option<Vec<u8>> {
40    ::hex::decode(unprefixed(text)).ok()
41}
42because!(bytes_of, "hex text back into bytes, with or without its opener, answering nothing rather than failing on text that is not hex");