Skip to main content

hara_native/
hta.rs

1use crate::core::{ResultValue, Value};
2use crate::lang::data::MapEntry as PMapEntry;
3#[cfg(test)]
4use crate::lang::data::{Tuple as PTuple, Vector as PVector};
5use crate::lang::protocol::INamespaced;
6use num_bigint::BigInt;
7use num_traits::ToPrimitive;
8
9const MAGIC: &[u8; 4] = b"HTA0";
10pub const MAX_FRAME_BYTES: usize = 64 * 1024 * 1024;
11pub const MAX_NESTING_DEPTH: usize = 256;
12const NIL: u8 = 0;
13const FALSE: u8 = 1;
14const TRUE: u8 = 2;
15const I64: u8 = 3;
16const STRING: u8 = 4;
17const BYTES: u8 = 5;
18const KEYWORD: u8 = 6;
19const SYMBOL: u8 = 7;
20const LIST: u8 = 8;
21const VECTOR: u8 = 9;
22const SET: u8 = 10;
23const MAP: u8 = 11;
24const HANDLE: u8 = 12;
25const NAMESPACE: u8 = 13;
26const VAR: u8 = 14;
27const F64: u8 = 15;
28const ATOM: u8 = 16;
29const ARRAY: u8 = 17;
30const OBJECT: u8 = 18;
31const CHARACTER: u8 = 19;
32const BIG_INTEGER: u8 = 20;
33const REGEX: u8 = 22;
34const TUPLE: u8 = 23;
35const CONS: u8 = 24;
36const QUEUE: u8 = 25;
37const ORDERED_MAP: u8 = 26;
38const SORTED_MAP: u8 = 27;
39const TRIE: u8 = 28;
40const ORDERED_SET: u8 = 29;
41const SORTED_SET: u8 = 30;
42const TAGGED: u8 = 31;
43const EXCEPTION_INFO: u8 = 32;
44const STRUCT: u8 = 33;
45const POINTER: u8 = 34;
46const VAR_REF: u8 = 35;
47const DEQUE: u8 = 36;
48const PRIORITY_MAP: u8 = 37;
49const MAP_ENTRY: u8 = 38;
50const RESULT_STRUCT_NAME: &str = "std.native/Result";
51const RESULT_STRUCT_FIELDS: [&str; 4] = ["status", "data", "error", "context"];
52
53/// The canonical HTA0 tag inventory. Every host codec must preserve these
54/// numeric assignments; omitted values are reserved for future revisions.
55pub const HTA0_TAG_INVENTORY: &[(u8, &str)] = &[
56    (NIL, "nil"),
57    (FALSE, "false"),
58    (TRUE, "true"),
59    (I64, "i64"),
60    (STRING, "string"),
61    (BYTES, "bytes"),
62    (KEYWORD, "keyword"),
63    (SYMBOL, "symbol"),
64    (LIST, "list"),
65    (VECTOR, "vector"),
66    (SET, "set"),
67    (MAP, "map"),
68    (HANDLE, "handle"),
69    (NAMESPACE, "namespace"),
70    (VAR, "legacy-var"),
71    (F64, "f64"),
72    (ATOM, "atom"),
73    (ARRAY, "array"),
74    (OBJECT, "object"),
75    (CHARACTER, "character"),
76    (BIG_INTEGER, "big-integer"),
77    (REGEX, "regex"),
78    (TUPLE, "tuple"),
79    (CONS, "cons"),
80    (QUEUE, "queue"),
81    (ORDERED_MAP, "ordered-map"),
82    (SORTED_MAP, "sorted-map"),
83    (TRIE, "trie"),
84    (ORDERED_SET, "ordered-set"),
85    (SORTED_SET, "sorted-set"),
86    (TAGGED, "tagged"),
87    (EXCEPTION_INFO, "exception-info"),
88    (STRUCT, "struct"),
89    (POINTER, "pointer"),
90    (VAR_REF, "var-ref"),
91    (DEQUE, "deque"),
92    (PRIORITY_MAP, "priority-map"),
93    (MAP_ENTRY, "map-entry"),
94];
95
96fn decode_exception_provenance(
97    value: Value,
98) -> Result<
99    (
100        Option<crate::core::ExceptionSite>,
101        Vec<crate::core::ExceptionSite>,
102    ),
103    String,
104> {
105    let entries = crate::core::map_entries(&value)
106        .ok_or_else(|| "hta/value-malformed: invalid exception provenance".to_string())?;
107    if entries.len() != 2 {
108        return Err("hta/value-malformed: invalid exception provenance fields".into());
109    }
110    let created = entries
111        .iter()
112        .find_map(|(key, value)| field_name(key, "ex/created-at").then_some(value))
113        .ok_or_else(|| "hta/value-malformed: missing exception creation provenance".to_string())?;
114    let throws = entries
115        .iter()
116        .find_map(|(key, value)| field_name(key, "ex/throws").then_some(value))
117        .ok_or_else(|| "hta/value-malformed: missing exception throw provenance".to_string())?;
118    let created = match created {
119        Value::Nil => None,
120        value => Some(decode_exception_site(value)?),
121    };
122    let Value::Vector(throws) = throws else {
123        return Err("hta/value-malformed: invalid exception throws provenance".into());
124    };
125    let throws = throws
126        .iter()
127        .map(decode_exception_site)
128        .collect::<Result<Vec<_>, _>>()?;
129    Ok((created, throws))
130}
131
132fn decode_exception_site(value: &Value) -> Result<crate::core::ExceptionSite, String> {
133    let entries = crate::core::map_entries(value)
134        .ok_or_else(|| "hta/value-malformed: invalid exception provenance site".to_string())?;
135    if entries.len() != 4 {
136        return Err("hta/value-malformed: invalid exception provenance site".into());
137    }
138    let get = |name: &str| {
139        entries
140            .iter()
141            .find_map(|(key, value)| field_name(key, name).then_some(value))
142    };
143    let namespace = match get("namespace") {
144        Some(Value::Nil) => None,
145        Some(Value::String(value)) => Some(value.clone()),
146        _ => return Err("hta/value-malformed: invalid exception provenance namespace".into()),
147    };
148    let resource = match get("resource") {
149        Some(Value::Nil) => None,
150        Some(Value::String(value)) => Some(value.clone()),
151        _ => return Err("hta/value-malformed: invalid exception provenance resource".into()),
152    };
153    let line = match get("line") {
154        Some(Value::Number(value)) if *value >= 0 => *value as usize,
155        _ => return Err("hta/value-malformed: invalid exception provenance line".into()),
156    };
157    let column = match get("column") {
158        Some(Value::Number(value)) if *value >= 0 => *value as usize,
159        _ => return Err("hta/value-malformed: invalid exception provenance column".into()),
160    };
161    Ok(crate::core::ExceptionSite {
162        namespace,
163        resource,
164        line,
165        column,
166    })
167}
168
169fn field_name(value: &Value, expected: &str) -> bool {
170    match value {
171        Value::Keyword(value) => value.as_str() == expected,
172        Value::String(value) => value == expected,
173        _ => false,
174    }
175}
176
177pub fn encode(value: &Value) -> Result<Vec<u8>, String> {
178    let mut output = MAGIC.to_vec();
179    encode_bare(value, &mut output, 0)?;
180    if output.len() > MAX_FRAME_BYTES {
181        return Err("hta/value-too-large: frame exceeds 64 MiB".into());
182    }
183    Ok(output)
184}
185
186pub fn decode(bytes: &[u8]) -> Result<Value, String> {
187    if bytes.len() > MAX_FRAME_BYTES {
188        return Err("hta/value-too-large: frame exceeds 64 MiB".into());
189    }
190    if !bytes.starts_with(MAGIC) {
191        return Err("hta/value-malformed: invalid HTA0 header".into());
192    }
193    let mut reader = Reader {
194        bytes,
195        cursor: MAGIC.len(),
196    };
197    let value = reader.value(0)?;
198    if reader.cursor != bytes.len() {
199        return Err("hta/value-malformed: trailing bytes".into());
200    }
201    Ok(value)
202}
203
204/// Decodes an HTA0 frame and verifies that its bytes are canonical.
205///
206/// The ordinary decoder is intentionally permissive for trusted legacy state;
207/// transport and artifact boundaries should use this entry point instead.
208pub fn decode_canonical(bytes: &[u8]) -> Result<Value, String> {
209    let value = decode(bytes)?;
210    let canonical = encode(&value)?;
211    if canonical != bytes {
212        return Err("hta/value-noncanonical: frame bytes are not canonical".into());
213    }
214    Ok(value)
215}
216
217fn encode_bare(value: &Value, output: &mut Vec<u8>, depth: usize) -> Result<(), String> {
218    if depth > MAX_NESTING_DEPTH {
219        return Err("hta/value-too-deep: nesting exceeds 256".into());
220    }
221    match value {
222        Value::Nil => output.push(NIL),
223        Value::Bool(false) => output.push(FALSE),
224        Value::Bool(true) => output.push(TRUE),
225        Value::Number(value) => {
226            output.push(I64);
227            output.extend_from_slice(&value.to_be_bytes());
228        }
229        Value::Float(value) => {
230            if !value.is_finite() {
231                return Err("hta/non-finite number".into());
232            }
233            output.push(F64);
234            output.extend_from_slice(&value.to_bits().to_be_bytes());
235        }
236        Value::Character(value) => {
237            output.push(CHARACTER);
238            output.extend_from_slice(&u32::from(*value).to_be_bytes());
239        }
240        Value::BigInteger(value) => {
241            if let Some(value) = value.to_i64() {
242                output.push(I64);
243                output.extend_from_slice(&value.to_be_bytes());
244            } else {
245                output.push(BIG_INTEGER);
246                encode_bytes(value.to_string().as_bytes(), output)?;
247            }
248        }
249        Value::Regex(value) => {
250            output.push(REGEX);
251            encode_bytes(value.as_bytes(), output)?;
252        }
253        Value::String(value) => {
254            output.push(STRING);
255            encode_bytes(value.as_str().as_bytes(), output)?;
256        }
257        Value::Bytes(value) => {
258            output.push(BYTES);
259            encode_bytes(value, output)?;
260        }
261        Value::ByteBuffer(value) => {
262            output.push(BYTES);
263            encode_bytes(&value.borrow(), output)?;
264        }
265        Value::Keyword(value) => {
266            output.push(KEYWORD);
267            encode_bytes(value.as_str().as_bytes(), output)?;
268        }
269        Value::Symbol(value) => {
270            output.push(SYMBOL);
271            encode_bytes(value.as_str().as_bytes(), output)?;
272        }
273        Value::List(values) => encode_sequence(LIST, values.iter(), output, depth)?,
274        Value::Tuple(values) => encode_sequence(VECTOR, values.iter(), output, depth)?,
275        Value::MapEntry(entry) => encode_sequence(MAP_ENTRY, entry.iter(), output, depth)?,
276        Value::Vector(values) => encode_sequence(VECTOR, values.iter(), output, depth)?,
277        Value::Cons(values) => encode_sequence(
278            CONS,
279            values.iter().collect::<Vec<_>>().iter(),
280            output,
281            depth,
282        )?,
283        Value::Queue(values) => encode_sequence(QUEUE, values.iter(), output, depth)?,
284        Value::Deque(values) => encode_sequence(DEQUE, values.iter(), output, depth)?,
285        Value::Set(values) => {
286            let mut encoded = values
287                .iter()
288                .map(|value| bare(value, depth + 1))
289                .collect::<Result<Vec<_>, _>>()?;
290            encoded.sort();
291            output.push(SET);
292            encode_len(encoded.len(), output)?;
293            for value in encoded {
294                output.extend_from_slice(&value);
295            }
296        }
297        Value::OrderedSet(values) => encode_sequence(ORDERED_SET, values.iter(), output, depth)?,
298        Value::SortedSet(values) => {
299            let mut encoded = values
300                .iter()
301                .map(|value| bare(value, depth + 1))
302                .collect::<Result<Vec<_>, _>>()?;
303            encoded.sort();
304            output.push(SORTED_SET);
305            encode_len(encoded.len(), output)?;
306            for value in encoded {
307                output.extend_from_slice(&value);
308            }
309        }
310        Value::OrderedMap(values) => encode_map(
311            ORDERED_MAP,
312            values.iter().map(|pair| (&pair.0, &pair.1)),
313            output,
314            depth,
315        )?,
316        Value::SortedMap(values) => encode_map(SORTED_MAP, values.iter(), output, depth)?,
317        Value::PriorityMap(values) => {
318            let entries = values.iter().collect::<Vec<_>>();
319            encode_map(
320                PRIORITY_MAP,
321                entries.iter().map(|pair| (&pair.0, &pair.1)),
322                output,
323                depth,
324            )?;
325        }
326        Value::Trie(values) => {
327            let entries = values
328                .iter()
329                .map(|key| {
330                    (
331                        Value::String(key.clone()),
332                        values.get(&key).unwrap().clone(),
333                    )
334                })
335                .collect::<Vec<_>>();
336            encode_map(
337                TRIE,
338                entries.iter().map(|pair| (&pair.0, &pair.1)),
339                output,
340                depth,
341            )?;
342        }
343        Value::Map(values) => {
344            let mut encoded = values
345                .iter()
346                .map(|(key, value)| Ok((bare(key, depth + 1)?, bare(value, depth + 1)?)))
347                .collect::<Result<Vec<_>, String>>()?;
348            encoded.sort_by(|left, right| left.0.cmp(&right.0));
349            output.push(MAP);
350            encode_len(encoded.len(), output)?;
351            for (key, value) in encoded {
352                output.extend_from_slice(&key);
353                output.extend_from_slice(&value);
354            }
355        }
356        Value::Namespace(value) => {
357            output.push(NAMESPACE);
358            encode_bytes(value.name().as_str().as_bytes(), output)?;
359        }
360        Value::Var(value) => {
361            output.push(VAR_REF);
362            encode_bare(&Value::Symbol(value.symbol().clone()), output, depth + 1)?;
363        }
364        Value::Atom(value) => {
365            output.push(ATOM);
366            encode_bare(&value.deref_value(), output, depth + 1)?;
367        }
368        Value::Array(values) => encode_sequence(ARRAY, values.borrow().iter(), output, depth)?,
369        Value::Object(values) => {
370            let values = values.borrow();
371            output.push(OBJECT);
372            encode_len(values.len(), output)?;
373            for (key, value) in values.iter() {
374                encode_bare(&Value::String(key.clone()), output, depth + 1)?;
375                encode_bare(value, output, depth + 1)?;
376            }
377        }
378        Value::Extension(value) => {
379            output.push(HANDLE);
380            encode_bytes(value.provider.as_bytes(), output)?;
381            encode_bytes(value.type_name.as_bytes(), output)?;
382            output.extend_from_slice(&value.handle.to_be_bytes());
383        }
384        Value::Tagged(value) => {
385            output.push(TAGGED);
386            encode_bare(&Value::Symbol(value.tag().clone()), output, depth + 1)?;
387            encode_bare(value.form(), output, depth + 1)?;
388        }
389        Value::ExceptionInfo(value) => {
390            if crate::core::map_entries(&value.data).is_none() {
391                return Err("hta/value-invalid: exception data must be a map".into());
392            }
393            if value
394                .cause
395                .as_deref()
396                .is_some_and(|cause| !matches!(cause, Value::ExceptionInfo(_)))
397            {
398                return Err("hta/value-invalid: exception cause must be an Exception".into());
399            }
400            output.push(EXCEPTION_INFO);
401            encode_bare(&Value::String(value.message.clone()), output, depth + 1)?;
402            encode_bare(&value.data, output, depth + 1)?;
403            encode_bare(
404                value.cause.as_deref().unwrap_or(&Value::Nil),
405                output,
406                depth + 1,
407            )?;
408            encode_bare(
409                &crate::core::exception_provenance_value(value),
410                output,
411                depth + 1,
412            )?;
413        }
414        Value::Result(value) => {
415            output.push(STRUCT);
416            encode_bare(&Value::String(RESULT_STRUCT_NAME.into()), output, depth + 1)?;
417            let fields = RESULT_STRUCT_FIELDS
418                .iter()
419                .map(|field| Value::String((*field).into()))
420                .collect::<Vec<_>>();
421            encode_sequence(VECTOR, fields.iter(), output, depth)?;
422            let values = [
423                value.status_value(),
424                value.data.clone(),
425                value.error_value(),
426                value.transport_context(),
427            ];
428            encode_sequence(VECTOR, values.iter(), output, depth)?;
429        }
430        Value::Struct(value) => {
431            output.push(STRUCT);
432            encode_bare(&Value::String(value.ty.name.clone()), output, depth + 1)?;
433            let fields = value
434                .ty
435                .fields
436                .iter()
437                .cloned()
438                .map(Value::String)
439                .collect::<Vec<_>>();
440            encode_sequence(VECTOR, fields.iter(), output, depth)?;
441            let values = value.ordered_values();
442            encode_sequence(VECTOR, values.into_iter(), output, depth)?;
443        }
444        Value::Pointer(value) => {
445            output.push(POINTER);
446            encode_bare(&Value::Keyword(value.context().clone()), output, depth + 1)?;
447            encode_bare(&Value::Map(value.fields().clone()), output, depth + 1)?;
448        }
449        Value::Mutable(_) | Value::MutableType(_) => {
450            return Err(
451                "hta/value-unsupported: mutable values are not serializable; use (into {} value)"
452                    .into(),
453            )
454        }
455        _ => return Err(format!("hta/value-unsupported: {}", value.display())),
456    }
457    Ok(())
458}
459
460fn encode_map<'a>(
461    tag: u8,
462    values: impl Iterator<Item = (&'a Value, &'a Value)>,
463    output: &mut Vec<u8>,
464    depth: usize,
465) -> Result<(), String> {
466    let values = values.collect::<Vec<_>>();
467    output.push(tag);
468    encode_len(values.len(), output)?;
469    for (key, value) in values {
470        encode_bare(key, output, depth + 1)?;
471        encode_bare(value, output, depth + 1)?;
472    }
473    Ok(())
474}
475
476fn bare(value: &Value, depth: usize) -> Result<Vec<u8>, String> {
477    let mut output = Vec::new();
478    encode_bare(value, &mut output, depth)?;
479    Ok(output)
480}
481
482fn encode_sequence<'a>(
483    tag: u8,
484    values: impl Iterator<Item = &'a Value>,
485    output: &mut Vec<u8>,
486    depth: usize,
487) -> Result<(), String> {
488    let values = values.collect::<Vec<_>>();
489    output.push(tag);
490    encode_len(values.len(), output)?;
491    for value in values {
492        encode_bare(value, output, depth + 1)?;
493    }
494    Ok(())
495}
496
497fn encode_bytes(value: &[u8], output: &mut Vec<u8>) -> Result<(), String> {
498    encode_len(value.len(), output)?;
499    output.extend_from_slice(value);
500    Ok(())
501}
502fn encode_len(value: usize, output: &mut Vec<u8>) -> Result<(), String> {
503    let value = u32::try_from(value).map_err(|_| "hta/value-too-large")?;
504    output.extend_from_slice(&value.to_be_bytes());
505    Ok(())
506}
507
508fn decode_result_struct(
509    name: &str,
510    fields: &[String],
511    values: &[Value],
512) -> Result<Option<Value>, String> {
513    let exact_fields = fields.len() == RESULT_STRUCT_FIELDS.len()
514        && fields
515            .iter()
516            .zip(RESULT_STRUCT_FIELDS.iter())
517            .all(|(field, expected)| field == expected);
518    if name != RESULT_STRUCT_NAME || !exact_fields {
519        return Ok(None);
520    }
521    let [status, data, error, context] = values else {
522        return Err("hta/value-malformed: Result arity mismatch".into());
523    };
524    let result = match status {
525        Value::Keyword(status) if status.as_str() == "success" => {
526            if !matches!(error, Value::Nil) {
527                return Err("hta/value-malformed: success Result contains an error".into());
528            }
529            ResultValue::success(data.clone(), context.clone())
530        }
531        Value::Keyword(status) if status.as_str() == "error" => {
532            if !matches!(data, Value::Nil) {
533                return Err("hta/value-malformed: error Result contains success data".into());
534            }
535            if !matches!(error, Value::ExceptionInfo(_)) {
536                return Err("hta/value-malformed: error Result lacks a native Error".into());
537            }
538            ResultValue::error(error.clone(), context.clone())
539        }
540        _ => return Err("hta/value-malformed: invalid Result status".into()),
541    }
542    .map_err(|error| format!("hta/value-malformed: invalid Result: {error}"))?;
543    Ok(Some(Value::Result(std::rc::Rc::new(result))))
544}
545
546struct Reader<'a> {
547    bytes: &'a [u8],
548    cursor: usize,
549}
550impl Reader<'_> {
551    fn value(&mut self, depth: usize) -> Result<Value, String> {
552        if depth > MAX_NESTING_DEPTH {
553            return Err("hta/value-too-deep: nesting exceeds 256".into());
554        }
555        let tag = self.byte()?;
556        match tag {
557            NIL => Ok(Value::Nil),
558            FALSE => Ok(Value::Bool(false)),
559            TRUE => Ok(Value::Bool(true)),
560            I64 => {
561                let bytes = self.take(8)?;
562                Ok(Value::Number(i64::from_be_bytes(bytes.try_into().unwrap())))
563            }
564            F64 => {
565                let bytes = self.take(8)?;
566                let value = f64::from_bits(u64::from_be_bytes(bytes.try_into().unwrap()));
567                if !value.is_finite() {
568                    return Err("hta/non-finite number".into());
569                }
570                Ok(Value::Float(value))
571            }
572            CHARACTER => {
573                let codepoint = u32::from_be_bytes(self.take(4)?.try_into().unwrap());
574                char::from_u32(codepoint)
575                    .map(Value::Character)
576                    .ok_or_else(|| "hta/value-malformed: invalid character scalar".into())
577            }
578            BIG_INTEGER => {
579                let text = String::from_utf8(self.data()?.to_vec())
580                    .map_err(|_| "hta/value-malformed: invalid big integer")?;
581                let value = BigInt::parse_bytes(text.as_bytes(), 10)
582                    .ok_or_else(|| "hta/value-malformed: invalid big integer".to_string())?;
583                Ok(crate::numeric::compact_integer(value))
584            }
585            REGEX => Ok(Value::Regex(
586                String::from_utf8(self.data()?.to_vec())
587                    .map_err(|_| "hta/value-malformed: invalid regex")?,
588            )),
589            STRING => Ok(Value::String(
590                String::from_utf8(self.data()?.to_vec())
591                    .map_err(|_| "hta/value-malformed: invalid UTF-8")?,
592            )),
593            BYTES => Ok(Value::Bytes(self.data()?.to_vec())),
594            KEYWORD => Ok(Value::Keyword(
595                String::from_utf8(self.data()?.to_vec())
596                    .map_err(|_| "hta/value-malformed: invalid UTF-8")?
597                    .into(),
598            )),
599            SYMBOL => Ok(Value::Symbol(
600                String::from_utf8(self.data()?.to_vec())
601                    .map_err(|_| "hta/value-malformed: invalid UTF-8")?
602                    .into(),
603            )),
604            LIST => Ok(Value::List(self.sequence(depth)?.into())),
605            TUPLE => Ok(Value::Tuple(Box::new(
606                crate::lang::data::Tuple::from_values(self.sequence(depth)?)?,
607            ))),
608            MAP_ENTRY => {
609                let values = self.sequence(depth)?;
610                let [key, value] = values.as_slice() else {
611                    return Err("hta/value-malformed: map entry must contain two values".into());
612                };
613                Ok(Value::MapEntry(Box::new(PMapEntry::new(
614                    key.clone(),
615                    value.clone(),
616                ))))
617            }
618            VECTOR => Ok(Value::Vector(self.sequence(depth)?.into())),
619            CONS => {
620                let mut values = self.sequence(depth)?;
621                if values.is_empty() {
622                    return Err("hta/value-malformed: empty cons".into());
623                }
624                let first = values.remove(0);
625                Ok(Value::Cons(Box::new(crate::lang::data::Cons::new(
626                    first,
627                    values.into_iter().collect(),
628                ))))
629            }
630            QUEUE => Ok(Value::Queue(Box::new(
631                self.sequence(depth)?.into_iter().collect(),
632            ))),
633            DEQUE => Ok(Value::Deque(Box::new(
634                self.sequence(depth)?.into_iter().collect(),
635            ))),
636            SET => Ok(Value::Set(self.sequence(depth)?.into())),
637            ORDERED_SET => Ok(Value::OrderedSet(Box::new(
638                self.sequence(depth)?.into_iter().collect(),
639            ))),
640            SORTED_SET => Ok(Value::SortedSet(Box::new(
641                self.sequence(depth)?.into_iter().collect(),
642            ))),
643            MAP => {
644                let size = self.len()?;
645                if size > self.bytes.len().saturating_sub(self.cursor) / 2 {
646                    return Err("hta/value-malformed: impossible map length".into());
647                }
648                let mut values = Vec::with_capacity(size);
649                for _ in 0..size {
650                    values.push((self.value(depth + 1)?, self.value(depth + 1)?));
651                }
652                Ok(Value::Map(values.into_iter().collect()))
653            }
654            ORDERED_MAP => Ok(Value::OrderedMap(Box::new(
655                self.entries(depth)?.into_iter().collect(),
656            ))),
657            SORTED_MAP => Ok(Value::SortedMap(Box::new(
658                self.entries(depth)?.into_iter().collect(),
659            ))),
660            PRIORITY_MAP => Ok(Value::PriorityMap(Box::new(
661                self.entries(depth)?.into_iter().collect(),
662            ))),
663            TRIE => {
664                let mut trie = crate::lang::data::Trie::new();
665                for (key, value) in self.entries(depth)? {
666                    let Value::String(key) = key else {
667                        return Err("hta/value-malformed: invalid trie key".into());
668                    };
669                    trie = trie.assoc_value(key, value);
670                }
671                Ok(Value::Trie(Box::new(trie)))
672            }
673            NAMESPACE => {
674                let name = String::from_utf8(self.data()?.to_vec())
675                    .map_err(|_| "hta/value-malformed: invalid namespace name")?;
676                Ok(Value::Namespace(std::rc::Rc::new(
677                    crate::kernel::Namespace::new(name),
678                )))
679            }
680            VAR => Err("hta/value-malformed: legacy var tag is not supported; use var-ref".into()),
681            VAR_REF => {
682                let symbol = match self.value(depth + 1)? {
683                    Value::Symbol(symbol) if symbol.get_namespace().is_some() => symbol,
684                    _ => return Err("hta/value-malformed: invalid Var reference".into()),
685                };
686                Ok(Value::Var(crate::kernel::Var::new(
687                    symbol.as_str(),
688                    Value::Nil,
689                )))
690            }
691            ATOM => Ok(Value::Atom(Box::new(crate::core::RuntimeAtom::new(
692                self.value(depth + 1)?,
693                true,
694            )))),
695            ARRAY => Ok(Value::Array(std::rc::Rc::new(std::cell::RefCell::new(
696                self.sequence(depth)?,
697            )))),
698            OBJECT => {
699                let size = self.len()?;
700                if size > self.bytes.len().saturating_sub(self.cursor) / 2 {
701                    return Err("hta/value-malformed: impossible object length".into());
702                }
703                let mut values = Vec::with_capacity(size);
704                for _ in 0..size {
705                    let Value::String(key) = self.value(depth + 1)? else {
706                        return Err("hta/value-malformed: invalid object key".into());
707                    };
708                    values.push((key, self.value(depth + 1)?));
709                }
710                Ok(Value::Object(std::rc::Rc::new(std::cell::RefCell::new(
711                    values,
712                ))))
713            }
714            HANDLE => {
715                let provider = String::from_utf8(self.data()?.to_vec())
716                    .map_err(|_| "hta/value-malformed: invalid handle owner")?;
717                let type_name = String::from_utf8(self.data()?.to_vec())
718                    .map_err(|_| "hta/value-malformed: invalid handle type")?;
719                let bytes = self.take(8)?;
720                Ok(Value::Extension(crate::core::ExtensionValue {
721                    provider,
722                    type_name,
723                    handle: u64::from_be_bytes(bytes.try_into().unwrap()),
724                }))
725            }
726            TAGGED => {
727                let Value::Symbol(tag) = self.value(depth + 1)? else {
728                    return Err("hta/value-malformed: invalid tagged literal tag".into());
729                };
730                Ok(Value::Tagged(Box::new(
731                    crate::lang::data::TaggedLiteral::new(tag, self.value(depth + 1)?),
732                )))
733            }
734            EXCEPTION_INFO => {
735                let Value::String(message) = self.value(depth + 1)? else {
736                    return Err("hta/value-malformed: invalid exception message".into());
737                };
738                let data = self.value(depth + 1)?;
739                let cause = match self.value(depth + 1)? {
740                    Value::Nil => None,
741                    value @ Value::ExceptionInfo(_) => Some(Box::new(value)),
742                    _ => {
743                        return Err("hta/value-malformed: invalid exception cause".into());
744                    }
745                };
746                if crate::core::map_entries(&data).is_none() {
747                    return Err("hta/value-malformed: invalid exception data".into());
748                }
749                let provenance = self.value(depth + 1)?;
750                let (created_at, throws) = decode_exception_provenance(provenance)?;
751                Ok(Value::ExceptionInfo(std::rc::Rc::new(
752                    crate::core::ExceptionInfo {
753                        message,
754                        data: Box::new(data),
755                        cause,
756                        provenance: std::rc::Rc::new(std::cell::RefCell::new(
757                            crate::core::ExceptionProvenance { created_at, throws },
758                        )),
759                    },
760                )))
761            }
762            STRUCT => {
763                let Value::String(name) = self.value(depth + 1)? else {
764                    return Err("hta/value-malformed: invalid struct name".into());
765                };
766                let fields = match self.value(depth + 1)? {
767                    Value::Vector(values) => values
768                        .iter()
769                        .map(|value| match value {
770                            Value::String(field) => Ok(field.clone()),
771                            _ => Err("hta/value-malformed: invalid struct field".into()),
772                        })
773                        .collect::<Result<Vec<_>, String>>()?,
774                    _ => return Err("hta/value-malformed: invalid struct fields".into()),
775                };
776                let values: Vec<Value> = match self.value(depth + 1)? {
777                    Value::Vector(values) => values.iter().cloned().collect(),
778                    _ => return Err("hta/value-malformed: invalid struct values".into()),
779                };
780                if fields.len() != values.len() {
781                    return Err("hta/value-malformed: struct arity mismatch".into());
782                }
783                if let Some(result) = decode_result_struct(&name, &fields, &values)? {
784                    return Ok(result);
785                }
786                Ok(Value::Struct(std::rc::Rc::new(
787                    crate::core::StructValue::from_values(
788                        std::rc::Rc::new(crate::core::StructType::detached(name, fields)),
789                        values,
790                        None,
791                    )?,
792                )))
793            }
794            POINTER => {
795                let Value::Keyword(context) = self.value(depth + 1)? else {
796                    return Err("hta/value-malformed: invalid pointer context".into());
797                };
798                let Value::Map(fields) = self.value(depth + 1)? else {
799                    return Err("hta/value-malformed: invalid pointer fields".into());
800                };
801                Ok(Value::Pointer(crate::lang::data::Pointer::new(
802                    context, fields,
803                )))
804            }
805            _ => Err(format!("hta/value-malformed: unknown value tag {tag}")),
806        }
807    }
808    fn sequence(&mut self, depth: usize) -> Result<Vec<Value>, String> {
809        let size = self.len()?;
810        if size > self.bytes.len().saturating_sub(self.cursor) {
811            return Err("hta/value-malformed: impossible sequence length".into());
812        }
813        (0..size).map(|_| self.value(depth + 1)).collect()
814    }
815    fn entries(&mut self, depth: usize) -> Result<Vec<(Value, Value)>, String> {
816        let size = self.len()?;
817        if size > self.bytes.len().saturating_sub(self.cursor) / 2 {
818            return Err("hta/value-malformed: impossible map length".into());
819        }
820        (0..size)
821            .map(|_| Ok((self.value(depth + 1)?, self.value(depth + 1)?)))
822            .collect()
823    }
824    fn data(&mut self) -> Result<&[u8], String> {
825        let size = self.len()?;
826        self.take(size)
827    }
828    fn len(&mut self) -> Result<usize, String> {
829        let bytes = self.take(4)?;
830        Ok(u32::from_be_bytes(bytes.try_into().unwrap()) as usize)
831    }
832    fn byte(&mut self) -> Result<u8, String> {
833        Ok(self.take(1)?[0])
834    }
835    fn take(&mut self, size: usize) -> Result<&[u8], String> {
836        let end = self
837            .cursor
838            .checked_add(size)
839            .ok_or("hta/value-malformed: length overflow")?;
840        if end > self.bytes.len() {
841            return Err("hta/value-malformed: truncated value".into());
842        }
843        let output = &self.bytes[self.cursor..end];
844        self.cursor = end;
845        Ok(output)
846    }
847}
848
849#[cfg(test)]
850mod tests {
851    use super::*;
852    #[test]
853    fn canonical_round_trip() {
854        let value = Value::Map(
855            vec![
856                (Value::Keyword("b".into()), Value::Number(2)),
857                (
858                    Value::Keyword("a".into()),
859                    Value::Vector(PVector::from(vec![Value::Bool(true), Value::Nil])),
860                ),
861            ]
862            .into_iter()
863            .collect(),
864        );
865        let encoded = encode(&value).unwrap();
866        assert_eq!(encode(&decode(&encoded).unwrap()).unwrap(), encoded);
867    }
868    #[test]
869    fn compact_vectors_and_legacy_tuples_have_distinct_wire_boundaries() {
870        let tuple = Value::Tuple(Box::new(
871            PTuple::from_values(vec![Value::Number(1), Value::Number(2)]).unwrap(),
872        ));
873        let encoded = encode(&tuple).unwrap();
874        assert_eq!(encoded[4], VECTOR);
875        assert!(matches!(decode(&encoded).unwrap(), Value::Vector(_)));
876
877        let mut legacy = encoded;
878        legacy[4] = TUPLE;
879        assert!(matches!(decode(&legacy).unwrap(), Value::Tuple(_)));
880
881        let entry = Value::MapEntry(Box::new(PMapEntry::new(
882            Value::Keyword("key".into()),
883            Value::Number(42),
884        )));
885        let encoded_entry = encode(&entry).unwrap();
886        assert_eq!(encoded_entry[4], MAP_ENTRY);
887        assert_eq!(decode(&encoded_entry).unwrap(), entry);
888    }
889
890    #[test]
891    fn pointers_round_trip_as_descriptors() {
892        let fields = vec![(Value::Keyword("id".into()), Value::String("ROOT".into()))]
893            .into_iter()
894            .collect();
895        let pointer = Value::Pointer(crate::lang::data::Pointer::new(
896            crate::lang::data::Keyword::from("kernel"),
897            fields,
898        ));
899        assert_eq!(decode(&encode(&pointer).unwrap()).unwrap(), pointer);
900    }
901
902    #[test]
903    fn immutable_v3_values_round_trip_without_collection_normalization() {
904        let queue = Value::Queue(Box::new(
905            vec![Value::Number(1), Value::Number(2)]
906                .into_iter()
907                .collect(),
908        ));
909        assert!(matches!(
910            decode(&encode(&queue).unwrap()).unwrap(),
911            Value::Queue(_)
912        ));
913        let deque = Value::Deque(Box::new(
914            vec![Value::Number(1), Value::Number(2)]
915                .into_iter()
916                .collect(),
917        ));
918        assert!(matches!(
919            decode(&encode(&deque).unwrap()).unwrap(),
920            Value::Deque(_)
921        ));
922        let priority_map = Value::PriorityMap(Box::new(
923            vec![
924                (Value::Keyword("a".into()), Value::Number(2)),
925                (Value::Keyword("b".into()), Value::Number(1)),
926            ]
927            .into_iter()
928            .collect(),
929        ));
930        let decoded = decode(&encode(&priority_map).unwrap()).unwrap();
931        assert!(matches!(decoded, Value::PriorityMap(_)));
932        assert_eq!(
933            crate::core::map_entries(&decoded).unwrap()[0].0,
934            Value::Keyword("b".into())
935        );
936        let tagged = Value::Tagged(Box::new(crate::lang::data::TaggedLiteral::new(
937            crate::lang::data::Symbol::parse("demo/tag"),
938            Value::Number(42),
939        )));
940        assert!(matches!(
941            decode(&encode(&tagged).unwrap()).unwrap(),
942            Value::Tagged(_)
943        ));
944    }
945    #[test]
946    fn floats_round_trip_with_ieee_754_bits() {
947        for value in [0.28, -0.0] {
948            let decoded = decode(&encode(&Value::Float(value)).unwrap()).unwrap();
949            let Value::Float(decoded) = decoded else {
950                panic!("float value")
951            };
952            assert_eq!(decoded.to_bits(), value.to_bits());
953        }
954        for value in [f64::NAN, f64::INFINITY, f64::NEG_INFINITY] {
955            assert!(encode(&Value::Float(value)).is_err());
956        }
957    }
958
959    #[test]
960    fn big_integer_wire_widths_are_canonicalized() {
961        for (value, tag) in [
962            (BigInt::from(i64::MIN), I64),
963            (BigInt::from(42_i64), I64),
964            (BigInt::from(i64::MAX), I64),
965            (BigInt::from(i64::MAX) + 1, BIG_INTEGER),
966        ] {
967            let encoded = encode(&Value::BigInteger(value)).unwrap();
968            assert_eq!(encoded[4], tag);
969            assert_eq!(
970                decode_canonical(&encoded).unwrap(),
971                decode(&encoded).unwrap()
972            );
973        }
974    }
975
976    #[test]
977    fn canonical_decoder_rejects_noncanonical_big_integer_and_map_frames() {
978        let noncanonical_integer = b"HTA0\x14\0\0\0\x02\x34\x32";
979        assert!(decode_canonical(noncanonical_integer)
980            .unwrap_err()
981            .starts_with("hta/value-noncanonical:"));
982
983        let mut noncanonical_map = b"HTA0\x0b\0\0\0\x02".to_vec();
984        noncanonical_map.extend(bare(&Value::String("b".into()), 0).unwrap());
985        noncanonical_map.extend(bare(&Value::Number(2), 0).unwrap());
986        noncanonical_map.extend(bare(&Value::String("a".into()), 0).unwrap());
987        noncanonical_map.extend(bare(&Value::Number(1), 0).unwrap());
988        assert!(decode_canonical(&noncanonical_map)
989            .unwrap_err()
990            .starts_with("hta/value-noncanonical:"));
991    }
992
993    #[test]
994    fn portable_language_scalars_round_trip() {
995        for value in [
996            Value::Character('雪'),
997            Value::BigInteger(BigInt::parse_bytes(b"123456789012345678901234567890", 10).unwrap()),
998            Value::Float(1.25),
999            Value::Regex("^[a-z]+$".into()),
1000        ] {
1001            assert_eq!(decode(&encode(&value).unwrap()).unwrap(), value);
1002        }
1003    }
1004
1005    #[test]
1006    fn scalar_regex_and_pointer_tags_match_the_portable_golden_vectors() {
1007        assert_eq!(
1008            encode(&Value::Character('λ')).unwrap(),
1009            b"HTA0\x13\0\0\x03\xbb"
1010        );
1011        assert_eq!(
1012            encode(&Value::Regex("a+".into())).unwrap(),
1013            b"HTA0\x16\0\0\0\x02a+"
1014        );
1015        let fields = vec![(Value::Keyword("id".into()), Value::String("ROOT".into()))]
1016            .into_iter()
1017            .collect();
1018        let pointer = Value::Pointer(crate::lang::data::Pointer::new(
1019            crate::lang::data::Keyword::from("kernel"),
1020            fields,
1021        ));
1022        assert_eq!(
1023            encode(&pointer).unwrap(),
1024            b"HTA0\x22\x06\0\0\0\x06kernel\x0b\0\0\0\x01\x06\0\0\0\x02id\x04\0\0\0\x04ROOT"
1025        );
1026    }
1027
1028    #[test]
1029    fn tag_inventory_keeps_legacy_var_distinct_from_var_reference() {
1030        assert_eq!(
1031            HTA0_TAG_INVENTORY
1032                .iter()
1033                .find(|(_, name)| *name == "character"),
1034            Some(&(19, "character"))
1035        );
1036        assert_eq!(
1037            HTA0_TAG_INVENTORY
1038                .iter()
1039                .find(|(_, name)| *name == "pointer"),
1040            Some(&(34, "pointer"))
1041        );
1042        assert_eq!(
1043            HTA0_TAG_INVENTORY
1044                .iter()
1045                .find(|(_, name)| *name == "var-ref"),
1046            Some(&(35, "var-ref"))
1047        );
1048        assert!(decode(b"HTA0\x0e\x07\0\0\0\x04rank\0").is_err());
1049    }
1050
1051    #[test]
1052    fn native_result_round_trips_through_the_canonical_struct_shape() {
1053        let context = Value::Map(
1054            vec![(Value::Keyword("source".into()), Value::String("hta".into()))]
1055                .into_iter()
1056                .collect(),
1057        );
1058        let value = Value::Result(std::rc::Rc::new(
1059            ResultValue::success(Value::Number(42), context).unwrap(),
1060        ));
1061
1062        let encoded = encode(&value).unwrap();
1063        let decoded = decode(&encoded).unwrap();
1064
1065        assert_eq!(decoded, value);
1066        assert!(matches!(decoded, Value::Result(_)));
1067        assert!(encoded
1068            .windows(17)
1069            .any(|bytes| bytes == b"std.native/Result"));
1070    }
1071
1072    #[test]
1073    fn canonical_maps_ignore_insertion_order() {
1074        let a = Value::Map(
1075            vec![
1076                (Value::String("b".into()), Value::Number(2)),
1077                (Value::String("a".into()), Value::Number(1)),
1078            ]
1079            .into_iter()
1080            .collect(),
1081        );
1082        let b = Value::Map(
1083            vec![
1084                (Value::String("a".into()), Value::Number(1)),
1085                (Value::String("b".into()), Value::Number(2)),
1086            ]
1087            .into_iter()
1088            .collect(),
1089        );
1090        assert_eq!(encode(&a).unwrap(), encode(&b).unwrap());
1091    }
1092    #[test]
1093    fn namespaces_and_vars_use_snapshot_and_reference_contracts() {
1094        let namespace = crate::kernel::Namespace::new("example.lib");
1095        let var = namespace.intern("answer", Value::Number(42));
1096        let value = Value::Map(
1097            vec![
1098                (
1099                    Value::Keyword("namespace".into()),
1100                    Value::Namespace(std::rc::Rc::new(namespace)),
1101                ),
1102                (Value::Keyword("var".into()), Value::Var(var)),
1103            ]
1104            .into_iter()
1105            .collect(),
1106        );
1107        let decoded = decode(&encode(&value).unwrap()).unwrap();
1108        let Value::Map(decoded) = decoded else {
1109            panic!("map snapshot")
1110        };
1111        let Value::Namespace(namespace) = decoded.get(&Value::Keyword("namespace".into())).unwrap()
1112        else {
1113            panic!("namespace snapshot")
1114        };
1115        assert_eq!(namespace.name().as_str(), "example.lib");
1116        let Value::Var(var) = decoded.get(&Value::Keyword("var".into())).unwrap() else {
1117            panic!("var snapshot")
1118        };
1119        assert_eq!(var.symbol().as_str(), "example.lib/answer");
1120        assert_eq!(var.deref_value(), Value::Nil);
1121        let encoded = encode(&Value::Var(var.clone())).unwrap();
1122        assert_eq!(encoded[4], VAR_REF);
1123        assert_eq!(encoded, b"HTA0\x23\x07\x00\x00\x00\x12example.lib/answer");
1124    }
1125
1126    #[test]
1127    fn opaque_handles_round_trip() {
1128        let value = Value::Extension(crate::core::ExtensionValue {
1129            provider: "runtime".into(),
1130            type_name: "cursor".into(),
1131            handle: 42,
1132        });
1133        assert_eq!(decode(&encode(&value).unwrap()).unwrap(), value);
1134    }
1135
1136    #[test]
1137    fn structs_preserve_wire_shape_and_mutables_are_rejected() {
1138        let ty = std::rc::Rc::new(crate::core::StructType::detached(
1139            "demo/Point".into(),
1140            vec!["x".into(), "y".into()],
1141        ));
1142        let value = Value::Struct(std::rc::Rc::new(
1143            crate::core::StructValue::from_values(
1144                ty,
1145                vec![Value::Number(1), Value::Number(2)],
1146                None,
1147            )
1148            .unwrap(),
1149        ));
1150        let decoded = decode(&encode(&value).unwrap()).unwrap();
1151        assert_eq!(
1152            crate::core::call_value(Value::Keyword("x".into()), vec![decoded.clone()]).unwrap(),
1153            Value::Number(1)
1154        );
1155        assert_eq!(
1156            crate::core::call_value(
1157                Value::Keyword("missing".into()),
1158                vec![decoded.clone(), Value::Number(7)],
1159            )
1160            .unwrap(),
1161            Value::Number(7)
1162        );
1163        let Value::Struct(decoded) = decoded else {
1164            panic!("struct value")
1165        };
1166        assert_eq!(decoded.ty.name, "demo/Point");
1167        assert_eq!(decoded.ty.fields, vec!["x", "y"]);
1168        assert_eq!(
1169            decoded
1170                .ordered_values()
1171                .into_iter()
1172                .cloned()
1173                .collect::<Vec<_>>(),
1174            vec![Value::Number(1), Value::Number(2)]
1175        );
1176
1177        let mutable = Value::Mutable(std::rc::Rc::new(
1178            crate::core::MutableValue::from_values(
1179                std::rc::Rc::new(crate::core::MutableType::detached(
1180                    "demo/Cursor".into(),
1181                    vec!["x".into()],
1182                )),
1183                vec![Value::Number(1)],
1184                None,
1185            )
1186            .unwrap(),
1187        ));
1188        assert_eq!(
1189            encode(&mutable).unwrap_err(),
1190            "hta/value-unsupported: mutable values are not serializable; use (into {} value)"
1191        );
1192    }
1193
1194    #[test]
1195    fn nesting_depth_is_bounded_on_encode_and_decode() {
1196        let mut value = Value::Nil;
1197        for _ in 0..=MAX_NESTING_DEPTH {
1198            value = Value::Vector(PVector::from(vec![value]));
1199        }
1200        assert!(encode(&value).unwrap_err().contains("value-too-deep"));
1201
1202        let mut bytes = MAGIC.to_vec();
1203        for _ in 0..=MAX_NESTING_DEPTH {
1204            bytes.extend_from_slice(&[VECTOR, 0, 0, 0, 1]);
1205        }
1206        bytes.push(NIL);
1207        assert!(decode(&bytes).unwrap_err().contains("value-too-deep"));
1208    }
1209
1210    #[test]
1211    fn impossible_container_lengths_fail_before_allocating() {
1212        let mut bytes = MAGIC.to_vec();
1213        bytes.extend_from_slice(&[VECTOR, 0xff, 0xff, 0xff, 0xff]);
1214        assert!(decode(&bytes)
1215            .unwrap_err()
1216            .contains("impossible sequence length"));
1217    }
1218}