miden_assembly_syntax/ast/attribute/
set.rs

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