cedar_policy_core/parser/
node.rs1use std::fmt::{self, Debug, Display};
18use std::hash::{Hash, Hasher};
19
20use miette::Diagnostic;
21use serde::{Deserialize, Serialize};
22
23use super::err::{ToASTError, ToASTErrorKind};
24use super::loc::Loc;
25
26#[derive(Debug, Clone, Deserialize, Serialize)]
28pub struct Node<T> {
29 pub node: T,
31
32 pub loc: Loc,
34}
35
36impl<T> Node<T> {
37 pub fn with_source_loc(node: T, loc: Loc) -> Self {
39 Node { node, loc }
40 }
41
42 pub fn map<R>(self, f: impl FnOnce(T) -> R) -> Node<R> {
44 Node {
45 node: f(self.node),
46 loc: self.loc.clone(),
47 }
48 }
49
50 pub fn as_ref(&self) -> Node<&T> {
52 Node {
53 node: &self.node,
54 loc: self.loc.clone(),
55 }
56 }
57
58 pub fn as_mut(&mut self) -> Node<&mut T> {
60 Node {
61 node: &mut self.node,
62 loc: self.loc.clone(),
63 }
64 }
65
66 pub fn into_inner(self) -> (T, Loc) {
68 (self.node, self.loc)
69 }
70
71 pub fn to_ast_err(&self, error_kind: impl Into<ToASTErrorKind>) -> ToASTError {
73 ToASTError::new(error_kind.into(), self.loc.clone())
74 }
75}
76
77impl<T: Clone> Node<&T> {
78 pub fn cloned(self) -> Node<T> {
80 self.map(|value| value.clone())
81 }
82}
83
84impl<T: Copy> Node<&T> {
85 pub fn copied(self) -> Node<T> {
87 self.map(|value| *value)
88 }
89}
90
91impl<T: Display> Display for Node<T> {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 Display::fmt(&self.node, f)
94 }
95}
96
97impl<T: std::error::Error> std::error::Error for Node<T> {
98 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
99 self.node.source()
100 }
101
102 #[allow(deprecated)]
103 fn description(&self) -> &str {
104 self.node.description()
105 }
106
107 fn cause(&self) -> Option<&dyn std::error::Error> {
108 #[allow(deprecated)]
109 self.node.cause()
110 }
111}
112
113impl<T: Diagnostic> Diagnostic for Node<T> {
115 fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
116 self.node.code()
117 }
118
119 fn severity(&self) -> Option<miette::Severity> {
120 self.node.severity()
121 }
122
123 fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
124 self.node.help()
125 }
126
127 fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
128 self.node.url()
129 }
130
131 fn source_code(&self) -> Option<&dyn miette::SourceCode> {
132 self.node.source_code()
133 }
134
135 fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
136 Some(Box::new(std::iter::once(miette::LabeledSpan::underline(
137 self.loc.span,
138 ))))
139 }
140
141 fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
142 self.node.related()
143 }
144
145 fn diagnostic_source(&self) -> Option<&dyn Diagnostic> {
146 self.node.diagnostic_source()
147 }
148}
149
150impl<T: PartialEq> PartialEq for Node<T> {
152 fn eq(&self, other: &Self) -> bool {
154 self.node == other.node
155 }
156}
157impl<T: Eq> Eq for Node<T> {}
158impl<T: Hash> Hash for Node<T> {
159 fn hash<H: Hasher>(&self, state: &mut H) {
161 self.node.hash(state);
162 }
163}
164
165impl<T> Node<Option<T>> {
167 pub fn as_inner(&self) -> Option<&T> {
169 self.node.as_ref()
170 }
171
172 pub fn collapse(&self) -> Option<Node<&T>> {
174 self.node.as_ref().map(|node| Node {
175 node,
176 loc: self.loc.clone(),
177 })
178 }
179
180 pub fn apply<F, R>(&self, f: F) -> Option<R>
183 where
184 F: FnOnce(&T, &Loc) -> Option<R>,
185 {
186 f(self.node.as_ref()?, &self.loc)
187 }
188
189 pub fn into_apply<F, R>(self, f: F) -> Option<R>
192 where
193 F: FnOnce(T, Loc) -> Option<R>,
194 {
195 f(self.node?, self.loc)
196 }
197
198 pub fn ok_or_missing(&self) -> Result<&T, ToASTError> {
201 self.node
202 .as_ref()
203 .ok_or_else(|| self.to_ast_err(ToASTErrorKind::MissingNodeData))
204 }
205}