cedar_policy_core/ast/
annotation.rs1use std::collections::BTreeMap;
18
19use educe::Educe;
20use serde::{Deserialize, Serialize};
21use smol_str::SmolStr;
22
23use crate::parser::Loc;
24
25use super::AnyId;
26
27#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Debug)]
29#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
30pub struct Annotations(
31 #[serde(default)]
32 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
33 #[serde(with = "::serde_with::rust::maps_duplicate_key_is_error")]
34 BTreeMap<AnyId, Annotation>,
35);
36
37impl std::fmt::Display for Annotations {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 for (k, v) in &self.0 {
40 writeln!(f, "@{k}({v})")?
41 }
42 Ok(())
43 }
44}
45
46impl Annotations {
47 pub fn new() -> Self {
49 Self(BTreeMap::new())
50 }
51
52 pub fn get(&self, key: &AnyId) -> Option<&Annotation> {
54 self.0.get(key)
55 }
56
57 pub fn iter(&self) -> impl Iterator<Item = (&AnyId, &Annotation)> {
59 self.0.iter()
60 }
61
62 pub fn is_empty(&self) -> bool {
64 self.0.is_empty()
65 }
66}
67
68#[derive(Debug)]
70pub struct IntoIter(std::collections::btree_map::IntoIter<AnyId, Annotation>);
71
72impl Iterator for IntoIter {
73 type Item = (AnyId, Annotation);
74
75 fn next(&mut self) -> Option<Self::Item> {
76 self.0.next()
77 }
78}
79
80impl IntoIterator for Annotations {
81 type Item = (AnyId, Annotation);
82
83 type IntoIter = IntoIter;
84
85 fn into_iter(self) -> Self::IntoIter {
86 IntoIter(self.0.into_iter())
87 }
88}
89
90impl Default for Annotations {
91 fn default() -> Self {
92 Self::new()
93 }
94}
95
96impl FromIterator<(AnyId, Annotation)> for Annotations {
97 fn from_iter<T: IntoIterator<Item = (AnyId, Annotation)>>(iter: T) -> Self {
98 Self(BTreeMap::from_iter(iter))
99 }
100}
101
102impl From<BTreeMap<AnyId, Annotation>> for Annotations {
103 fn from(value: BTreeMap<AnyId, Annotation>) -> Self {
104 Self(value)
105 }
106}
107
108#[derive(Educe, Clone, Debug, Serialize, Deserialize, Default)]
110#[educe(Hash, PartialEq, Eq, PartialOrd, Ord)]
111#[serde(transparent)]
112#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
113#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
114pub struct Annotation {
115 pub val: SmolStr,
117 #[serde(skip)]
120 #[educe(Hash(ignore))]
121 #[educe(PartialEq(ignore))]
122 #[educe(PartialOrd(ignore))]
123 pub loc: Option<Loc>,
124}
125
126impl std::fmt::Display for Annotation {
127 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128 write!(f, "\"{}\"", self.val.escape_debug())
129 }
130}
131
132impl Annotation {
133 pub fn with_optional_value(val: Option<SmolStr>, loc: Option<Loc>) -> Self {
138 Self {
139 val: val.unwrap_or_default(),
140 loc,
141 }
142 }
143}
144
145impl AsRef<str> for Annotation {
146 fn as_ref(&self) -> &str {
147 &self.val
148 }
149}
150
151#[cfg(feature = "arbitrary")]
152impl<'a> arbitrary::Arbitrary<'a> for Annotation {
153 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
154 Ok(Self {
155 val: u.arbitrary::<&str>()?.into(),
156 loc: None,
157 })
158 }
159
160 fn size_hint(depth: usize) -> (usize, Option<usize>) {
161 <&str as arbitrary::Arbitrary>::size_hint(depth)
162 }
163}