miden_assembly_syntax/ast/attribute/meta/
list.rs

1use alloc::vec::Vec;
2
3use miden_core::utils::{
4    ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
5};
6use miden_debug_types::{SourceSpan, Spanned};
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10use super::MetaExpr;
11use crate::ast::Ident;
12
13/// Represents the metadata of a named list [crate::ast::Attribute], i.e. `@name(item0, .., itemN)`
14#[derive(Debug, Clone)]
15#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
16#[cfg_attr(
17    all(feature = "arbitrary", test),
18    miden_test_serde_macros::serde_test(winter_serde(true))
19)]
20pub struct MetaList {
21    #[cfg_attr(feature = "serde", serde(skip, default))]
22    pub span: SourceSpan,
23    /// The identifier used as the name of this attribute
24    pub name: Ident,
25    /// The list of items representing the value of this attribute - will always contain at least
26    /// one element when parsed.
27    pub items: Vec<MetaExpr>,
28}
29
30impl Spanned for MetaList {
31    #[inline(always)]
32    fn span(&self) -> SourceSpan {
33        self.span
34    }
35}
36
37impl MetaList {
38    pub fn new<I>(name: Ident, items: I) -> Self
39    where
40        I: IntoIterator<Item = MetaExpr>,
41    {
42        Self {
43            span: SourceSpan::default(),
44            name,
45            items: items.into_iter().collect(),
46        }
47    }
48
49    pub fn with_span(mut self, span: SourceSpan) -> Self {
50        self.span = span;
51        self
52    }
53
54    /// Get the name of this attribute as a string
55    pub fn name(&self) -> &str {
56        self.name.as_str()
57    }
58
59    /// Get the name of this attribute as an [Ident]
60    pub fn id(&self) -> Ident {
61        self.name.clone()
62    }
63
64    /// Returns true if the metadata list is empty
65    #[inline]
66    pub fn is_empty(&self) -> bool {
67        self.items.is_empty()
68    }
69
70    /// Returns the number of items in the metadata list
71    #[inline]
72    pub fn len(&self) -> usize {
73        self.items.len()
74    }
75
76    /// Get the metadata list as a slice
77    #[inline]
78    pub fn as_slice(&self) -> &[MetaExpr] {
79        self.items.as_slice()
80    }
81
82    /// Get the metadata list as a mutable slice
83    #[inline]
84    pub fn as_mut_slice(&mut self) -> &mut [MetaExpr] {
85        self.items.as_mut_slice()
86    }
87}
88
89impl Eq for MetaList {}
90
91impl PartialEq for MetaList {
92    fn eq(&self, other: &Self) -> bool {
93        self.name == other.name && self.items == other.items
94    }
95}
96
97impl PartialOrd for MetaList {
98    #[inline]
99    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
100        Some(self.cmp(other))
101    }
102}
103
104impl Ord for MetaList {
105    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
106        self.name.cmp(&other.name).then_with(|| self.items.cmp(&other.items))
107    }
108}
109
110impl core::hash::Hash for MetaList {
111    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
112        self.name.hash(state);
113        self.items.hash(state);
114    }
115}
116
117#[cfg(feature = "arbitrary")]
118impl proptest::arbitrary::Arbitrary for MetaList {
119    type Parameters = ();
120
121    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
122        use proptest::{arbitrary::any, strategy::Strategy};
123
124        let name = any::<Ident>();
125        let items = proptest::collection::vec(any::<MetaExpr>(), 1..3);
126        (name, items)
127            .prop_map(|(name, items)| Self { span: SourceSpan::UNKNOWN, name, items })
128            .boxed()
129    }
130
131    type Strategy = proptest::prelude::BoxedStrategy<Self>;
132}
133
134impl Serializable for MetaList {
135    fn write_into<W: ByteWriter>(&self, target: &mut W) {
136        self.name.write_into(target);
137        self.items.write_into(target);
138    }
139}
140
141impl Deserializable for MetaList {
142    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
143        let name = Ident::read_from(source)?;
144        let items = Vec::read_from(source)?;
145
146        Ok(Self { span: SourceSpan::UNKNOWN, name, items })
147    }
148}