use super::funejson::Value; const DIGITS: &[u8; 16] = b"0123456789abcdef"; /// Bytes as lowercase hexadecimal, two digits per byte. /// /// Bytes are a list of integers 0-255 across the registry (there is no bytes /// type), so a value outside that range is refused rather than masked to a /// byte: 256 quietly becoming 0 would change key material without a trace. /// /// # Panics /// Panics if any value is outside 0-255. pub fn hex_encode(bytes: &[i64]) -> String { let mut out = String::with_capacity(bytes.len() * 2); for &b in bytes { if !(0..=255).contains(&b) { panic!("bytes must be a list of integers from 0 to 255"); } out.push(DIGITS[(b >> 4) as usize] as char); out.push(DIGITS[(b & 15) as usize] as char); } out } /// A JSON list of byte values, refusing what the other languages refuse (a /// fraction, a string, a boolean) with the same words instead of letting /// `as_i64` turn it into a number. fn bytes_from_value(value: &Value, name: &str) -> Vec { match value { Value::Arr(items) => items .iter() .map(|item| match item { Value::Int(i) => *i, _ => panic!("{} must be a list of integers from 0 to 255", name), }) .collect(), _ => panic!("{} must be a list of integers from 0 to 255", name), } } pub fn fune_vector(args: &[Value]) -> Value { Value::str(&hex_encode(&bytes_from_value(&args[0], "bytes"))) }