1use nom::error::{ContextError, ErrorKind, FromExternalError, ParseError};
2use std::fmt;
3use thiserror::Error;
4
5pub type NixUriResult<T> = Result<T, NixUriError>;
6
7#[derive(Debug, Clone, PartialEq)]
10pub enum ErrorTree<I> {
11 Base {
13 location: I,
15 kind: BaseErrorKind,
17 },
18 Stack {
20 base: Box<ErrorTree<I>>,
22 contexts: Vec<(I, StackContext)>,
24 },
25 Alt(Vec<ErrorTree<I>>),
27}
28
29#[derive(Debug, Clone, PartialEq)]
31pub enum BaseErrorKind {
32 Kind(ErrorKind),
34 Expected(Expectation),
36 External(String),
38}
39
40#[derive(Debug, Clone, PartialEq)]
42pub enum Expectation {
43 Tag(&'static str),
45 Char(char),
47 Eof,
49 Alpha,
51 Digit,
53 HexDigit,
55 AlphaNumeric,
57 Space,
59 Multispace,
61 Something,
63}
64
65#[derive(Debug, Clone, PartialEq)]
67pub enum StackContext {
68 Context(&'static str),
70 Kind(ErrorKind),
72}
73
74impl<I> ErrorTree<I> {
75 pub fn map_locations<O>(self, f: impl Fn(I) -> O + Copy) -> ErrorTree<O> {
77 match self {
78 ErrorTree::Base { location, kind } => ErrorTree::Base {
79 location: f(location),
80 kind,
81 },
82 ErrorTree::Stack { base, contexts } => ErrorTree::Stack {
83 base: Box::new(base.map_locations(f)),
84 contexts: contexts.into_iter().map(|(i, c)| (f(i), c)).collect(),
85 },
86 ErrorTree::Alt(alts) => {
87 ErrorTree::Alt(alts.into_iter().map(|e| e.map_locations(f)).collect())
88 }
89 }
90 }
91}
92
93impl<I: Clone> ParseError<I> for ErrorTree<I> {
94 fn from_error_kind(input: I, kind: ErrorKind) -> Self {
95 ErrorTree::Base {
96 location: input,
97 kind: BaseErrorKind::Kind(kind),
98 }
99 }
100
101 fn append(input: I, kind: ErrorKind, other: Self) -> Self {
102 let context = (input, StackContext::Kind(kind));
103 match other {
104 ErrorTree::Stack { base, mut contexts } => {
105 contexts.push(context);
106 ErrorTree::Stack { base, contexts }
107 }
108 base => ErrorTree::Stack {
109 base: Box::new(base),
110 contexts: vec![context],
111 },
112 }
113 }
114
115 fn from_char(input: I, c: char) -> Self {
116 ErrorTree::Base {
117 location: input,
118 kind: BaseErrorKind::Expected(Expectation::Char(c)),
119 }
120 }
121
122 fn or(self, other: Self) -> Self {
123 let mut alts = match self {
125 ErrorTree::Alt(v) => v,
126 e => vec![e],
127 };
128 match other {
129 ErrorTree::Alt(v) => alts.extend(v),
130 e => alts.push(e),
131 }
132 ErrorTree::Alt(alts)
133 }
134}
135
136impl<I: Clone> ContextError<I> for ErrorTree<I> {
137 fn add_context(input: I, ctx: &'static str, other: Self) -> Self {
138 let context = (input, StackContext::Context(ctx));
139 match other {
140 ErrorTree::Stack { base, mut contexts } => {
141 contexts.push(context);
142 ErrorTree::Stack { base, contexts }
143 }
144 base => ErrorTree::Stack {
145 base: Box::new(base),
146 contexts: vec![context],
147 },
148 }
149 }
150}
151
152impl<I: Clone, E: std::fmt::Display> FromExternalError<I, E> for ErrorTree<I> {
153 fn from_external_error(input: I, _kind: ErrorKind, e: E) -> Self {
154 ErrorTree::Base {
155 location: input,
156 kind: BaseErrorKind::External(e.to_string()),
157 }
158 }
159}
160
161impl<I: fmt::Display> fmt::Display for ErrorTree<I> {
162 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163 match self {
164 ErrorTree::Base { location, kind } => {
165 write!(f, "error {:?} at: {}", kind, location)
166 }
167 ErrorTree::Stack { base, contexts } => {
168 write!(f, "{}", base)?;
169 for (input, context) in contexts {
170 write!(f, "\n in {:?} at: {}", context, input)?;
171 }
172 Ok(())
173 }
174 ErrorTree::Alt(alts) => {
175 writeln!(f, "one of:")?;
176 for alt in alts {
177 writeln!(f, " {}", alt)?;
178 }
179 Ok(())
180 }
181 }
182 }
183}
184
185impl<I: fmt::Debug + fmt::Display> std::error::Error for ErrorTree<I> {}
186
187pub type IErr<E> = ErrorTree<E>;
188
189#[derive(Debug, Error)]
190#[non_exhaustive]
191pub enum NixUriError {
192 #[error("Error: {0}")]
194 Error(String),
195 #[error("Error parsing: {0}")]
197 ParseError(String),
198 #[error("Not a valid Url: {0}")]
200 InvalidUrl(String),
201 #[error("The path is not absolute: {0}")]
203 NotAbsolute(String),
204 #[error("Contains an illegal path character: {0}")]
206 PathCharacter(String),
207 #[error("FlakeRef Type: {0} is missing the following required parameter: {1}")]
211 MissingTypeParameter(String, String),
212 #[error("The type is not known: {0}")]
214 UnknownUriType(String),
215 #[error("The type is not known: {0}")]
218 UnknownTransportLayer(String),
219 #[error("Invalid FlakeRef Type: {0}")]
221 InvalidType(String),
222 #[error("The parameter: {0} is not supported by the flakeref type.")]
223 UnsupportedParam(String),
224 #[error("field: `{0}` only supported by: `{1}`.")]
225 UnsupportedByType(String, String),
226 #[error("The parameter: {0} invalid.")]
227 UnknownUriParameter(String),
228 #[error("Nom Error: {0}")]
231 Nom(String),
232 #[error(transparent)]
233 NomParseError(#[from] IErr<String>),
234 #[error("Servo Url Parsing Error: {0}")]
237 ServoUrl(#[from] url::ParseError),
238}
239
240impl From<IErr<&str>> for NixUriError {
241 fn from(value: IErr<&str>) -> Self {
242 let new_errs = value.map_locations(|i| i.to_string());
243 Self::NomParseError(new_errs)
244 }
245}
246
247pub fn tag<'a>(
250 expected: &'static str,
251) -> impl FnMut(&'a str) -> nom::IResult<&'a str, &'a str, ErrorTree<&'a str>> {
252 move |input: &'a str| {
253 if let Some(rest) = input.strip_prefix(expected) {
254 Ok((rest, &input[..expected.len()]))
255 } else {
256 Err(nom::Err::Error(ErrorTree::Base {
257 location: input,
258 kind: BaseErrorKind::Expected(Expectation::Tag(expected)),
259 }))
260 }
261 }
262}