nandi/rustnimpublic Fork 0
8354895601e0a0fa3e1962b9ef728d00050ffb97
Commits
Clone
git clone https://git.rickub.com/nandi/rustnim.git
git clone ssh://git@rickub.com/nandi/rustnim.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Add display.rs and the alloc half: all of base16ct now goes through afb2a6e · on 8354895601e0a0fa3e1962b9ef728d00050ffb97 · nandithebull · 18h ago
main.rs · 128 lines · 4.1 KBRust Blame HistoryRaw
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//@ args: run
//@ cfg: feature=alloc
// base16ct 1.0.0, transpiled as a multi-file crate.
//
// `error.rs`, `lower.rs`, `upper.rs`, `mixed.rs` and `display.rs` are the
// crate's own files, byte-for-byte.
// This file carries `lib.rs`'s core -- `decoded_len`, `encoded_len` and
// `decode_inner` verbatim -- plus a driver, because the runner needs a `main`.
// The `alloc`-gated items are on, via `--cfg feature=alloc`.

mod display;
mod error;
mod lower;
mod mixed;
mod upper;

// `lib.rs` re-exports these from `alloc` for its modules to `use crate::..`;
// this crate root stands in for it.
#[cfg(feature = "alloc")]
pub use std::{string::String, vec::Vec};

pub use crate::display::HexDisplay;
pub use crate::error::{Error, Result};

/// Compute decoded length of the given hex-encoded input.
#[inline(always)]
pub fn decoded_len(bytes: &[u8]) -> Result<usize> {
    if bytes.len() & 1 == 0 {
        Ok(bytes.len() / 2)
    } else {
        Err(Error::InvalidLength)
    }
}

/// Get the length of Base16 (hex) produced by encoding the given bytes.
#[inline(always)]
pub fn encoded_len(bytes: &[u8]) -> usize {
    bytes.len() * 2
}

fn decode_inner<'a>(
    src: &[u8],
    dst: &'a mut [u8],
    decode_nibble: impl Fn(u8) -> u16,
) -> Result<&'a [u8]> {
    let dst = dst
        .get_mut(..decoded_len(src)?)
        .ok_or(Error::InvalidLength)?;

    let mut err: u16 = 0;
    for (src, dst) in src.chunks_exact(2).zip(dst.iter_mut()) {
        let byte = (decode_nibble(src[0]) << 4) | decode_nibble(src[1]);
        err |= byte >> 8;
        *dst = byte as u8;
    }

    match err {
        0 => Ok(dst),
        _ => Err(Error::InvalidEncoding),
    }
}

fn show(tag: &str, r: Result<&[u8]>) {
    match r {
        Ok(v) => {
            print!("{} ok ", tag);
            for b in v.iter() {
                print!("{:02x}", b);
            }
            println!(" len={}", v.len());
        }
        Err(e) => println!("{} err {:?} / {}", tag, e, e),
    }
}

fn main() {
    let mut buf = [0u8; 16];

    show("lower", lower::decode(b"abcd1234", &mut buf));
    show("mixed-l", mixed::decode(b"abcd1234", &mut buf));
    show("mixed-u", mixed::decode(b"ABCD1234", &mut buf));
    show("mixed-m", mixed::decode(b"abCD1234", &mut buf));
    show("edge", mixed::decode(b"00ff7f80", &mut buf));
    show("oddlen", mixed::decode(b"abc", &mut buf));
    show("bad", mixed::decode(b"zzzz", &mut buf));
    show("empty", mixed::decode(b"", &mut buf));

    let mut small = [0u8; 2];
    show("short-dst", mixed::decode(b"abcd1234", &mut small));

    show("upper", upper::decode(b"ABCD1234", &mut buf));
    show("upper-rej", upper::decode(b"abcd1234", &mut buf));

    let mut enc = [0u8; 8];
    show("encode", lower::encode(b"\xab\xcd\x12\x34", &mut enc));
    let mut encu = [0u8; 8];
    show("encode-up", upper::encode(b"\xab\xcd\x12\x34", &mut encu));

    // `encode_str` is a closure over an `unsafe` block returning a borrowed
    // `&str` -- a view of the bytes just written, not a copy.
    let mut enc2 = [0u8; 8];
    match lower::encode_str(b"\xab\xcd\x12\x34", &mut enc2) {
        Ok(s) => println!("encode_str ok {} len={}", s, s.len()),
        Err(e) => println!("encode_str err {:?}", e),
    }
    let mut tiny = [0u8; 2];
    match lower::encode_str(b"\xab\xcd", &mut tiny) {
        Ok(s) => println!("tiny ok {}", s),
        Err(e) => println!("tiny err {:?} / {}", e, e),
    }

    println!("{} {}", decoded_len(b"abcd").unwrap(), encoded_len(b"\xab\xcd"));

    // The `alloc` half: `decode_vec` and `encode_string`.
    println!("{:?}", lower::decode_vec(b"abcd1234"));
    println!("{:?}", lower::decode_vec(b"abc"));
    println!("{:?}", mixed::decode_vec(b"ABcd1234"));
    println!("{}", lower::encode_string(b"\xab\xcd\x12\x34"));
    println!("{}", upper::encode_string(b"\xab\xcd\x12\x34"));
    println!("[{}]", lower::encode_string(b""));

    // `HexDisplay` is a tuple struct holding a borrowed slice, and its
    // `UpperHex`/`LowerHex` impls write once per byte into the formatter.
    let raw = b"\xab\xcd\x12\x34";
    println!("{}", HexDisplay(raw));
    println!("{:X} {:x}", HexDisplay(raw), HexDisplay(raw));
    println!("{}", HexDisplay(b""));
}