aranya_policy_module/
data.rs

1extern crate alloc;
2
3use alloc::{borrow::ToOwned as _, collections::BTreeMap, format, string::String, vec, vec::Vec};
4use core::fmt::{self, Display};
5
6pub use aranya_id::BaseId;
7use aranya_id::{Id, IdTag};
8use aranya_policy_ast::{Ident, Identifier, Span, Text, TypeKind, VType};
9use serde::{Deserialize, Serialize};
10
11use super::ffi::Type;
12
13#[derive(Debug, thiserror::Error)]
14/// Indicates that the Value conversion has failed
15pub enum ValueConversionError {
16    /// A conversion was attempted to a type that is not compatible with this Value
17    #[error("expected type {want}, but got {got}: {msg}")]
18    InvalidType {
19        /// Expected type name
20        want: String,
21        /// Received type name
22        got: String,
23        /// Extra information
24        msg: String,
25    },
26    /// A struct conversion found a field mismatch between types
27    #[error("invalid struct member `{0}`")]
28    InvalidStructMember(Identifier),
29    /// The target type does not have sufficient range to represent this Value
30    #[error("value out of range")]
31    OutOfRange,
32    /// Some internal state is corrupt
33    #[error("bad state")]
34    BadState,
35}
36
37impl ValueConversionError {
38    /// Constructs an `InvalidType` error
39    pub fn invalid_type(
40        want: impl Into<String>,
41        got: impl Into<String>,
42        msg: impl Into<String>,
43    ) -> Self {
44        Self::InvalidType {
45            want: want.into(),
46            got: got.into(),
47            msg: msg.into(),
48        }
49    }
50}
51
52/// Allows a type to be used by FFI derive.
53// TODO(eric): move this into `super::ffi`?
54pub trait Typed {
55    /// Indicates the type of the type.
56    const TYPE: Type<'static>;
57}
58
59macro_rules! impl_typed {
60    ($name:ty => $type:ident) => {
61        impl Typed for $name {
62            const TYPE: Type<'static> = Type::$type;
63        }
64    };
65}
66
67impl_typed!(Text => String);
68
69impl_typed!(Vec<u8> => Bytes);
70impl_typed!(&[u8] => Bytes);
71
72impl_typed!(isize => Int);
73impl_typed!(i64 => Int);
74impl_typed!(i32 => Int);
75impl_typed!(i16 => Int);
76impl_typed!(i8 => Int);
77
78impl_typed!(usize => Int);
79impl_typed!(u64 => Int);
80impl_typed!(u32 => Int);
81impl_typed!(u16 => Int);
82impl_typed!(u8 => Int);
83
84impl_typed!(bool => Bool);
85
86impl<Tag: IdTag> Typed for Id<Tag> {
87    const TYPE: Type<'static> = Type::Id;
88}
89
90impl<T: Typed> Typed for Option<T> {
91    const TYPE: Type<'static> = Type::Optional(const { &T::TYPE });
92}
93
94/// All of the value types allowed in the VM
95#[derive(
96    Debug,
97    Clone,
98    PartialEq,
99    Eq,
100    Serialize,
101    Deserialize,
102    rkyv::Archive,
103    rkyv::Deserialize,
104    rkyv::Serialize,
105)]
106#[rkyv(serialize_bounds(
107    __S: rkyv::ser::Writer + rkyv::ser::Allocator,
108    __S::Error: rkyv::rancor::Source,
109))]
110#[rkyv(deserialize_bounds(__D::Error: rkyv::rancor::Source))]
111#[rkyv(bytecheck(
112    bounds(
113        __C: rkyv::validation::ArchiveContext,
114        __C::Error: rkyv::rancor::Source,
115    )
116))]
117pub enum Value {
118    /// Integer (64-bit signed)
119    Int(i64),
120    /// Boolean
121    Bool(bool),
122    /// String (UTF-8)
123    String(Text),
124    /// Bytes
125    Bytes(Vec<u8>),
126    /// Struct
127    Struct(#[rkyv(omit_bounds)] Struct),
128    /// Fact
129    Fact(Fact),
130    /// A unique identifier.
131    Id(BaseId),
132    /// Enumeration value
133    Enum(Identifier, i64),
134    /// Textual Identifier (name)
135    Identifier(Identifier),
136    /// Empty optional value
137    None,
138}
139
140/// Trait for converting from a [`Value`], similar to [`TryFrom<Value>`].
141///
142/// This trait allows us to add a blanket impl for `Option`, which we cannot
143/// do for `TryFrom<Value>` because of overlap and foreign type restrictions.
144pub trait TryFromValue: Sized {
145    /// Tries to convert a [`Value`] into `Self`.
146    fn try_from_value(value: Value) -> Result<Self, ValueConversionError>;
147}
148
149impl<T: TryFromValue> TryFromValue for Option<T> {
150    fn try_from_value(value: Value) -> Result<Self, ValueConversionError> {
151        if matches!(value, Value::None) {
152            Ok(None)
153        } else {
154            T::try_from_value(value).map(Some)
155        }
156    }
157}
158
159impl<T: TryFrom<Value, Error = ValueConversionError>> TryFromValue for T {
160    fn try_from_value(value: Value) -> Result<Self, ValueConversionError> {
161        Self::try_from(value)
162    }
163}
164
165/// Like `AsMut`, but fallible.
166pub trait TryAsMut<T: ?Sized> {
167    /// The error result.
168    type Error;
169
170    /// Converts this type into a mutable reference of the
171    /// (usually inferred) input type.
172    fn try_as_mut(&mut self) -> Result<&mut T, Self::Error>;
173}
174
175impl Value {
176    /// Get the [`TypeKind`], if possible.
177    pub fn vtype(&self) -> Option<TypeKind> {
178        match self {
179            Self::Int(_) => Some(TypeKind::Int),
180            Self::Bool(_) => Some(TypeKind::Bool),
181            Self::String(_) => Some(TypeKind::String),
182            Self::Bytes(_) => Some(TypeKind::Bytes),
183            Self::Id(_) => Some(TypeKind::Id),
184            Self::Enum(name, _) => Some(TypeKind::Enum(Ident {
185                name: name.to_owned(),
186                span: Span::default(),
187            })),
188            Self::Struct(s) => Some(TypeKind::Struct(Ident {
189                name: s.name.clone(),
190                span: Span::default(),
191            })),
192            _ => None,
193        }
194    }
195
196    /// Returns a string representing the value's type.
197    pub fn type_name(&self) -> String {
198        match self {
199            Self::Int(_) => String::from("Int"),
200            Self::Bool(_) => String::from("Bool"),
201            Self::String(_) => String::from("String"),
202            Self::Bytes(_) => String::from("Bytes"),
203            Self::Struct(s) => format!("Struct {}", s.name),
204            Self::Fact(f) => format!("Fact {}", f.name),
205            Self::Id(_) => String::from("Id"),
206            Self::Enum(name, _) => format!("Enum {}", name),
207            Self::Identifier(_) => String::from("Identifier"),
208            Self::None => String::from("None"),
209        }
210    }
211
212    /// Checks to see if a [`Value`] matches some [`VType`]
213    /// ```
214    /// use aranya_policy_ast::{Span, TypeKind, VType};
215    /// use aranya_policy_module::Value;
216    ///
217    /// let value = Value::Int(1);
218    /// let int_type = VType {
219    ///     kind: TypeKind::Int,
220    ///     span: Span::empty(),
221    /// };
222    ///
223    /// assert!(value.fits_type(&int_type));
224    /// ```
225    pub fn fits_type(&self, expected_type: &VType) -> bool {
226        use aranya_policy_ast::TypeKind;
227        match (self.vtype(), &expected_type.kind) {
228            (None, TypeKind::Optional(_)) => true,
229            (None, _) => false,
230            (Some(vtype), TypeKind::Optional(inner)) => vtype.matches(&inner.kind),
231            (Some(vtype), kind) => vtype.matches(kind),
232        }
233    }
234}
235
236impl<T: Into<Self>> From<Option<T>> for Value {
237    fn from(value: Option<T>) -> Self {
238        value.map_or(Self::None, Into::into)
239    }
240}
241
242impl From<i64> for Value {
243    fn from(value: i64) -> Self {
244        Self::Int(value)
245    }
246}
247
248impl From<bool> for Value {
249    fn from(value: bool) -> Self {
250        Self::Bool(value)
251    }
252}
253
254impl From<Text> for Value {
255    fn from(value: Text) -> Self {
256        Self::String(value)
257    }
258}
259
260impl From<Identifier> for Value {
261    fn from(value: Identifier) -> Self {
262        Self::Identifier(value)
263    }
264}
265
266impl From<&[u8]> for Value {
267    fn from(value: &[u8]) -> Self {
268        Self::Bytes(value.to_owned())
269    }
270}
271
272impl From<Vec<u8>> for Value {
273    fn from(value: Vec<u8>) -> Self {
274        Self::Bytes(value)
275    }
276}
277
278impl From<Struct> for Value {
279    fn from(value: Struct) -> Self {
280        Self::Struct(value)
281    }
282}
283
284impl From<Fact> for Value {
285    fn from(value: Fact) -> Self {
286        Self::Fact(value)
287    }
288}
289
290impl<Tag: IdTag> From<Id<Tag>> for Value {
291    fn from(id: Id<Tag>) -> Self {
292        Self::Id(id.as_base())
293    }
294}
295
296impl TryFrom<Value> for i64 {
297    type Error = ValueConversionError;
298
299    fn try_from(value: Value) -> Result<Self, Self::Error> {
300        if let Value::Int(i) = value {
301            return Ok(i);
302        }
303        Err(ValueConversionError::invalid_type(
304            "Int",
305            value.type_name(),
306            "Value -> i64",
307        ))
308    }
309}
310
311impl TryFrom<Value> for bool {
312    type Error = ValueConversionError;
313
314    fn try_from(value: Value) -> Result<Self, Self::Error> {
315        if let Value::Bool(b) = value {
316            return Ok(b);
317        }
318        Err(ValueConversionError::invalid_type(
319            "Bool",
320            value.type_name(),
321            "Value -> bool",
322        ))
323    }
324}
325
326impl TryFrom<Value> for Text {
327    type Error = ValueConversionError;
328
329    fn try_from(value: Value) -> Result<Self, Self::Error> {
330        if let Value::String(s) = value {
331            return Ok(s);
332        }
333        Err(ValueConversionError::invalid_type(
334            "String",
335            value.type_name(),
336            "Value -> Text",
337        ))
338    }
339}
340
341impl TryFrom<Value> for Identifier {
342    type Error = ValueConversionError;
343
344    fn try_from(value: Value) -> Result<Self, Self::Error> {
345        let Value::Identifier(text) = value else {
346            return Err(ValueConversionError::invalid_type(
347                "Identifier",
348                value.type_name(),
349                "Value -> Identifier",
350            ));
351        };
352        Ok(text)
353    }
354}
355
356impl TryFrom<Value> for Vec<u8> {
357    type Error = ValueConversionError;
358
359    fn try_from(value: Value) -> Result<Self, Self::Error> {
360        if let Value::Bytes(v) = value {
361            return Ok(v);
362        }
363        Err(ValueConversionError::invalid_type(
364            "Bytes",
365            value.type_name(),
366            "Value -> Vec<u8>",
367        ))
368    }
369}
370
371impl TryFrom<Value> for Struct {
372    type Error = ValueConversionError;
373
374    fn try_from(value: Value) -> Result<Self, Self::Error> {
375        if let Value::Struct(s) = value {
376            return Ok(s);
377        }
378        Err(ValueConversionError::invalid_type(
379            "Struct",
380            value.type_name(),
381            "Value -> Struct",
382        ))
383    }
384}
385
386impl TryFrom<Value> for Fact {
387    type Error = ValueConversionError;
388
389    fn try_from(value: Value) -> Result<Self, Self::Error> {
390        if let Value::Fact(f) = value {
391            return Ok(f);
392        }
393        Err(ValueConversionError::invalid_type(
394            "Fact",
395            value.type_name(),
396            "Value -> Fact",
397        ))
398    }
399}
400
401impl<Tag: IdTag> TryFrom<Value> for Id<Tag> {
402    type Error = ValueConversionError;
403
404    fn try_from(value: Value) -> Result<Self, Self::Error> {
405        if let Value::Id(id) = value {
406            Ok(Self::from_base(id))
407        } else {
408            Err(ValueConversionError::invalid_type(
409                "Id",
410                value.type_name(),
411                "Value -> Id",
412            ))
413        }
414    }
415}
416
417impl TryAsMut<i64> for Value {
418    type Error = ValueConversionError;
419    fn try_as_mut(&mut self) -> Result<&mut i64, Self::Error> {
420        if let Self::Int(s) = self {
421            return Ok(s);
422        }
423        Err(ValueConversionError::invalid_type(
424            "i64",
425            self.type_name(),
426            "Value -> i64",
427        ))
428    }
429}
430
431impl TryAsMut<bool> for Value {
432    type Error = ValueConversionError;
433    fn try_as_mut(&mut self) -> Result<&mut bool, Self::Error> {
434        if let Self::Bool(b) = self {
435            return Ok(b);
436        }
437        Err(ValueConversionError::invalid_type(
438            "bool",
439            self.type_name(),
440            "Value -> bool",
441        ))
442    }
443}
444
445impl TryAsMut<[u8]> for Value {
446    type Error = ValueConversionError;
447    fn try_as_mut(&mut self) -> Result<&mut [u8], Self::Error> {
448        if let Self::Bytes(v) = self {
449            return Ok(v);
450        }
451        Err(ValueConversionError::invalid_type(
452            "Vec<u8>",
453            self.type_name(),
454            "Value -> [u8]",
455        ))
456    }
457}
458
459impl TryAsMut<Struct> for Value {
460    type Error = ValueConversionError;
461    fn try_as_mut(&mut self) -> Result<&mut Struct, Self::Error> {
462        if let Self::Struct(s) = self {
463            return Ok(s);
464        }
465        Err(ValueConversionError::invalid_type(
466            "Struct",
467            self.type_name(),
468            "Value -> Struct",
469        ))
470    }
471}
472
473impl TryAsMut<Fact> for Value {
474    type Error = ValueConversionError;
475    fn try_as_mut(&mut self) -> Result<&mut Fact, Self::Error> {
476        if let Self::Fact(f) = self {
477            return Ok(f);
478        }
479        Err(ValueConversionError::invalid_type(
480            "Fact",
481            self.type_name(),
482            "Value -> Fact",
483        ))
484    }
485}
486
487impl Display for Value {
488    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
489        match self {
490            Self::Int(i) => write!(f, "{}", i),
491            Self::Bool(b) => write!(f, "{}", b),
492            Self::String(s) => write!(f, "\"{}\"", s),
493            Self::Bytes(v) => {
494                write!(f, "b:")?;
495                for b in v {
496                    write!(f, "{:02X}", b)?;
497                }
498                Ok(())
499            }
500            Self::Struct(s) => s.fmt(f),
501            Self::Fact(fa) => fa.fmt(f),
502            Self::Id(id) => id.fmt(f),
503            Self::Enum(name, value) => write!(f, "{name}::{value}"),
504            Self::Identifier(name) => write!(f, "{name}"),
505            Self::None => write!(f, "None"),
506        }
507    }
508}
509
510/// The subset of Values that can be hashed. Only these types of values
511/// can be used in the key portion of a Fact.
512#[derive(
513    Debug,
514    Clone,
515    PartialEq,
516    Eq,
517    Hash,
518    PartialOrd,
519    Ord,
520    Serialize,
521    Deserialize,
522    rkyv::Archive,
523    rkyv::Deserialize,
524    rkyv::Serialize,
525)]
526#[cfg_attr(feature = "proptest", derive(proptest_derive::Arbitrary))]
527pub enum HashableValue {
528    /// An integer.
529    Int(i64),
530    /// A bool.
531    Bool(bool),
532    /// A string.
533    String(Text),
534    /// A unique identifier.
535    Id(BaseId),
536    /// Enum
537    Enum(Identifier, i64),
538}
539
540impl HashableValue {
541    /// Get the [`TypeKind`]. Unlike the Value version, this cannot
542    /// fail.
543    pub fn vtype(&self) -> TypeKind {
544        use aranya_policy_ast::TypeKind;
545        match self {
546            Self::Int(_) => TypeKind::Int,
547            Self::Bool(_) => TypeKind::Bool,
548            Self::String(_) => TypeKind::String,
549            Self::Id(_) => TypeKind::Id,
550            Self::Enum(id, _) => TypeKind::Enum(Ident {
551                name: id.clone(),
552                span: Span::default(),
553            }),
554        }
555    }
556}
557
558impl TryFrom<Value> for HashableValue {
559    type Error = ValueConversionError;
560
561    fn try_from(value: Value) -> Result<Self, Self::Error> {
562        match value {
563            Value::Int(v) => Ok(Self::Int(v)),
564            Value::Bool(v) => Ok(Self::Bool(v)),
565            Value::String(v) => Ok(Self::String(v)),
566            Value::Id(v) => Ok(Self::Id(v)),
567            Value::Enum(id, value) => Ok(Self::Enum(id, value)),
568            _ => Err(ValueConversionError::invalid_type(
569                "Int | Bool | String | Id | Enum",
570                value.type_name(),
571                "Value -> HashableValue",
572            )),
573        }
574    }
575}
576
577impl From<HashableValue> for Value {
578    fn from(value: HashableValue) -> Self {
579        match value {
580            HashableValue::Int(v) => Self::Int(v),
581            HashableValue::Bool(v) => Self::Bool(v),
582            HashableValue::String(v) => Self::String(v),
583            HashableValue::Id(v) => Self::Id(v),
584            HashableValue::Enum(id, value) => Self::Enum(id, value),
585        }
586    }
587}
588
589impl Display for HashableValue {
590    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
591        let real_value: Value = self.to_owned().into();
592        write!(f, "{}", real_value)
593    }
594}
595
596/// One labeled value in a fact key. A sequence of FactKeys mapped to
597/// a sequence of FactValues comprises a Fact.
598#[derive(
599    Debug,
600    Clone,
601    PartialEq,
602    Eq,
603    PartialOrd,
604    Ord,
605    Hash,
606    Serialize,
607    Deserialize,
608    rkyv::Archive,
609    rkyv::Deserialize,
610    rkyv::Serialize,
611)]
612#[cfg_attr(feature = "proptest", derive(proptest_derive::Arbitrary))]
613pub struct FactKey {
614    /// key name
615    pub identifier: Identifier,
616    /// key value
617    pub value: HashableValue,
618}
619
620impl FactKey {
621    /// Creates a new fact key.
622    pub fn new(name: Identifier, value: HashableValue) -> Self {
623        Self {
624            identifier: name,
625            value,
626        }
627    }
628}
629
630impl Display for FactKey {
631    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
632        write!(f, "{}: {}", self.identifier, self.value)
633    }
634}
635
636/// One labeled value in a fact value.
637#[derive(
638    Debug,
639    Clone,
640    PartialEq,
641    Eq,
642    Serialize,
643    Deserialize,
644    rkyv::Archive,
645    rkyv::Deserialize,
646    rkyv::Serialize,
647)]
648pub struct FactValue {
649    /// value name
650    pub identifier: Identifier,
651    /// value
652    pub value: Value,
653}
654
655impl FactValue {
656    /// Creates a new fact value.
657    pub fn new(name: Identifier, value: Value) -> Self {
658        Self {
659            identifier: name,
660            value,
661        }
662    }
663}
664
665impl Display for FactValue {
666    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
667        write!(f, "{}: {}", self.identifier, self.value)
668    }
669}
670
671/// A list of fact keys.
672pub type FactKeyList = Vec<FactKey>;
673
674/// A list of fact values.
675pub type FactValueList = Vec<FactValue>;
676
677/// A generic key/value pair. Used for Effects and Command fields.
678/// Technically identical to a FactValue but separate to distinguish
679/// usage.
680#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
681pub struct KVPair(Identifier, Value);
682
683impl KVPair {
684    /// Creates a key-value pair.
685    pub fn new(key: Identifier, value: Value) -> Self {
686        Self(key, value)
687    }
688
689    /// Creates a key-value pair with an integer value.
690    pub fn new_int(key: Identifier, value: i64) -> Self {
691        Self(key, Value::Int(value))
692    }
693
694    /// Returns the key half of the key-value pair.
695    pub fn key(&self) -> &Identifier {
696        &self.0
697    }
698
699    /// Returns the value half of the key-value pair.
700    pub fn value(&self) -> &Value {
701        &self.1
702    }
703}
704
705impl Display for KVPair {
706    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
707        write!(f, "{}: {}", self.0, self.1)
708    }
709}
710
711impl From<KVPair> for (Identifier, Value) {
712    fn from(kv: KVPair) -> Self {
713        (kv.0, kv.1)
714    }
715}
716
717impl From<&KVPair> for (Identifier, Value) {
718    fn from(value: &KVPair) -> Self {
719        (value.0.clone(), value.1.clone())
720    }
721}
722
723impl From<FactKey> for KVPair {
724    fn from(value: FactKey) -> Self {
725        Self(value.identifier, value.value.into())
726    }
727}
728
729impl From<FactValue> for KVPair {
730    fn from(value: FactValue) -> Self {
731        Self(value.identifier, value.value)
732    }
733}
734
735/// A Fact
736#[derive(
737    Debug,
738    Clone,
739    PartialEq,
740    Eq,
741    Serialize,
742    Deserialize,
743    rkyv::Archive,
744    rkyv::Deserialize,
745    rkyv::Serialize,
746)]
747#[rkyv(serialize_bounds(
748    __S: rkyv::ser::Writer + rkyv::ser::Allocator,
749    __S::Error: rkyv::rancor::Source,
750))]
751#[rkyv(deserialize_bounds(__D::Error: rkyv::rancor::Source))]
752#[rkyv(bytecheck(
753    bounds(
754        __C: rkyv::validation::ArchiveContext,
755        __C::Error: rkyv::rancor::Source,
756    )
757))]
758pub struct Fact {
759    /// The name of the fact
760    pub name: Identifier,
761    /// The keys of the fact
762    #[rkyv(omit_bounds)]
763    pub keys: FactKeyList,
764    /// The values of the fact
765    #[rkyv(omit_bounds)]
766    pub values: FactValueList,
767}
768
769impl Fact {
770    /// Creates a fact.
771    pub fn new(name: Identifier) -> Self {
772        Self {
773            name,
774            keys: vec![],
775            values: vec![],
776        }
777    }
778
779    /// Sets the fact's key.
780    pub fn set_key<V>(&mut self, name: Identifier, value: V)
781    where
782        V: Into<HashableValue>,
783    {
784        match self.keys.iter_mut().find(|e| e.identifier == name) {
785            None => self.keys.push(FactKey::new(name, value.into())),
786            Some(e) => e.value = value.into(),
787        }
788    }
789
790    /// Sets the fact's value.
791    pub fn set_value<V>(&mut self, name: Identifier, value: V)
792    where
793        V: Into<Value>,
794    {
795        match self.values.iter_mut().find(|e| e.identifier == name) {
796            None => self.values.push(FactValue {
797                identifier: name,
798                value: value.into(),
799            }),
800            Some(e) => e.value = value.into(),
801        }
802    }
803}
804
805impl Display for Fact {
806    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
807        write!(f, "{}[", self.name)?;
808        let mut i = false;
809        for FactKey {
810            identifier: k,
811            value: v,
812        } in &self.keys
813        {
814            if i {
815                write!(f, ", ")?;
816            }
817            i = true;
818            write!(f, "{}: {}", k, v)?;
819        }
820        write!(f, "]=>{{")?;
821        i = false;
822        for FactValue {
823            identifier: k,
824            value: v,
825        } in &self.values
826        {
827            if i {
828                write!(f, ", ")?;
829            }
830            i = true;
831            write!(f, "{}: {}", k, v)?;
832        }
833        write!(f, " }}")
834    }
835}
836
837/// A Struct value
838#[derive(
839    Debug,
840    Clone,
841    PartialEq,
842    Eq,
843    Serialize,
844    Deserialize,
845    rkyv::Archive,
846    rkyv::Deserialize,
847    rkyv::Serialize,
848)]
849#[rkyv(serialize_bounds(
850    __S: rkyv::ser::Writer + rkyv::ser::Allocator,
851    __S::Error: rkyv::rancor::Source,
852))]
853#[rkyv(deserialize_bounds(__D::Error: rkyv::rancor::Source))]
854#[rkyv(bytecheck(
855    bounds(
856        __C: rkyv::validation::ArchiveContext,
857        __C::Error: rkyv::rancor::Source,
858    )
859))]
860pub struct Struct {
861    /// The name of the struct
862    pub name: Identifier,
863    /// the fields of the struct
864    #[rkyv(omit_bounds)]
865    pub fields: BTreeMap<Identifier, Value>,
866}
867
868impl Struct {
869    /// Creates a struct.
870    pub fn new(
871        name: Identifier,
872        fields: impl IntoIterator<Item = impl Into<(Identifier, Value)>>,
873    ) -> Self {
874        Self {
875            name,
876            fields: fields.into_iter().map(Into::into).collect(),
877        }
878    }
879}
880
881impl Display for Struct {
882    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
883        write!(f, "{}{{", self.name)?;
884        let mut i = false;
885        for (k, v) in &self.fields {
886            if i {
887                write!(f, ", ")?;
888            }
889            i = true;
890            write!(f, "{}: {}", k, v)?;
891        }
892        write!(f, "}}")
893    }
894}