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