miden_assembly_syntax/ast/attribute/
set.rs

1use alloc::vec::Vec;
2use core::fmt;
3
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize};
6
7use super::*;
8use crate::ast::Ident;
9
10/// An [AttributeSet] provides storage and access to all of the attributes attached to a Miden
11/// Assembly item, e.g. procedure definition.
12///
13/// Attributes are unique by name, so if you attempt to add multiple attributes with the same name,
14/// the last write wins. In Miden Assembly syntax, multiple key-value attributes are merged
15/// automatically, and a syntax error is only generated when keys conflict. All other attribute
16/// types produce an error if they are declared multiple times on the same item.
17#[derive(Default, Clone, PartialEq, Eq)]
18#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
19pub struct AttributeSet {
20    /// The attributes in this set.
21    ///
22    /// The [AttributeSet] structure has map-like semantics, so why are we using a vector here?
23    ///
24    /// * We expect attributes to be relatively rare, with no more than a handful on the same item
25    ///   at any given time.
26    /// * A vector is much more space and time efficient to search for small numbers of items
27    /// * We can achieve map-like semantics without O(N) complexity by keeping the vector sorted by
28    ///   the attribute name, and using binary search to search it. This gives us O(1) best-case
29    ///   performance, and O(log N) in the worst case.
30    attrs: Vec<Attribute>,
31}
32
33impl AttributeSet {
34    /// Create a new [AttributeSet] from `attrs`
35    ///
36    /// If the input attributes have duplicate entries for the same name, only one will be selected,
37    /// but it is unspecified which.
38    pub fn new<I>(attrs: I) -> Self
39    where
40        I: IntoIterator<Item = Attribute>,
41    {
42        let mut this = Self { attrs: attrs.into_iter().collect() };
43        this.attrs.sort_by_key(|attr| attr.id());
44        this.attrs.dedup_by_key(|attr| attr.id());
45        this
46    }
47
48    /// Returns true if there are no attributes in this set
49    #[inline]
50    pub fn is_empty(&self) -> bool {
51        self.attrs.is_empty()
52    }
53
54    /// Returns the number of attributes in this set
55    #[inline]
56    pub fn len(&self) -> usize {
57        self.attrs.len()
58    }
59
60    /// Check if this set has an attributed named `name`
61    pub fn has(&self, name: impl AsRef<str>) -> bool {
62        self.get(name).is_some()
63    }
64
65    /// Get the attribute named `name`, if one is present.
66    pub fn get(&self, name: impl AsRef<str>) -> Option<&Attribute> {
67        let name = name.as_ref();
68        match self.attrs.binary_search_by_key(&name, |attr| attr.name()) {
69            Ok(index) => self.attrs.get(index),
70            Err(_) => None,
71        }
72    }
73
74    /// Get a mutable reference to the attribute named `name`, if one is present.
75    pub fn get_mut(&mut self, name: impl AsRef<str>) -> Option<&mut Attribute> {
76        let name = name.as_ref();
77        match self.attrs.binary_search_by_key(&name, |attr| attr.name()) {
78            Ok(index) => self.attrs.get_mut(index),
79            Err(_) => None,
80        }
81    }
82
83    /// Get an iterator over the attributes in this set
84    #[inline]
85    pub fn iter(&self) -> core::slice::Iter<'_, Attribute> {
86        self.attrs.iter()
87    }
88
89    /// Get a mutable iterator over the attributes in this set
90    #[inline]
91    pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, Attribute> {
92        self.attrs.iter_mut()
93    }
94
95    /// Insert `attr` in the attribute set, replacing any existing attribute with the same name
96    ///
97    /// Returns true if the insertion was new, or false if the insertion replaced an existing entry.
98    pub fn insert(&mut self, attr: Attribute) -> bool {
99        let name = attr.name();
100        match self.attrs.binary_search_by_key(&name, |attr| attr.name()) {
101            Ok(index) => {
102                // Replace existing attribute
103                self.attrs[index] = attr;
104                false
105            },
106            Err(index) => {
107                self.attrs.insert(index, attr);
108                true
109            },
110        }
111    }
112
113    /// Insert `attr` in the attribute set, but only if there is no existing attribute with the same
114    /// name.
115    ///
116    /// Returns `Err` with `attr` if there is already an existing attribute with the same name.
117    pub fn insert_new(&mut self, attr: Attribute) -> Result<(), Attribute> {
118        if self.has(attr.name()) {
119            Err(attr)
120        } else {
121            self.insert(attr);
122            Ok(())
123        }
124    }
125
126    /// Removes the attribute named `name`, if present.
127    pub fn remove(&mut self, name: impl AsRef<str>) -> Option<Attribute> {
128        let name = name.as_ref();
129        match self.attrs.binary_search_by_key(&name, |attr| attr.name()) {
130            Ok(index) => Some(self.attrs.remove(index)),
131            Err(_) => None,
132        }
133    }
134
135    /// Gets the given key's corresponding entry in the set for in-place modfication
136    pub fn entry(&mut self, key: Ident) -> AttributeSetEntry<'_> {
137        match self.attrs.binary_search_by_key(&key.as_str(), |attr| attr.name()) {
138            Ok(index) => AttributeSetEntry::occupied(self, index),
139            Err(index) => AttributeSetEntry::vacant(self, key, index),
140        }
141    }
142
143    /// Clear all attributes from the set
144    #[inline]
145    pub fn clear(&mut self) {
146        self.attrs.clear();
147    }
148}
149
150impl fmt::Debug for AttributeSet {
151    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152        let mut builder = f.debug_map();
153        for attr in self.iter() {
154            match attr.metadata() {
155                None => {
156                    builder.entry(&attr.name(), &"None");
157                },
158                Some(meta) => {
159                    builder.entry(&attr.name(), &meta);
160                },
161            }
162        }
163        builder.finish()
164    }
165}
166
167impl FromIterator<Attribute> for AttributeSet {
168    #[inline]
169    fn from_iter<T: IntoIterator<Item = Attribute>>(iter: T) -> Self {
170        Self::new(iter)
171    }
172}
173
174impl Extend<Attribute> for AttributeSet {
175    fn extend<T: IntoIterator<Item = Attribute>>(&mut self, iter: T) {
176        for attr in iter {
177            self.insert(attr);
178        }
179    }
180}
181
182/// Represents an entry under a specific key in a [AttributeSet]
183pub enum AttributeSetEntry<'a> {
184    /// The entry is currently occupied with a value
185    Occupied(AttributeSetOccupiedEntry<'a>),
186    /// The entry is currently vacant
187    Vacant(AttributeSetVacantEntry<'a>),
188}
189impl<'a> AttributeSetEntry<'a> {
190    fn occupied(set: &'a mut AttributeSet, index: usize) -> Self {
191        Self::Occupied(AttributeSetOccupiedEntry { set, index })
192    }
193
194    fn vacant(set: &'a mut AttributeSet, key: Ident, index: usize) -> Self {
195        Self::Vacant(AttributeSetVacantEntry { set, key, index })
196    }
197}
198
199#[doc(hidden)]
200pub struct AttributeSetOccupiedEntry<'a> {
201    set: &'a mut AttributeSet,
202    index: usize,
203}
204impl AttributeSetOccupiedEntry<'_> {
205    #[inline]
206    pub fn get(&self) -> &Attribute {
207        &self.set.attrs[self.index]
208    }
209
210    #[inline]
211    pub fn get_mut(&mut self) -> &mut Attribute {
212        &mut self.set.attrs[self.index]
213    }
214
215    pub fn insert(self, attr: Attribute) {
216        if attr.name() != self.get().name() {
217            self.set.insert(attr);
218        } else {
219            self.set.attrs[self.index] = attr;
220        }
221    }
222
223    #[inline]
224    pub fn remove(self) -> Attribute {
225        self.set.attrs.remove(self.index)
226    }
227}
228
229#[doc(hidden)]
230pub struct AttributeSetVacantEntry<'a> {
231    set: &'a mut AttributeSet,
232    key: Ident,
233    index: usize,
234}
235impl AttributeSetVacantEntry<'_> {
236    pub fn insert(self, attr: Attribute) {
237        if self.key != attr.id() {
238            self.set.insert(attr);
239        } else {
240            self.set.attrs.insert(self.index, attr);
241        }
242    }
243}
244
245#[cfg(feature = "arbitrary")]
246impl proptest::arbitrary::Arbitrary for AttributeSet {
247    type Parameters = ();
248
249    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
250        use proptest::{arbitrary::any, strategy::Strategy};
251
252        let items = proptest::collection::vec(any::<Attribute>(), 1..3);
253        items.prop_map(|attrs| Self { attrs }).boxed()
254    }
255
256    type Strategy = proptest::prelude::BoxedStrategy<Self>;
257}
258
259impl Serializable for AttributeSet {
260    fn write_into<W: ByteWriter>(&self, target: &mut W) {
261        self.attrs.write_into(target)
262    }
263}
264
265impl Deserializable for AttributeSet {
266    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
267        let attrs = Vec::read_from(source)?;
268        Ok(Self { attrs })
269    }
270}