Skip to main content

aver/types/
byte.rs

1/// Byte namespace — byte-level operations on integers.
2///
3/// Byte is NOT a type — these are functions operating on Int (0–255).
4/// Same pattern as Char: namespace of operations on existing types.
5///
6/// Methods:
7///   Byte.toHex(n: Int)        → Result<String, String>  — byte to 2-char lowercase hex
8///   Byte.fromHex(s: String)   → Result<Int, String>     — 2-char hex to byte
9///
10/// No effects required.
11use std::collections::HashMap;
12
13use crate::value::{RuntimeError, Value};
14
15pub fn register(global: &mut HashMap<String, Value>) {
16    let mut members = HashMap::new();
17    for method in &["toHex", "fromHex"] {
18        members.insert(
19            method.to_string(),
20            Value::Builtin(format!("Byte.{}", method)),
21        );
22    }
23    global.insert(
24        "Byte".to_string(),
25        Value::Namespace {
26            name: "Byte".to_string(),
27            members,
28        },
29    );
30}
31
32pub fn effects(_name: &str) -> &'static [&'static str] {
33    &[]
34}
35
36pub fn call(name: &str, args: &[Value]) -> Option<Result<Value, RuntimeError>> {
37    match name {
38        "Byte.toHex" => Some(to_hex(args)),
39        "Byte.fromHex" => Some(from_hex(args)),
40        _ => None,
41    }
42}
43
44// ─── Implementations ────────────────────────────────────────────────────────
45
46fn to_hex(args: &[Value]) -> Result<Value, RuntimeError> {
47    if args.len() != 1 {
48        return Err(RuntimeError::Error(format!(
49            "Byte.toHex() takes 1 argument, got {}",
50            args.len()
51        )));
52    }
53    let Value::Int(n) = &args[0] else {
54        return Err(RuntimeError::Error(
55            "Byte.toHex: argument must be an Int".to_string(),
56        ));
57    };
58    let n = *n;
59    if n < 0 || n > 255 {
60        return Ok(Value::Err(Box::new(Value::Str(format!(
61            "Byte.toHex: {} is out of range 0–255",
62            n
63        )))));
64    }
65    Ok(Value::Ok(Box::new(Value::Str(format!("{:02x}", n)))))
66}
67
68fn from_hex(args: &[Value]) -> Result<Value, RuntimeError> {
69    if args.len() != 1 {
70        return Err(RuntimeError::Error(format!(
71            "Byte.fromHex() takes 1 argument, got {}",
72            args.len()
73        )));
74    }
75    let Value::Str(s) = &args[0] else {
76        return Err(RuntimeError::Error(
77            "Byte.fromHex: argument must be a String".to_string(),
78        ));
79    };
80    if s.len() != 2 {
81        return Ok(Value::Err(Box::new(Value::Str(format!(
82            "Byte.fromHex: expected exactly 2 hex chars, got '{}'",
83            s
84        )))));
85    }
86    match u8::from_str_radix(s, 16) {
87        Ok(n) => Ok(Value::Ok(Box::new(Value::Int(n as i64)))),
88        Err(_) => Ok(Value::Err(Box::new(Value::Str(format!(
89            "Byte.fromHex: invalid hex '{}'",
90            s
91        ))))),
92    }
93}