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}