cedar_policy_core/parser/
node.rs1use std::fmt::{self, Debug, Display};
18
19use educe::Educe;
20use miette::Diagnostic;
21
22use super::err::{ToASTError, ToASTErrorKind};
23use super::loc::Loc;
24
25#[derive(Educe, Debug, Clone)]
27#[educe(PartialEq, Eq, Hash, Ord, PartialOrd)]
28pub struct Node<T> {
29 pub node: T,
31
32 #[educe(PartialEq(ignore))]
34 #[educe(PartialOrd(ignore))]
35 #[educe(Hash(ignore))]
36 pub loc: Loc,
37}
38
39impl<T> Node<T> {
40 pub fn with_source_loc(node: T, loc: Loc) -> Self {
42 Node { node, loc }
43 }
44
45 pub fn map<R>(self, f: impl FnOnce(T) -> R) -> Node<R> {
47 Node {
48 node: f(self.node),
49 loc: self.loc,
50 }
51 }
52
53 pub fn as_ref(&self) -> Node<&T> {
55 Node {
56 node: &self.node,
57 loc: self.loc.clone(),
58 }
59 }
60
61 pub fn as_mut(&mut self) -> Node<&mut T> {
63 Node {
64 node: &mut self.node,
65 loc: self.loc.clone(),
66 }
67 }
68
69 pub fn into_inner(self) -> (T, Loc) {
71 (self.node, self.loc)
72 }
73
74 pub fn to_ast_err(&self, error_kind: impl Into<ToASTErrorKind>) -> ToASTError {
76 ToASTError::new(error_kind.into(), self.loc.clone())
77 }
78}
79
80impl<T: Clone> Node<&T> {
81 pub fn cloned(self) -> Node<T> {
83 self.map(|value| value.clone())
84 }
85}
86
87impl<T: Copy> Node<&T> {
88 pub fn copied(self) -> Node<T> {
90 self.map(|value| *value)
91 }
92}
93
94impl<T: Display> Display for Node<T> {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 Display::fmt(&self.node, f)
97 }
98}
99
100impl<T: std::error::Error> std::error::Error for Node<T> {
101 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
102 self.node.source()
103 }
104
105 #[allow(deprecated)]
106 fn description(&self) -> &str {
107 self.node.description()
108 }
109
110 fn cause(&self) -> Option<&dyn std::error::Error> {
111 #[allow(deprecated)]
112 self.node.cause()
113 }
114}
115
116impl<T: Diagnostic> Diagnostic for Node<T> {
118 impl_diagnostic_from_source_loc_field!(loc);
119
120 fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
121 self.node.code()
122 }
123
124 fn severity(&self) -> Option<miette::Severity> {
125 self.node.severity()
126 }
127
128 fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
129 self.node.help()
130 }
131
132 fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
133 self.node.url()
134 }
135
136 fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
137 self.node.related()
138 }
139
140 fn diagnostic_source(&self) -> Option<&dyn Diagnostic> {
141 self.node.diagnostic_source()
142 }
143}
144
145impl<T> Node<Option<T>> {
147 pub fn as_inner(&self) -> Option<&T> {
149 self.node.as_ref()
150 }
151
152 pub fn collapse(&self) -> Option<Node<&T>> {
154 self.node.as_ref().map(|node| Node {
155 node,
156 loc: self.loc.clone(),
157 })
158 }
159
160 pub fn apply<F, R>(&self, f: F) -> Option<R>
163 where
164 F: FnOnce(&T, &Loc) -> Option<R>,
165 {
166 f(self.node.as_ref()?, &self.loc)
167 }
168
169 pub fn into_apply<F, R>(self, f: F) -> Option<R>
172 where
173 F: FnOnce(T, Loc) -> Option<R>,
174 {
175 f(self.node?, self.loc)
176 }
177
178 pub fn try_as_inner(&self) -> Result<&T, ToASTError> {
180 self.node
181 .as_ref()
182 .ok_or_else(|| self.to_ast_err(ToASTErrorKind::EmptyNodeInvariantViolation))
183 }
184
185 pub fn try_into_inner(self) -> Result<T, ToASTError> {
187 self.node.ok_or_else(|| {
188 ToASTError::new(
189 ToASTErrorKind::EmptyNodeInvariantViolation,
190 self.loc.clone(),
191 )
192 })
193 }
194}