cedar_policy_core/error_macros.rs
1/*
2 * Copyright Cedar Contributors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/// Macro which implements the `.labels()` and `.source_code()` methods of
18/// `miette::Diagnostic` by using the parameter `$i` which must be the name
19/// of a field of type `Loc`
20#[macro_export]
21macro_rules! impl_diagnostic_from_source_loc_field {
22 ( $i:ident ) => {
23 fn source_code(&self) -> Option<&dyn miette::SourceCode> {
24 Some(&self.$i.src as &dyn miette::SourceCode)
25 }
26
27 fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
28 Some(Box::new(std::iter::once(miette::LabeledSpan::underline(
29 self.$i.span,
30 ))) as _)
31 }
32 };
33}
34
35/// Macro which implements the `.labels()` and `.source_code()` methods of
36/// `miette::Diagnostic` by using the parameter `$i` which must be the name
37/// of a field of type `Option<Loc>`
38#[macro_export]
39macro_rules! impl_diagnostic_from_source_loc_opt_field {
40 ( $i:ident ) => {
41 fn source_code(&self) -> Option<&dyn miette::SourceCode> {
42 self.$i
43 .as_ref()
44 .map(|loc| &loc.src as &dyn miette::SourceCode)
45 }
46
47 fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
48 self.$i
49 .as_ref()
50 .map(|loc| Box::new(std::iter::once(miette::LabeledSpan::underline(loc.span))) as _)
51 }
52 };
53}
54
55/// Macro which implements the `.labels()` and `.source_code()` methods of
56/// `miette::Diagnostic` by using the parameters `$i` and `$j` which must be
57/// names of fields of type `Loc`.
58/// Both locations will be underlined. It is assumed they have the same `src`.
59#[macro_export]
60macro_rules! impl_diagnostic_from_two_source_loc_fields {
61 ( $i:ident, $j:ident ) => {
62 fn source_code(&self) -> Option<&dyn miette::SourceCode> {
63 // use the `src` from the first location and assume it is the same
64 // as the `src` from the second location
65 Some(&self.$i.src as &dyn miette::SourceCode)
66 }
67
68 fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
69 Some(Box::new(
70 [
71 miette::LabeledSpan::underline(self.$i.span),
72 miette::LabeledSpan::underline(self.$j.span),
73 ]
74 .into_iter(),
75 ) as _)
76 }
77 };
78}
79
80/// Macro which implements the `.labels()` and `.source_code()` methods of
81/// `miette::Diagnostic` by using the parameters `$i` and `$j` which must be the
82/// names of fields of type `Option<Loc>`.
83/// Both locations will be underlined, if both locs are present.
84/// It is assumed that both locs have the same `src`, if both locs are present.
85#[macro_export]
86macro_rules! impl_diagnostic_from_two_source_loc_opt_fields {
87 ( $i:ident , $j:ident ) => {
88 fn source_code(&self) -> Option<&dyn miette::SourceCode> {
89 self.$i
90 .as_ref()
91 .map(|loc| &loc.src as &dyn miette::SourceCode)
92 .or_else(|| {
93 self.$j
94 .as_ref()
95 .map(|loc| &loc.src as &dyn miette::SourceCode)
96 })
97 }
98
99 fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
100 let x = self
101 .$i
102 .as_ref()
103 .map(|loc| miette::LabeledSpan::underline(loc.span));
104 let y = self
105 .$j
106 .as_ref()
107 .map(|loc| miette::LabeledSpan::underline(loc.span));
108
109 match (x, y) {
110 (None, None) => None,
111 (Some(span), None) | (None, Some(span)) => Some(Box::new(std::iter::once(span))),
112 (Some(span_a), Some(span_b)) => Some(Box::new([span_a, span_b].into_iter()) as _),
113 }
114 }
115 };
116}
117
118/// Macro which implements the `.labels()` and `.source_code()` methods of
119/// `miette::Diagnostic` by using the parameter `$i` which must be an `Expr`
120/// (or `Box<Expr>`) type field.
121#[macro_export]
122macro_rules! impl_diagnostic_from_expr_field {
123 ( $i:ident ) => {
124 fn source_code(&self) -> Option<&dyn miette::SourceCode> {
125 self.$i
126 .source_loc()
127 .as_ref()
128 .map(|loc| &loc.src as &dyn miette::SourceCode)
129 }
130
131 fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
132 self.$i
133 .source_loc()
134 .as_ref()
135 .map(|loc| Box::new(std::iter::once(miette::LabeledSpan::underline(loc.span))) as _)
136 }
137 };
138}