Functional Weave
Code in Python

encoding.hex@1.0.0

impl/rust/hex_decode.rs

1,343 bytes · the Rust implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one

fn digit_value(b: u8) -> i64 {
    match b {
        b'0'..=b'9' => (b - b'0') as i64,
        b'a'..=b'f' => (b - b'a' + 10) as i64,
        b'A'..=b'F' => (b - b'A' + 10) as i64,
        _ => -1,
    }
}

/// Hexadecimal text back to bytes, either case, strictly.
///
/// A 0x prefix, whitespace or an odd digit count is an error, not skipped.
/// Characters are checked before the length, so the answer for non-ASCII
/// input does not depend on how a language counts its length.
///
/// # Panics
/// Panics on any character that is not a hex digit, or an odd digit count.
pub fn hex_decode(text: &str) -> Vec<i64> {
    let mut digits = Vec::with_capacity(text.len());
    for &b in text.as_bytes() {
        let d = digit_value(b);
        if d < 0 {
            panic!("hex text may only contain the digits 0-9, a-f and A-F");
        }
        digits.push(d);
    }
    if digits.len() % 2 != 0 {
        panic!("hex text must have an even number of digits, received {}", digits.len());
    }
    digits.chunks(2).map(|pair| pair[0] * 16 + pair[1]).collect()
}

pub fn fune_vector(args: &[Value]) -> Value {
    let text = match &args[0] {
        Value::Str(s) => s.as_str(),
        _ => panic!("hex text must be a string"),
    };
    Value::Arr(hex_decode(text).into_iter().map(Value::Int).collect())
}