Skip to main content

rune/runtime/const_value/
node.rs

1//! The array a [`ConstValue`] is made of.
2//!
3//! A constant is an owned tree, and a tree which owns its parts is built,
4//! walked, cloned and dropped by recursing over it unless something is done
5//! about it. So it is not stored as a tree at all: it is stored as one array of
6//! nodes in pre-order, in which every subtree is a contiguous run.
7//!
8//! That makes dropping and cloning a constant the same operation as dropping
9//! and cloning one array, and makes reading one back off disk a linear pass
10//! which *checks* how deeply the array nests rather than a descent which finds
11//! out by surviving.
12
13use core::fmt;
14use core::mem::take;
15use core::ops::{Deref, DerefMut};
16
17#[cfg(feature = "musli")]
18use musli_core::{Decode, Encode};
19#[cfg(feature = "serde")]
20use serde::{Deserialize, Serialize};
21
22use crate::alloc::prelude::*;
23use crate::alloc::{self, Box, Vec};
24use crate::runtime::{AnyTypeInfo, Bytes, Inline, Object, OwnedTuple, TypeInfo, Value};
25use crate::{self as rune};
26use crate::{Hash, TypeHash};
27
28use super::{MAX_CONST_DEPTH, MAX_CONST_SIZE};
29
30/// One node of the array a [`ConstValue`] is made of.
31///
32/// The nodes of a subtree are laid out in pre-order, so `size` is what says
33/// where one subtree ends and the next begins - it is how many nodes this node
34/// and everything below it occupy, so a leaf is `1`.
35///
36/// It is derived rather than stored: whoever hands over an array hands over the
37/// kinds, and the sizes are worked out from them, so there is nothing for a
38/// size to disagree with.
39#[derive(Debug, TryClone)]
40pub(crate) struct ConstNode {
41    #[try_clone(copy)]
42    pub(crate) size: u32,
43    /// How deeply this node's subtree nests, itself included. A leaf is `1`.
44    ///
45    /// Keeping it means the depth of a constant is known without walking it,
46    /// which is what lets the bound be checked wherever one is built out of
47    /// others rather than only where one is built from scratch.
48    #[try_clone(copy)]
49    pub(crate) height: u32,
50    pub(crate) kind: ConstNodeKind,
51}
52
53/// What one node of a [`ConstValue`] is.
54///
55/// Only the counts are stored - which nodes are a node's children is decided by
56/// where they are, which is what makes the array a tree.
57#[derive(Debug, TryClone)]
58#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
59#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(crate = musli_core))]
60pub(crate) enum ConstNodeKind {
61    /// An inline constant value.
62    Inline(#[try_clone(copy)] Inline),
63    /// A string constant.
64    String(Box<str>),
65    /// A byte string.
66    Bytes(Box<[u8]>),
67    /// An instance of some type of value, made of the `fields` subtrees which
68    /// follow it.
69    Instance {
70        /// The type hash of the value. If the value is a variant, this is the
71        /// type hash of the enum.
72        #[try_clone(copy)]
73        hash: Hash,
74        /// The type hash of the variant, or [`Hash::EMPTY`] if this is not an
75        /// enum.
76        #[try_clone(copy)]
77        variant_hash: Hash,
78        /// How many subtrees follow.
79        #[try_clone(copy)]
80        fields: u32,
81    },
82    /// An object, where `keys[n]` names the `n`th of the `keys.len()` subtrees
83    /// which follow it.
84    ///
85    /// The keys are kept sorted, so that whoever reads one back does not have
86    /// to sort them again.
87    Object { keys: Box<[Box<str>]> },
88}
89
90impl ConstNodeKind {
91    /// How many subtrees follow this node.
92    #[inline]
93    pub(crate) fn children(&self) -> usize {
94        match self {
95            ConstNodeKind::Instance { fields, .. } => *fields as usize,
96            ConstNodeKind::Object { keys } => keys.len(),
97            _ => 0,
98        }
99    }
100
101    pub(crate) fn type_info(&self) -> TypeInfo {
102        fn struct_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
103            write!(f, "unknown constant struct")
104        }
105
106        fn variant_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
107            write!(f, "unknown constant variant")
108        }
109
110        match self {
111            ConstNodeKind::Inline(value) => value.type_info(),
112            ConstNodeKind::String(..) => TypeInfo::any::<crate::alloc::String>(),
113            ConstNodeKind::Bytes(..) => TypeInfo::any::<Bytes>(),
114            ConstNodeKind::Object { .. } => TypeInfo::any::<Object>(),
115            ConstNodeKind::Instance {
116                hash, variant_hash, ..
117            } => match *hash {
118                Option::<Value>::HASH => TypeInfo::any::<Option<Value>>(),
119                crate::runtime::Vec::HASH => TypeInfo::any::<crate::runtime::Vec>(),
120                OwnedTuple::HASH => TypeInfo::any::<OwnedTuple>(),
121                Object::HASH => TypeInfo::any::<Object>(),
122                hash if *variant_hash == Hash::EMPTY => {
123                    TypeInfo::any_type_info(AnyTypeInfo::new(struct_name, hash))
124                }
125                hash => TypeInfo::any_type_info(AnyTypeInfo::new(variant_name, hash)),
126            },
127        }
128    }
129}
130
131/// What is wrong with an array which does not describe a constant.
132///
133/// An array is only ever built here, so this is what a *decoded* one can be:
134/// whoever wrote it decided what is in it, and a `.rnc` file is read back from
135/// disk.
136#[derive(Debug)]
137pub(crate) enum ConstNodesError {
138    /// The array is empty, and every constant has at least a root.
139    #[cfg(any(feature = "serde", feature = "musli"))]
140    Empty,
141    /// A node claims more subtrees follow it than the array has left, or the
142    /// array has nodes left over once the root's subtree ends.
143    #[cfg(any(feature = "serde", feature = "musli"))]
144    Malformed,
145    /// The array nests deeper than a constant is allowed to.
146    TooDeep { max: usize },
147    /// The array is made of more nodes than a constant is allowed to be.
148    TooLarge { max: usize },
149    /// Memory ran out while the array was being checked.
150    Alloc(alloc::Error),
151}
152
153impl From<alloc::Error> for ConstNodesError {
154    #[inline]
155    fn from(error: alloc::Error) -> Self {
156        ConstNodesError::Alloc(error)
157    }
158}
159
160impl fmt::Display for ConstNodesError {
161    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162        match self {
163            #[cfg(any(feature = "serde", feature = "musli"))]
164            ConstNodesError::Empty => write!(f, "Constant value is empty"),
165            #[cfg(any(feature = "serde", feature = "musli"))]
166            ConstNodesError::Malformed => {
167                write!(f, "Constant value is not a tree")
168            }
169            ConstNodesError::TooDeep { max } => {
170                write!(f, "Constant value is nested too deeply, limit is {max}")
171            }
172            ConstNodesError::TooLarge { max } => {
173                write!(
174                    f,
175                    "Constant value is made of too many values, limit is {max}"
176                )
177            }
178            ConstNodesError::Alloc(error) => error.fmt(f),
179        }
180    }
181}
182
183impl core::error::Error for ConstNodesError {}
184
185/// Work out the size of every subtree in `kinds`, checking as it goes that the
186/// array describes one tree and that the tree is within the limits.
187///
188/// The walk goes backwards, so that a node is reached once everything below it
189/// has been. Each node takes the subtrees of its children off the stack, which
190/// is what says the array is a tree: running out of them means a node claimed
191/// children it does not have, and having any left at the end means the array
192/// holds more than the root's subtree.
193#[cfg(any(feature = "serde", feature = "musli"))]
194fn measure(kinds: &[ConstNodeKind]) -> Result<Vec<(u32, u32)>, ConstNodesError> {
195    let len = kinds.len();
196
197    if len == 0 {
198        return Err(ConstNodesError::Empty);
199    }
200
201    if len > MAX_CONST_SIZE {
202        return Err(ConstNodesError::TooLarge {
203            max: MAX_CONST_SIZE,
204        });
205    }
206
207    let mut sizes = Vec::new();
208    let mut heights = Vec::new();
209    sizes.try_resize(len, 0u32)?;
210    heights.try_resize(len, 0u32)?;
211
212    // The subtrees which are complete but whose parent has not been reached
213    // yet, most recent first - so popping hands them back in the order they
214    // appear in the array.
215    let mut pending = Vec::new();
216
217    for index in (0..len).rev() {
218        let mut size = 1u32;
219        let mut height = 1u32;
220
221        for _ in 0..kinds[index].children() {
222            let child: usize = pending.pop().ok_or(ConstNodesError::Malformed)?;
223
224            size = size
225                .checked_add(sizes[child])
226                .ok_or(ConstNodesError::Malformed)?;
227
228            height = height.max(heights[child].saturating_add(1));
229        }
230
231        sizes[index] = size;
232        heights[index] = height;
233        pending.try_push(index)?;
234    }
235
236    // Everything below the root has been taken by something, and the root is
237    // what is left.
238    if pending.len() != 1 {
239        return Err(ConstNodesError::Malformed);
240    }
241
242    if heights[0] as usize > MAX_CONST_DEPTH {
243        return Err(ConstNodesError::TooDeep {
244            max: MAX_CONST_DEPTH,
245        });
246    }
247
248    let mut out = Vec::try_with_capacity(len)?;
249
250    for index in 0..len {
251        out.try_push((sizes[index], heights[index]))?;
252    }
253
254    Ok(out)
255}
256
257/// The fields of an instance or the values of an object.
258///
259/// A field is a subtree rather than an element, so this is a view over the run
260/// which holds them all rather than a slice of them.
261#[derive(Clone, Copy)]
262pub struct ConstFields<'a> {
263    nodes: &'a [ConstNode],
264    len: usize,
265}
266
267impl<'a> ConstFields<'a> {
268    /// An empty set of fields.
269    pub(crate) const EMPTY: ConstFields<'static> = ConstFields { nodes: &[], len: 0 };
270
271    /// How many fields there are.
272    #[inline]
273    pub fn len(&self) -> usize {
274        self.len
275    }
276
277    /// Whether there are no fields.
278    #[inline]
279    pub fn is_empty(&self) -> bool {
280        self.len == 0
281    }
282
283    /// Get the field at `index`.
284    ///
285    /// This walks past the fields before it, since a field is as long as the
286    /// subtree it is.
287    pub fn get(&self, index: usize) -> Option<&'a ConstValue> {
288        if index >= self.len {
289            return None;
290        }
291
292        let mut nodes = self.nodes;
293
294        for _ in 0..index {
295            let size = nodes.first()?.size as usize;
296            nodes = nodes.get(size..)?;
297        }
298
299        let size = nodes.first()?.size as usize;
300        Some(ConstValue::from_nodes(nodes.get(..size)?))
301    }
302
303    /// Iterate over the fields in order.
304    #[inline]
305    pub fn iter(&self) -> ConstFieldsIter<'a> {
306        ConstFieldsIter {
307            nodes: self.nodes,
308            len: self.len,
309        }
310    }
311}
312
313impl fmt::Debug for ConstFields<'_> {
314    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
315        f.debug_list().entries(self.iter()).finish()
316    }
317}
318
319impl<'a> IntoIterator for ConstFields<'a> {
320    type Item = &'a ConstValue;
321    type IntoIter = ConstFieldsIter<'a>;
322
323    #[inline]
324    fn into_iter(self) -> Self::IntoIter {
325        self.iter()
326    }
327}
328
329/// An iterator over the fields of an instance, see [`ConstFields::iter`].
330#[derive(Clone)]
331pub struct ConstFieldsIter<'a> {
332    nodes: &'a [ConstNode],
333    len: usize,
334}
335
336impl<'a> Iterator for ConstFieldsIter<'a> {
337    type Item = &'a ConstValue;
338
339    #[inline]
340    fn next(&mut self) -> Option<Self::Item> {
341        if self.len == 0 {
342            return None;
343        }
344
345        let size = self.nodes.first()?.size as usize;
346        let (head, tail) = self.nodes.split_at_checked(size)?;
347        self.nodes = tail;
348        self.len -= 1;
349        Some(ConstValue::from_nodes(head))
350    }
351
352    #[inline]
353    fn size_hint(&self) -> (usize, Option<usize>) {
354        (self.len, Some(self.len))
355    }
356}
357
358impl ExactSizeIterator for ConstFieldsIter<'_> {
359    #[inline]
360    fn len(&self) -> usize {
361        self.len
362    }
363}
364
365/// A constant value.
366///
367/// This is the borrowed half of the pair, the way [`Item`] is to [`ItemBuf`] -
368/// a subtree of a constant is a run of the array its parent is stored in, so a
369/// field of a constant is one of these rather than something which had to be
370/// copied out.
371///
372/// [`Item`]: crate::Item
373/// [`ItemBuf`]: crate::ItemBuf
374#[repr(transparent)]
375pub struct ConstValue {
376    nodes: [ConstNode],
377}
378
379impl ConstValue {
380    /// View a run of nodes as the constant it describes.
381    ///
382    /// The run has to be one whole subtree, which is what everything handing
383    /// one out here is careful to pass.
384    #[inline]
385    pub(crate) fn from_nodes(nodes: &[ConstNode]) -> &Self {
386        // SAFETY: `ConstValue` is `#[repr(transparent)]` over `[ConstNode]`.
387        unsafe { &*(nodes as *const [ConstNode] as *const ConstValue) }
388    }
389
390    /// The nodes this constant is made of, its root first.
391    #[inline]
392    pub(crate) fn as_nodes(&self) -> &[ConstNode] {
393        &self.nodes
394    }
395
396    /// What the root of this constant is.
397    #[inline]
398    pub(crate) fn kind(&self) -> &ConstNodeKind {
399        // A constant is never empty - see `measure` and `ConstBuilder::build`.
400        match self.nodes.first() {
401            Some(node) => &node.kind,
402            None => &ConstNodeKind::Inline(Inline::Empty),
403        }
404    }
405
406    /// The subtrees which follow the root, whatever it is.
407    ///
408    /// This is what the code written by the [`ToConstValue`] derive reads a
409    /// constant's fields back out of.
410    ///
411    /// [`ToConstValue`]: derive@crate::ToConstValue
412    #[inline]
413    pub fn fields(&self) -> ConstFields<'_> {
414        let Some((_, rest)) = self.nodes.split_first() else {
415            return ConstFields::EMPTY;
416        };
417
418        ConstFields {
419            nodes: rest,
420            len: self.kind().children(),
421        }
422    }
423
424    /// What the root of this constant is, so that it can be changed in place.
425    ///
426    /// Only the leaves an inline value is stored in are reachable this way,
427    /// which is what keeps the shape of the array from being changed under it.
428    #[inline]
429    pub(crate) fn kind_mut(&mut self) -> Option<&mut ConstNodeKind> {
430        Some(&mut self.nodes.first_mut()?.kind)
431    }
432
433    /// How deeply this constant nests, itself included - so a scalar is `1`.
434    ///
435    /// Every constant which exists is within [`MAX_CONST_DEPTH`], which is
436    /// checked wherever one is built and wherever one is read back.
437    #[inline]
438    pub(crate) fn height(&self) -> u32 {
439        match self.nodes.first() {
440            Some(node) => node.height,
441            None => 0,
442        }
443    }
444
445    /// Get the type information of the value.
446    #[inline]
447    pub(crate) fn type_info(&self) -> TypeInfo {
448        self.kind().type_info()
449    }
450}
451
452impl fmt::Debug for ConstValue {
453    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
454        self::debug::fmt(self, f)
455    }
456}
457
458impl TryToOwned for ConstValue {
459    type Owned = ConstValueBuf;
460
461    #[inline]
462    fn try_to_owned(&self) -> alloc::Result<Self::Owned> {
463        ConstValueBuf::from_vec(self.nodes.try_to_owned()?)
464    }
465}
466
467/// A constant value which owns what it is made of.
468///
469/// This is the owned half of the pair, the way [`ItemBuf`] is to [`Item`].
470/// Everything it is made of is in one allocation, so cloning one is one copy
471/// and dropping one is one deallocation, whatever shape the constant is.
472///
473/// [`Item`]: crate::Item
474/// [`ItemBuf`]: crate::ItemBuf
475pub struct ConstValueBuf {
476    nodes: Nodes,
477}
478
479/// Where the nodes of an owned constant are kept.
480///
481/// Most constants are one scalar, so the one-node case is kept inline and a
482/// constant only allocates once it is made of something.
483enum Nodes {
484    One(ConstNode),
485    Many(Box<[ConstNode]>),
486}
487
488impl Nodes {
489    #[inline]
490    fn as_slice(&self) -> &[ConstNode] {
491        match self {
492            Nodes::One(node) => core::slice::from_ref(node),
493            Nodes::Many(nodes) => nodes,
494        }
495    }
496
497    #[inline]
498    fn as_mut_slice(&mut self) -> &mut [ConstNode] {
499        match self {
500            Nodes::One(node) => core::slice::from_mut(node),
501            Nodes::Many(nodes) => nodes,
502        }
503    }
504}
505
506impl TryClone for Nodes {
507    #[inline]
508    fn try_clone(&self) -> alloc::Result<Self> {
509        Ok(match self {
510            Nodes::One(node) => Nodes::One(node.try_clone()?),
511            Nodes::Many(nodes) => Nodes::Many(nodes.try_clone()?),
512        })
513    }
514}
515
516impl ConstValueBuf {
517    /// Build one from a run of nodes which is known to be a whole subtree.
518    pub(crate) fn from_vec(nodes: Vec<ConstNode>) -> alloc::Result<Self> {
519        let mut nodes = nodes;
520
521        // A constant which is one node is kept inline, which is what a scalar
522        // constant costs - nothing.
523        if nodes.len() == 1 {
524            if let Some(node) = nodes.pop() {
525                return Ok(Self {
526                    nodes: Nodes::One(node),
527                });
528            }
529        }
530
531        Ok(Self {
532            nodes: Nodes::Many(nodes.try_into_boxed_slice()?),
533        })
534    }
535
536    /// Build one from the kinds an array is made of, working out the shape and
537    /// checking that it is a tree within the limits.
538    ///
539    /// This is what reading a constant back from somewhere else goes through,
540    /// so it is where an array which is not a constant is turned away.
541    #[cfg(any(feature = "serde", feature = "musli"))]
542    pub(crate) fn from_kinds(kinds: Vec<ConstNodeKind>) -> Result<Self, ConstNodesError> {
543        let sizes = measure(&kinds)?;
544
545        let mut nodes = Vec::try_with_capacity(kinds.len())?;
546
547        for ((size, height), kind) in sizes.into_iter().zip(kinds) {
548            nodes.try_push(ConstNode { size, height, kind })?;
549        }
550
551        Ok(Self::from_vec(nodes)?)
552    }
553
554    /// The kinds this constant is made of, which is what is written down when
555    /// one is handed to somebody else.
556    #[cfg(any(feature = "serde", feature = "musli"))]
557    #[inline]
558    pub(crate) fn kinds(&self) -> impl ExactSizeIterator<Item = &ConstNodeKind> + '_ {
559        self.nodes.as_slice().iter().map(|node| &node.kind)
560    }
561}
562
563impl ConstValueBuf {
564    /// Build one out of a single node which has nothing below it.
565    ///
566    /// This is where most constants come from and it does not allocate.
567    #[inline]
568    pub(crate) fn from_kind(kind: ConstNodeKind) -> Self {
569        Self {
570            nodes: Nodes::One(ConstNode {
571                size: 1,
572                height: 1,
573                kind,
574            }),
575        }
576    }
577}
578
579impl Deref for ConstValueBuf {
580    type Target = ConstValue;
581
582    #[inline]
583    fn deref(&self) -> &Self::Target {
584        ConstValue::from_nodes(self.nodes.as_slice())
585    }
586}
587
588impl DerefMut for ConstValueBuf {
589    #[inline]
590    fn deref_mut(&mut self) -> &mut Self::Target {
591        let nodes = self.nodes.as_mut_slice();
592        // SAFETY: `ConstValue` is `#[repr(transparent)]` over `[ConstNode]`.
593        unsafe { &mut *(nodes as *mut [ConstNode] as *mut ConstValue) }
594    }
595}
596
597/// A constant is written down as the kinds its nodes are, since the shape is
598/// worked out from them again when it is read back - so there is nothing for a
599/// size written down to disagree with.
600#[cfg(feature = "serde")]
601impl Serialize for ConstValueBuf {
602    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
603    where
604        S: serde::Serializer,
605    {
606        use serde::ser::SerializeSeq;
607
608        let mut seq = serializer.serialize_seq(Some(self.nodes.as_slice().len()))?;
609
610        for kind in self.kinds() {
611            seq.serialize_element(kind)?;
612        }
613
614        seq.end()
615    }
616}
617
618/// Reading a constant back checks that what was written down is a tree, and
619/// that it is one within the limits, before anything walks it.
620#[cfg(feature = "serde")]
621impl<'de> Deserialize<'de> for ConstValueBuf {
622    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
623    where
624        D: serde::Deserializer<'de>,
625    {
626        use serde::de::Error;
627
628        let kinds = Vec::<ConstNodeKind>::deserialize(deserializer)?;
629        ConstValueBuf::from_kinds(kinds).map_err(D::Error::custom)
630    }
631}
632
633#[cfg(feature = "musli")]
634impl<M> Encode<M> for ConstValueBuf
635where
636    ConstNodeKind: Encode<M>,
637{
638    type Encode = Self;
639
640    const IS_BITWISE_ENCODE: bool = false;
641
642    #[inline]
643    fn encode<E>(&self, encoder: E) -> Result<(), E::Error>
644    where
645        E: musli_core::en::Encoder<Mode = M>,
646    {
647        use musli_core::en::{Encoder, SequenceEncoder};
648
649        encoder.encode_sequence_fn(self.nodes.as_slice().len(), |seq| {
650            for kind in self.kinds() {
651                seq.encode_next()?.encode(kind)?;
652            }
653
654            Ok(())
655        })
656    }
657
658    #[inline]
659    fn as_encode(&self) -> &Self::Encode {
660        self
661    }
662}
663
664#[cfg(feature = "musli")]
665impl<'de, M, A> Decode<'de, M, A> for ConstValueBuf
666where
667    A: musli_core::Allocator,
668    ConstNodeKind: Decode<'de, M, A>,
669{
670    const IS_BITWISE_DECODE: bool = false;
671
672    #[inline]
673    fn decode<D>(decoder: D) -> Result<Self, D::Error>
674    where
675        D: musli_core::de::Decoder<'de, Mode = M, Allocator = A>,
676    {
677        use musli_core::Context;
678
679        let cx = decoder.cx();
680        let kinds = decoder.decode::<Vec<ConstNodeKind>>()?;
681        ConstValueBuf::from_kinds(kinds).map_err(|error| cx.custom(error))
682    }
683}
684
685impl AsRef<ConstValue> for ConstValueBuf {
686    #[inline]
687    fn as_ref(&self) -> &ConstValue {
688        self
689    }
690}
691
692impl core::borrow::Borrow<ConstValue> for ConstValueBuf {
693    #[inline]
694    fn borrow(&self) -> &ConstValue {
695        self
696    }
697}
698
699impl TryClone for ConstValueBuf {
700    #[inline]
701    fn try_clone(&self) -> alloc::Result<Self> {
702        Ok(Self {
703            nodes: self.nodes.try_clone()?,
704        })
705    }
706}
707
708impl fmt::Debug for ConstValueBuf {
709    #[inline]
710    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
711        fmt::Debug::fmt(&**self, f)
712    }
713}
714
715/// Builds the array a constant is made of.
716///
717/// Nodes are appended in the order they are walked, which is the order they are
718/// stored in. A node which has subtrees below it is opened before them and
719/// closed after, since how long its subtree is is only known once they are all
720/// there.
721pub(crate) struct ConstBuilder {
722    nodes: Vec<ConstNode>,
723    /// The greatest height among the subtrees which are complete at each level
724    /// which is still open, innermost last.
725    levels: Vec<u32>,
726    /// The greatest height among the subtrees which are complete at the
727    /// outermost level.
728    height: u32,
729}
730
731impl ConstBuilder {
732    #[inline]
733    pub(crate) fn new() -> Self {
734        Self {
735            nodes: Vec::new(),
736            levels: Vec::new(),
737            height: 0,
738        }
739    }
740
741    /// How many nodes have been appended so far, which is what
742    /// [`MAX_CONST_SIZE`] is measured against.
743    #[inline]
744    pub(crate) fn len(&self) -> usize {
745        self.nodes.len()
746    }
747
748    /// Say that a subtree of `height` is complete at the level being built.
749    #[inline]
750    fn record(&mut self, height: u32) {
751        match self.levels.last_mut() {
752            Some(level) => *level = (*level).max(height),
753            None => self.height = self.height.max(height),
754        }
755    }
756
757    /// Append a node which has nothing below it.
758    #[inline]
759    pub(crate) fn leaf(&mut self, kind: ConstNodeKind) -> alloc::Result<()> {
760        self.nodes.try_push(ConstNode {
761            size: 1,
762            height: 1,
763            kind,
764        })?;
765
766        self.record(1);
767        Ok(())
768    }
769
770    /// Append a node whose subtrees are appended after it, handing back what
771    /// [`ConstBuilder::close`] needs.
772    #[inline]
773    pub(crate) fn open(&mut self, kind: ConstNodeKind) -> alloc::Result<usize> {
774        let at = self.nodes.len();
775
776        self.nodes.try_push(ConstNode {
777            size: 0,
778            height: 0,
779            kind,
780        })?;
781
782        self.levels.try_push(0)?;
783        Ok(at)
784    }
785
786    /// Say that everything below the node opened at `at` has been appended.
787    #[inline]
788    pub(crate) fn close(&mut self, at: usize) {
789        let below = self.levels.pop().unwrap_or(0);
790        let height = below.saturating_add(1);
791        let size = self.nodes.len().saturating_sub(at);
792
793        if let Some(node) = self.nodes.get_mut(at) {
794            node.size = size as u32;
795            node.height = height;
796        }
797
798        self.record(height);
799    }
800
801    /// Append a constant which has already been built, as it is.
802    #[inline]
803    pub(crate) fn extend(&mut self, value: &ConstValue) -> alloc::Result<()> {
804        self.nodes.try_reserve(value.as_nodes().len())?;
805
806        for node in value.as_nodes() {
807            self.nodes.try_push(node.try_clone()?)?;
808        }
809
810        self.record(value.height());
811        Ok(())
812    }
813
814    /// Take what has been built, checking that it is within the limits.
815    ///
816    /// Checking here is what makes the limits hold of *every* constant rather
817    /// than only of the ones built from a value: a host which nests one
818    /// constant inside another in a loop is bounded the same way a script is.
819    pub(crate) fn build(mut self) -> Result<ConstValueBuf, ConstNodesError> {
820        if self.nodes.is_empty() {
821            self.leaf(ConstNodeKind::Inline(Inline::Empty))?;
822        }
823
824        if self.nodes.len() > MAX_CONST_SIZE {
825            return Err(ConstNodesError::TooLarge {
826                max: MAX_CONST_SIZE,
827            });
828        }
829
830        if self.height as usize > MAX_CONST_DEPTH {
831            return Err(ConstNodesError::TooDeep {
832                max: MAX_CONST_DEPTH,
833            });
834        }
835
836        Ok(ConstValueBuf::from_vec(take(&mut self.nodes))?)
837    }
838}
839
840/// Formatting a constant, which walks it without recursing into it.
841mod debug {
842    use core::fmt;
843
844    use crate::alloc::{Box, Vec};
845    use crate::Hash;
846
847    use super::{ConstNodeKind, ConstValue};
848
849    /// A node whose subtrees are part way through being written.
850    struct Level<'a> {
851        /// How many of them are left.
852        remaining: usize,
853        /// How many there were, so that the one being written can be found.
854        total: usize,
855        /// What names them, if this is an object.
856        keys: Option<&'a [Box<str>]>,
857    }
858
859    pub(super) fn fmt(value: &ConstValue, f: &mut fmt::Formatter<'_>) -> fmt::Result {
860        // A constant nests as deeply as whoever built it made it, so the levels
861        // which are part way through are kept here rather than as native
862        // frames.
863        let mut levels = Vec::<Level<'_>>::new();
864
865        for node in value.as_nodes() {
866            if let Some(level) = levels.last_mut() {
867                let index = level.total - level.remaining;
868
869                if index > 0 {
870                    write!(f, ", ")?;
871                }
872
873                if let Some(key) = level.keys.and_then(|keys| keys.get(index)) {
874                    write!(f, "{key:?}: ")?;
875                }
876
877                level.remaining -= 1;
878            }
879
880            let level = match &node.kind {
881                ConstNodeKind::Inline(value) => {
882                    write!(f, "{value:?}")?;
883                    None
884                }
885                ConstNodeKind::String(value) => {
886                    write!(f, "{value:?}")?;
887                    None
888                }
889                ConstNodeKind::Bytes(value) => {
890                    write!(f, "{value:?}")?;
891                    None
892                }
893                ConstNodeKind::Instance {
894                    hash,
895                    variant_hash,
896                    fields,
897                } => {
898                    if *variant_hash == Hash::EMPTY {
899                        write!(f, "{hash}(")?;
900                    } else {
901                        write!(f, "{hash}::{variant_hash}(")?;
902                    }
903
904                    Some(Level {
905                        remaining: *fields as usize,
906                        total: *fields as usize,
907                        keys: None,
908                    })
909                }
910                ConstNodeKind::Object { keys } => {
911                    write!(f, "#{{")?;
912
913                    Some(Level {
914                        remaining: keys.len(),
915                        total: keys.len(),
916                        keys: Some(keys),
917                    })
918                }
919            };
920
921            if let Some(level) = level {
922                levels.try_push(level).map_err(|_| fmt::Error)?;
923            }
924
925            // Close every level which the node just written completed,
926            // innermost first.
927            while levels.last().is_some_and(|level| level.remaining == 0) {
928                let Some(level) = levels.pop() else {
929                    break;
930                };
931
932                if level.keys.is_some() {
933                    write!(f, "}}")?;
934                } else {
935                    write!(f, ")")?;
936                }
937            }
938        }
939
940        Ok(())
941    }
942}