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