miden_assembly_syntax/ast/attribute/meta/
kv.rs1use alloc::collections::BTreeMap;
2use core::borrow::Borrow;
3
4use miden_core::utils::{
5 ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
6};
7use miden_debug_types::{SourceSpan, Spanned};
8#[cfg(feature = "serde")]
9use serde::{Deserialize, Serialize};
10
11use super::MetaExpr;
12use crate::ast::Ident;
13
14#[derive(Debug, Clone)]
16#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17pub struct MetaKeyValue {
18 #[cfg_attr(feature = "serde", serde(skip, default))]
19 pub span: SourceSpan,
20 pub name: Ident,
22 pub items: BTreeMap<Ident, MetaExpr>,
24}
25
26impl Spanned for MetaKeyValue {
27 #[inline(always)]
28 fn span(&self) -> SourceSpan {
29 self.span
30 }
31}
32
33impl MetaKeyValue {
34 pub fn new<K, V, I>(name: Ident, items: I) -> Self
35 where
36 I: IntoIterator<Item = (K, V)>,
37 K: Into<Ident>,
38 V: Into<MetaExpr>,
39 {
40 let items = items.into_iter().map(|(k, v)| (k.into(), v.into())).collect();
41 Self { span: SourceSpan::default(), name, items }
42 }
43
44 pub fn with_span(mut self, span: SourceSpan) -> Self {
45 self.span = span;
46 self
47 }
48
49 #[inline]
51 pub fn name(&self) -> &str {
52 self.name.as_str()
53 }
54
55 #[inline]
57 pub fn id(&self) -> Ident {
58 self.name.clone()
59 }
60
61 pub fn contains_key<Q>(&self, key: &Q) -> bool
63 where
64 Ident: Borrow<Q> + Ord,
65 Q: ?Sized + Ord,
66 {
67 self.items.contains_key(key)
68 }
69
70 pub fn get<Q>(&self, key: &Q) -> Option<&MetaExpr>
72 where
73 Ident: Borrow<Q> + Ord,
74 Q: ?Sized + Ord,
75 {
76 self.items.get(key)
77 }
78
79 pub fn insert(&mut self, key: impl Into<Ident>, value: impl Into<MetaExpr>) {
81 self.items.insert(key.into(), value.into());
82 }
83
84 pub fn remove<Q>(&mut self, key: &Q) -> Option<MetaExpr>
86 where
87 Ident: Borrow<Q> + Ord,
88 Q: ?Sized + Ord,
89 {
90 self.items.remove(key)
91 }
92
93 pub fn entry(
95 &mut self,
96 key: Ident,
97 ) -> alloc::collections::btree_map::Entry<'_, Ident, MetaExpr> {
98 self.items.entry(key)
99 }
100
101 #[inline]
103 pub fn iter(&self) -> impl Iterator<Item = (&Ident, &MetaExpr)> {
104 self.items.iter()
105 }
106}
107
108impl IntoIterator for MetaKeyValue {
109 type Item = (Ident, MetaExpr);
110 type IntoIter = alloc::collections::btree_map::IntoIter<Ident, MetaExpr>;
111
112 #[inline]
113 fn into_iter(self) -> Self::IntoIter {
114 self.items.into_iter()
115 }
116}
117
118impl Eq for MetaKeyValue {}
119
120impl PartialEq for MetaKeyValue {
121 fn eq(&self, other: &Self) -> bool {
122 self.name == other.name && self.items == other.items
123 }
124}
125
126impl PartialOrd for MetaKeyValue {
127 #[inline]
128 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
129 Some(self.cmp(other))
130 }
131}
132
133impl Ord for MetaKeyValue {
134 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
135 self.name.cmp(&other.name).then_with(|| self.items.cmp(&other.items))
136 }
137}
138
139impl core::hash::Hash for MetaKeyValue {
140 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
141 self.name.hash(state);
142 self.items.hash(state);
143 }
144}
145
146#[cfg(feature = "arbitrary")]
147impl proptest::arbitrary::Arbitrary for MetaKeyValue {
148 type Parameters = ();
149
150 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
151 use proptest::{arbitrary::any, strategy::Strategy};
152
153 let name = any::<Ident>();
154 let items = proptest::collection::btree_map(any::<Ident>(), any::<MetaExpr>(), 1..3);
155 (name, items)
156 .prop_map(|(name, items)| Self { span: SourceSpan::UNKNOWN, name, items })
157 .boxed()
158 }
159
160 type Strategy = proptest::prelude::BoxedStrategy<Self>;
161}
162
163impl Serializable for MetaKeyValue {
164 fn write_into<W: ByteWriter>(&self, target: &mut W) {
165 self.name.write_into(target);
166 self.items.write_into(target);
167 }
168}
169
170impl Deserializable for MetaKeyValue {
171 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
172 let name = Ident::read_from(source)?;
173 let items = BTreeMap::read_from(source)?;
174
175 Ok(Self { span: SourceSpan::UNKNOWN, name, items })
176 }
177}