Skip to main content

rune/runtime/
const_value.rs

1#[macro_use]
2mod macros;
3
4mod node;
5
6pub(crate) use self::node::{ConstBuilder, ConstNodeKind, ConstNodesError};
7pub use self::node::{ConstFields, ConstFieldsIter, ConstValue, ConstValueBuf};
8
9use core::any;
10use core::cmp::Ordering;
11
12use crate::alloc;
13use crate::alloc::prelude::*;
14use crate::runtime;
15use crate::{declare_dyn_trait, hash_in, Hash, TypeHash};
16
17use super::{
18    Bytes, ExpectedType, FromValue, Inline, Object, OwnedTuple, Repr, RuntimeError, ToValue, Tuple,
19    Type, Value, VmErrorKind, VmIntegerRepr,
20};
21
22/// How deeply a [`ConstValue`] is allowed to nest.
23///
24/// A constant is stored as one array rather than as a tree, so nesting no
25/// longer costs a native frame to build or to take apart. What it still costs
26/// is everything which has to *understand* the nesting - lowering a constant
27/// into instructions, turning one into a pattern - so how deep one may be is
28/// still bounded, and the bound is checked once, where the array is built or
29/// read back.
30///
31/// This is the ceiling the `max-const-depth` option is measured against. The
32/// option can lower the effective bound but not raise it past this.
33pub(crate) const MAX_CONST_DEPTH: usize = 128;
34
35/// How many values a [`ConstValue`] is allowed to be made of.
36///
37/// The value a constant is converted from shares what it is made of - a value
38/// used twice is one allocation pointed at twice - while a `ConstValue` is a
39/// tree which owns each of its parts outright. So converting one expands a graph
40/// into a tree, and a constant function which does nothing more suspicious than
41/// `let v = f(n - 1); [v, v]` produces a value which is linear to evaluate and
42/// exponential to convert. Depth does not catch it: that shape is only `n` deep.
43///
44/// Nothing else bounds it. `const-budget` bounds the instructions evaluation is
45/// allowed to run, and the doubling above needs a handful per level.
46pub(crate) const MAX_CONST_SIZE: usize = 1 << 16;
47/// Derive for the [`ToConstValue`] trait.
48///
49/// This is principally used for associated constants in native modules, since
50/// Rune has to be provided a constant-compatible method for constructing values
51/// of the given type.
52///
53/// [`ToConstValue`]: trait@crate::ToConstValue
54///
55/// # Examples
56///
57/// ```
58/// use rune::{docstring, Any, ContextError, Module, ToConstValue};
59///
60/// #[derive(Any, ToConstValue)]
61/// pub struct Duration {
62///     #[const_value(with = const_duration)]
63///     inner: std::time::Duration,
64/// }
65///
66/// mod const_duration {
67///     use rune::runtime::{ConstValue, ConstValueBuf, RuntimeError, Value};
68///     use std::time::Duration;
69///
70///     #[inline]
71///     pub(super) fn to_const_value(duration: Duration) -> Result<ConstValueBuf, RuntimeError> {
72///         let secs = duration.as_secs();
73///         let nanos = duration.subsec_nanos();
74///         rune::to_const_value((secs, nanos))
75///     }
76///
77///     #[inline]
78///     pub(super) fn from_const_value(value: &ConstValue) -> Result<Duration, RuntimeError> {
79///         let (secs, nanos) = rune::from_const_value::<(u64, u32)>(value)?;
80///         Ok(Duration::new(secs, nanos))
81///     }
82///
83///     #[inline]
84///     pub(super) fn from_value(value: Value) -> Result<Duration, RuntimeError> {
85///         let (secs, nanos) = rune::from_value::<(u64, u32)>(value)?;
86///         Ok(Duration::new(secs, nanos))
87///     }
88/// }
89///
90/// #[rune::module(::time)]
91/// pub fn module() -> Result<Module, ContextError> {
92///     let mut m = Module::from_meta(module__meta)?;
93///     m.ty::<Duration>()?;
94///
95///     m
96///         .constant(
97///             "SECOND",
98///             Duration {
99///                 inner: std::time::Duration::from_secs(1),
100///             },
101///         )
102///         .build_associated::<Duration>()?
103///         .docs(docstring! {
104///             /// The duration of one second.
105///             ///
106///             /// # Examples
107///             ///
108///             /// ```rune
109///             /// use time::Duration;
110///             ///
111///             /// let duration = Duration::SECOND;
112///             /// ```
113///         })?;
114///
115///     Ok(m)
116/// }
117/// ```
118pub use rune_macros::ToConstValue;
119
120/// An array which does not describe a constant within the limits is reported
121/// the way anything else the machine turns away is.
122impl From<ConstNodesError> for RuntimeError {
123    fn from(error: ConstNodesError) -> Self {
124        match error {
125            #[cfg(any(feature = "serde", feature = "musli"))]
126            ConstNodesError::Empty | ConstNodesError::Malformed => {
127                RuntimeError::new(VmErrorKind::MalformedConstValue)
128            }
129            ConstNodesError::TooDeep { max } => {
130                RuntimeError::new(VmErrorKind::MaxConstDepth { max })
131            }
132            ConstNodesError::TooLarge { max } => {
133                RuntimeError::new(VmErrorKind::MaxConstSize { max })
134            }
135            ConstNodesError::Alloc(error) => RuntimeError::from(error),
136        }
137    }
138}
139
140/// Convert something into a [`ConstValueBuf`].
141///
142/// # Examples
143///
144/// ```
145/// let value = rune::to_const_value((i32::MIN, u64::MAX))?;
146/// let (a, b) = rune::from_const_value::<(i32, u64)>(&value)?;
147///
148/// assert_eq!(a, i32::MIN);
149/// assert_eq!(b, u64::MAX);
150/// # Ok::<_, rune::support::Error>(())
151/// ```
152pub fn from_const_value<T>(value: impl AsRef<ConstValue>) -> Result<T, RuntimeError>
153where
154    T: FromConstValue,
155{
156    T::from_const_value(value.as_ref())
157}
158
159/// Convert something into a [`ConstValueBuf`].
160///
161/// # Examples
162///
163/// ```
164/// let value = rune::to_const_value((i32::MIN, u64::MAX))?;
165/// let (a, b) = rune::from_const_value::<(i32, u64)>(&value)?;
166///
167/// assert_eq!(a, i32::MIN);
168/// assert_eq!(b, u64::MAX);
169/// # Ok::<_, rune::support::Error>(())
170/// ```
171pub fn to_const_value(value: impl ToConstValue) -> Result<ConstValueBuf, RuntimeError> {
172    value.to_const_value()
173}
174
175/// Trait to perform a conversion to a [`ConstValueBuf`].
176pub trait ToConstValue: Sized {
177    /// Convert into a constant value.
178    fn to_const_value(self) -> Result<ConstValueBuf, RuntimeError>;
179
180    /// Return the constant constructor for the given type.
181    #[inline]
182    #[doc(hidden)]
183    fn construct() -> alloc::Result<Option<ConstConstructImpl>> {
184        Ok(None)
185    }
186}
187
188impl ToConstValue for ConstValueBuf {
189    #[inline]
190    fn to_const_value(self) -> Result<ConstValueBuf, RuntimeError> {
191        Ok(self)
192    }
193}
194
195impl ToConstValue for &ConstValue {
196    #[inline]
197    fn to_const_value(self) -> Result<ConstValueBuf, RuntimeError> {
198        Ok(self.try_to_owned()?)
199    }
200}
201
202impl ToConstValue for Value {
203    #[inline]
204    fn to_const_value(self) -> Result<ConstValueBuf, RuntimeError> {
205        ConstValueBuf::from_value_ref(&self)
206    }
207}
208
209impl ConstValueBuf {
210    /// Construct a constant value that is a string.
211    pub fn string(value: impl AsRef<str>) -> Result<ConstValueBuf, RuntimeError> {
212        let value = alloc::Box::try_from(value.as_ref())?;
213        Ok(Self::from_kind(ConstNodeKind::String(value)))
214    }
215
216    /// Construct a constant value that is bytes.
217    pub fn bytes(value: impl AsRef<[u8]>) -> Result<ConstValueBuf, RuntimeError> {
218        let value = alloc::Box::try_from(value.as_ref())?;
219        Ok(Self::from_kind(ConstNodeKind::Bytes(value)))
220    }
221
222    /// Construct a new tuple constant value.
223    pub fn tuple<I>(fields: I) -> Result<ConstValueBuf, RuntimeError>
224    where
225        I: IntoIterator,
226        I::Item: AsRef<ConstValue>,
227        I::IntoIter: ExactSizeIterator,
228    {
229        Self::instance(OwnedTuple::HASH, Hash::EMPTY, fields)
230    }
231
232    /// Construct a constant value for a struct.
233    pub fn for_struct<const N: usize>(
234        hash: Hash,
235        fields: [ConstValueBuf; N],
236    ) -> Result<ConstValueBuf, RuntimeError> {
237        Self::instance(hash, Hash::EMPTY, fields)
238    }
239
240    /// Construct an instance of `hash` out of the constants it is made of,
241    /// which are laid down after it in the order they are given.
242    pub(crate) fn instance<I>(
243        hash: Hash,
244        variant_hash: Hash,
245        fields: I,
246    ) -> Result<ConstValueBuf, RuntimeError>
247    where
248        I: IntoIterator,
249        I::Item: AsRef<ConstValue>,
250        I::IntoIter: ExactSizeIterator,
251    {
252        let fields = fields.into_iter();
253
254        let mut builder = ConstBuilder::new();
255
256        let at = builder.open(ConstNodeKind::Instance {
257            hash,
258            variant_hash,
259            fields: fields.len() as u32,
260        })?;
261
262        for field in fields {
263            builder.extend(field.as_ref())?;
264        }
265
266        builder.close(at);
267        Ok(builder.build()?)
268    }
269
270    /// Construct a constant value from a reference to a value.
271    ///
272    /// The walk is bounded before it descends, which is what keeps a value
273    /// whose depth a script decided from costing a native frame per level.
274    pub(crate) fn from_value_ref(value: &Value) -> Result<ConstValueBuf, RuntimeError> {
275        let mut builder = ConstBuilder::new();
276        from_value_ref_at(value, 0, &mut builder)?;
277        Ok(builder.build()?)
278    }
279}
280
281/// Append the constant `value` describes to `builder`, having already descended
282/// `depth` levels into the value the conversion started at.
283fn from_value_ref_at(
284    value: &Value,
285    depth: usize,
286    builder: &mut ConstBuilder,
287) -> Result<(), RuntimeError> {
288    if depth >= MAX_CONST_DEPTH {
289        return Err(RuntimeError::new(VmErrorKind::MaxConstDepth {
290            max: MAX_CONST_DEPTH,
291        }));
292    }
293
294    // Counted here rather than per container so that what is bounded is
295    // what is actually built, whatever shape it is in.
296    if builder.len() >= MAX_CONST_SIZE {
297        return Err(RuntimeError::new(VmErrorKind::MaxConstSize {
298            max: MAX_CONST_SIZE,
299        }));
300    }
301
302    let depth = depth + 1;
303
304    match value.as_ref() {
305        Repr::Inline(value) => {
306            builder.leaf(ConstNodeKind::Inline(*value))?;
307        }
308        Repr::Dynamic(value) => {
309            return Err(RuntimeError::from(VmErrorKind::ConstNotSupported {
310                actual: value.type_info(),
311            }));
312        }
313        Repr::Any(value) => match value.type_hash() {
314            alloc::String::HASH => {
315                let string = value.borrow_ref::<alloc::String>()?;
316                builder.leaf(ConstNodeKind::String(alloc::Box::try_from(
317                    string.as_str(),
318                )?))?;
319            }
320            Bytes::HASH => {
321                let bytes = value.borrow_ref::<Bytes>()?;
322                builder.leaf(ConstNodeKind::Bytes(alloc::Box::try_from(
323                    bytes.as_slice(),
324                )?))?;
325            }
326            OwnedTuple::HASH => {
327                let tuple = value.borrow_ref::<OwnedTuple>()?;
328
329                let at = builder.open(ConstNodeKind::Instance {
330                    hash: OwnedTuple::HASH,
331                    variant_hash: Hash::EMPTY,
332                    fields: tuple.len() as u32,
333                })?;
334
335                for value in tuple.iter() {
336                    from_value_ref_at(value, depth, builder)?;
337                }
338
339                builder.close(at);
340            }
341            Object::HASH => {
342                let object = value.borrow_ref::<Object>()?;
343
344                let mut keys = alloc::Vec::try_with_capacity(object.len())?;
345
346                for key in object.keys() {
347                    keys.try_push(alloc::Box::try_from(key.as_str())?)?;
348                }
349
350                // The keys are stored in the order they are read back in, so
351                // that nothing which walks a constant has to sort them again.
352                keys.sort();
353
354                let at = builder.open(ConstNodeKind::Object {
355                    keys: keys.try_clone()?.try_into_boxed_slice()?,
356                })?;
357
358                for key in keys.iter() {
359                    let Some(value) = object.get(key.as_ref()) else {
360                        return Err(RuntimeError::new(VmErrorKind::MalformedConstValue));
361                    };
362
363                    from_value_ref_at(value, depth, builder)?;
364                }
365
366                builder.close(at);
367            }
368            Option::<Value>::HASH => {
369                let option = value.borrow_ref::<Option<Value>>()?;
370
371                match &*option {
372                    Some(some) => {
373                        let at = builder.open(ConstNodeKind::Instance {
374                            hash: Option::<Value>::HASH,
375                            variant_hash: hash_in!(crate, ::std::option::Option::Some),
376                            fields: 1,
377                        })?;
378
379                        from_value_ref_at(some, depth, builder)?;
380                        builder.close(at);
381                    }
382                    None => {
383                        builder.leaf(ConstNodeKind::Instance {
384                            hash: Option::<Value>::HASH,
385                            variant_hash: hash_in!(crate, ::std::option::Option::None),
386                            fields: 0,
387                        })?;
388                    }
389                }
390            }
391            runtime::Vec::HASH => {
392                let vec = value.borrow_ref::<runtime::Vec>()?;
393
394                let at = builder.open(ConstNodeKind::Instance {
395                    hash: runtime::Vec::HASH,
396                    variant_hash: Hash::EMPTY,
397                    fields: vec.len() as u32,
398                })?;
399
400                for value in vec.iter() {
401                    from_value_ref_at(value, depth, builder)?;
402                }
403
404                builder.close(at);
405            }
406            _ => {
407                return Err(RuntimeError::from(VmErrorKind::ConstNotSupported {
408                    actual: value.type_info(),
409                }));
410            }
411        },
412    }
413
414    Ok(())
415}
416
417impl ConstValue {
418    /// Try to coerce the current value as the specified integer `T`.
419    ///
420    /// # Examples
421    ///
422    /// ```
423    /// let value = rune::to_const_value(u32::MAX)?;
424    ///
425    /// assert_eq!(value.as_integer::<u64>()?, u32::MAX as u64);
426    /// assert!(value.as_integer::<i32>().is_err());
427    ///
428    /// # Ok::<(), rune::support::Error>(())
429    /// ```
430    pub fn as_integer<T>(&self) -> Result<T, RuntimeError>
431    where
432        T: TryFrom<i64> + TryFrom<u64>,
433    {
434        match self.kind() {
435            ConstNodeKind::Inline(Inline::Signed(value)) => match (*value).try_into() {
436                Ok(number) => Ok(number),
437                Err(..) => Err(RuntimeError::new(
438                    VmErrorKind::ValueToIntegerCoercionError {
439                        from: VmIntegerRepr::from(*value),
440                        to: any::type_name::<T>(),
441                    },
442                )),
443            },
444            ConstNodeKind::Inline(Inline::Unsigned(value)) => match (*value).try_into() {
445                Ok(number) => Ok(number),
446                Err(..) => Err(RuntimeError::new(
447                    VmErrorKind::ValueToIntegerCoercionError {
448                        from: VmIntegerRepr::from(*value),
449                        to: any::type_name::<T>(),
450                    },
451                )),
452            },
453            kind => Err(RuntimeError::new(VmErrorKind::ExpectedNumber {
454                actual: kind.type_info(),
455            })),
456        }
457    }
458
459    inline_macros!(inline_into);
460
461    /// Coerce into the string this is, if it is one.
462    pub fn as_string(&self) -> Result<&str, ExpectedType> {
463        let ConstNodeKind::String(value) = self.kind() else {
464            return Err(ExpectedType::new::<alloc::String>(self.type_info()));
465        };
466
467        Ok(value)
468    }
469
470    /// Coerce into the fields of the tuple this is, if it is one.
471    pub fn as_tuple(&self) -> Result<ConstFields<'_>, ExpectedType> {
472        let ConstNodeKind::Instance {
473            hash: OwnedTuple::HASH,
474            variant_hash: Hash::EMPTY,
475            ..
476        } = self.kind()
477        else {
478            return Err(ExpectedType::new::<Tuple>(self.type_info()));
479        };
480
481        Ok(self.fields())
482    }
483
484    /// Convert into virtual machine value.
485    ///
486    /// We provide this associated method since a constant value can be
487    /// converted into a value infallibly, which is not captured by the trait
488    /// otherwise.
489    ///
490    /// The walk is a single pass over the array the constant is stored as, with
491    /// the containers which are part way through kept on a work stack, so a
492    /// constant which nests deeply costs memory rather than native frames.
493    pub(crate) fn to_value_with(&self, cx: &dyn ConstContext) -> Result<Value, RuntimeError> {
494        /// A container whose values are still being built.
495        struct Frame<'a> {
496            kind: FrameKind<'a>,
497            remaining: usize,
498            values: alloc::Vec<Value>,
499        }
500
501        enum FrameKind<'a> {
502            Tuple,
503            Vec,
504            Object(&'a [alloc::Box<str>]),
505            Some,
506        }
507
508        fn close(frame: Frame<'_>) -> Result<Value, RuntimeError> {
509            match frame.kind {
510                FrameKind::Tuple => Ok(Value::try_from(OwnedTuple::try_from(frame.values)?)?),
511                FrameKind::Vec => Ok(Value::try_from(runtime::Vec::from(frame.values))?),
512                FrameKind::Object(keys) => {
513                    let mut object = Object::with_capacity(keys.len())?;
514
515                    for (key, value) in keys.iter().zip(frame.values) {
516                        object.insert(alloc::String::try_from(key.as_ref())?, value)?;
517                    }
518
519                    Ok(Value::try_from(object)?)
520                }
521                FrameKind::Some => {
522                    let mut values = frame.values.into_iter();
523
524                    let Some(value) = values.next() else {
525                        return Err(RuntimeError::new(VmErrorKind::MalformedConstValue));
526                    };
527
528                    Ok(Value::try_from(Some(value))?)
529                }
530            }
531        }
532
533        fn open<'a>(kind: FrameKind<'a>, len: usize) -> Result<Frame<'a>, RuntimeError> {
534            Ok(Frame {
535                kind,
536                remaining: len,
537                values: alloc::Vec::try_with_capacity(len)?,
538            })
539        }
540
541        let nodes = self.as_nodes();
542        let mut frames = alloc::Vec::<Frame<'_>>::new();
543        let mut index = 0;
544
545        loop {
546            let Some(node) = nodes.get(index) else {
547                return Err(RuntimeError::new(VmErrorKind::MalformedConstValue));
548            };
549
550            // What the node produces outright, if anything - a node which opens
551            // a container produces nothing until the container is closed.
552            let mut produced = None;
553
554            match &node.kind {
555                ConstNodeKind::Inline(value) => {
556                    produced = Some(Value::from(*value));
557                    index += 1;
558                }
559                ConstNodeKind::String(string) => {
560                    produced = Some(Value::try_from(string.as_ref())?);
561                    index += 1;
562                }
563                ConstNodeKind::Bytes(bytes) => {
564                    produced = Some(Value::try_from(bytes.as_ref())?);
565                    index += 1;
566                }
567                ConstNodeKind::Object { keys } => {
568                    frames.try_push(open(FrameKind::Object(keys), keys.len())?)?;
569                    index += 1;
570                }
571                ConstNodeKind::Instance {
572                    hash,
573                    variant_hash,
574                    fields,
575                } => {
576                    let fields = *fields as usize;
577
578                    match (*hash, *variant_hash) {
579                        (OwnedTuple::HASH, Hash::EMPTY) => {
580                            frames.try_push(open(FrameKind::Tuple, fields)?)?;
581                            index += 1;
582                        }
583                        (runtime::Vec::HASH, Hash::EMPTY) => {
584                            frames.try_push(open(FrameKind::Vec, fields)?)?;
585                            index += 1;
586                        }
587                        (Option::<Value>::HASH, variant_hash) => {
588                            match (variant_hash, fields) {
589                                (hash_in!(crate, ::std::option::Option::Some), 1) => {
590                                    frames.try_push(open(FrameKind::Some, 1)?)?;
591                                }
592                                (hash_in!(crate, ::std::option::Option::None), 0) => {
593                                    produced = Some(Value::try_from(None)?);
594                                }
595                                _ => {
596                                    return Err(RuntimeError::missing_constant_constructor(*hash));
597                                }
598                            }
599
600                            index += 1;
601                        }
602                        (hash, _) => {
603                            // A type which is only known to whoever declared it
604                            // builds itself out of the constants it is made of,
605                            // so its subtree is handed over whole rather than
606                            // walked into here.
607                            let Some(constructor) = cx.get(hash) else {
608                                return Err(RuntimeError::missing_constant_constructor(hash));
609                            };
610
611                            let size = node.size as usize;
612
613                            let Some(subtree) = nodes.get(index..index + size) else {
614                                return Err(RuntimeError::new(VmErrorKind::MalformedConstValue));
615                            };
616
617                            produced =
618                                Some(constructor.const_construct(ConstValue::from_nodes(subtree))?);
619
620                            index += size;
621                        }
622                    }
623                }
624            }
625
626            // Hand what was produced to the container which was waiting for it,
627            // and close every container which that completed.
628            loop {
629                if let Some(value) = produced.take() {
630                    let Some(frame) = frames.last_mut() else {
631                        return Ok(value);
632                    };
633
634                    frame.values.try_push(value)?;
635                    frame.remaining -= 1;
636                }
637
638                if !frames.last().is_some_and(|frame| frame.remaining == 0) {
639                    break;
640                }
641
642                let Some(frame) = frames.pop() else {
643                    break;
644                };
645
646                produced = Some(close(frame)?);
647            }
648        }
649    }
650}
651
652impl FromValue for ConstValueBuf {
653    #[inline]
654    fn from_value(value: Value) -> Result<Self, RuntimeError> {
655        ConstValueBuf::from_value_ref(&value)
656    }
657}
658
659impl ToValue for ConstValueBuf {
660    #[inline]
661    fn to_value(self) -> Result<Value, RuntimeError> {
662        ConstValue::to_value_with(&self, &EmptyConstContext)
663    }
664}
665
666impl ConstValue {
667    #[inline]
668    #[cfg(test)]
669    pub(crate) fn to_value(&self) -> Result<Value, RuntimeError> {
670        self.to_value_with(&EmptyConstContext)
671    }
672}
673
674impl AsRef<ConstValue> for ConstValue {
675    #[inline]
676    fn as_ref(&self) -> &ConstValue {
677        self
678    }
679}
680
681impl From<Inline> for ConstValueBuf {
682    #[inline]
683    fn from(value: Inline) -> Self {
684        ConstValueBuf::from_kind(ConstNodeKind::Inline(value))
685    }
686}
687
688impl TryFrom<alloc::String> for ConstValueBuf {
689    type Error = alloc::Error;
690
691    #[inline]
692    fn try_from(value: alloc::String) -> Result<Self, Self::Error> {
693        Ok(Self::from_kind(ConstNodeKind::String(
694            alloc::Box::try_from(value)?,
695        )))
696    }
697}
698
699impl TryFrom<alloc::Box<str>> for ConstValueBuf {
700    type Error = alloc::Error;
701
702    #[inline]
703    fn try_from(value: alloc::Box<str>) -> Result<Self, Self::Error> {
704        Ok(Self::from_kind(ConstNodeKind::String(value)))
705    }
706}
707
708impl TryFrom<Bytes> for ConstValueBuf {
709    type Error = alloc::Error;
710
711    #[inline]
712    fn try_from(value: Bytes) -> Result<Self, Self::Error> {
713        Self::try_from(value.as_slice())
714    }
715}
716
717impl TryFrom<&str> for ConstValueBuf {
718    type Error = alloc::Error;
719
720    #[inline]
721    fn try_from(value: &str) -> Result<Self, Self::Error> {
722        Ok(Self::from_kind(ConstNodeKind::String(
723            alloc::Box::try_from(value)?,
724        )))
725    }
726}
727
728impl ToConstValue for &str {
729    #[inline]
730    fn to_const_value(self) -> Result<ConstValueBuf, RuntimeError> {
731        Ok(ConstValueBuf::try_from(self)?)
732    }
733}
734
735impl TryFrom<alloc::Box<[u8]>> for ConstValueBuf {
736    type Error = alloc::Error;
737
738    #[inline]
739    fn try_from(value: alloc::Box<[u8]>) -> Result<Self, Self::Error> {
740        Ok(Self::from_kind(ConstNodeKind::Bytes(value)))
741    }
742}
743
744impl TryFrom<&[u8]> for ConstValueBuf {
745    type Error = alloc::Error;
746
747    #[inline]
748    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
749        Ok(Self::from_kind(ConstNodeKind::Bytes(alloc::Box::try_from(
750            value,
751        )?)))
752    }
753}
754
755impl ToConstValue for &[u8] {
756    #[inline]
757    fn to_const_value(self) -> Result<ConstValueBuf, RuntimeError> {
758        Ok(ConstValueBuf::try_from(self)?)
759    }
760}
761
762/// Trait to perform a conversion from a [`ConstValue`].
763pub trait FromConstValue: Sized {
764    /// Convert from a constant value.
765    fn from_const_value(value: &ConstValue) -> Result<Self, RuntimeError>;
766}
767
768impl FromConstValue for ConstValueBuf {
769    #[inline]
770    fn from_const_value(value: &ConstValue) -> Result<Self, RuntimeError> {
771        Ok(value.try_to_owned()?)
772    }
773}
774
775impl FromConstValue for bool {
776    #[inline]
777    fn from_const_value(value: &ConstValue) -> Result<Self, RuntimeError> {
778        value.as_bool()
779    }
780}
781
782impl FromConstValue for char {
783    #[inline]
784    fn from_const_value(value: &ConstValue) -> Result<Self, RuntimeError> {
785        value.as_char()
786    }
787}
788
789macro_rules! impl_integer {
790    ($($ty:ty),* $(,)?) => {
791        $(
792            impl FromConstValue for $ty {
793                #[inline]
794                fn from_const_value(value: &ConstValue) -> Result<Self, RuntimeError> {
795                    value.as_integer()
796                }
797            }
798        )*
799    };
800}
801
802impl_integer!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
803
804declare_dyn_trait! {
805    /// The vtable for constant constructors.
806    struct ConstConstructVtable;
807
808    /// The implementation wrapper for a constant constructor.
809    pub struct ConstConstructImpl;
810
811    /// Implementation of a constant constructor.
812    ///
813    /// Do not implement manually, this is provided when deriving [`ToConstValue`].
814    ///
815    /// [`ToConstValue`]: derive@ToConstValue
816    pub trait ConstConstruct {
817        /// Construct from the constant which describes the instance, whose
818        /// fields are the subtrees it is made of.
819        #[doc(hidden)]
820        fn const_construct(&self, value: &ConstValue) -> Result<Value, RuntimeError>;
821
822        /// Construct from values.
823        #[doc(hidden)]
824        fn runtime_construct(&self, fields: &mut [Value]) -> Result<Value, RuntimeError>;
825    }
826}
827
828pub(crate) trait ConstContext {
829    fn get(&self, hash: Hash) -> Option<&ConstConstructImpl>;
830}
831
832pub(crate) struct EmptyConstContext;
833
834impl ConstContext for EmptyConstContext {
835    #[inline]
836    fn get(&self, _: Hash) -> Option<&ConstConstructImpl> {
837        None
838    }
839}