evitable_syn_meta_ext/error/
mod.rs

1use proc_macro2::{Span, TokenStream};
2use std::error::Error as StdError;
3use std::fmt;
4use std::iter::{self, Iterator};
5use std::string::ToString;
6use std::vec;
7use syn::spanned::Spanned;
8use syn::{Lit, LitStr};
9
10mod kind;
11
12use self::kind::{ErrorKind, ErrorUnknownField};
13
14/// An alias of `Result` specific to attribute parsing.
15pub type Result<T> = ::std::result::Result<T, Error>;
16
17/// An error encountered during attribute parsing.
18///
19/// Given that most errors darling encounters represent code bugs in dependent crates,
20/// the internal structure of the error is deliberately opaque.
21#[derive(Debug)]
22#[cfg_attr(test, derive(Clone))]
23pub struct Error {
24  kind: ErrorKind,
25  locations: Vec<String>,
26  /// The span to highlight in the emitted diagnostic.
27  span: Option<Span>,
28}
29
30/// Error creation functions
31impl Error {
32  pub(self) fn new(kind: ErrorKind) -> Self {
33    Error {
34      kind,
35      locations: Vec::new(),
36      span: None,
37    }
38  }
39
40  /// Creates a new error with a custom message.
41  pub fn custom<T: fmt::Display>(msg: T) -> Self {
42    Error::new(ErrorKind::Custom(msg.to_string()))
43  }
44
45  /// Creates a new error for a field that appears twice in the input.
46  pub fn duplicate_field(name: &str) -> Self {
47    Error::new(ErrorKind::DuplicateField(name.into()))
48  }
49
50  /// Creates a new error for a non-optional field that does not appear in the input.
51  pub fn missing_field(name: &str) -> Self {
52    Error::new(ErrorKind::MissingField(name.into()))
53  }
54
55  /// Creates a new error for a field name that appears in the input but does not correspond
56  /// to a known field.
57  pub fn unknown_field(name: &str) -> Self {
58    Error::new(ErrorKind::UnknownField(name.into()))
59  }
60
61  /// Creates a new error for a field name that appears in the input but does not correspond to
62  /// a known attribute. The second argument is the list of known attributes; if a similar name
63  /// is found that will be shown in the emitted error message.
64  pub fn unknown_field_with_alts<'a, T, I>(field: &str, alternates: I) -> Self
65  where
66    T: AsRef<str> + 'a,
67    I: IntoIterator<Item = &'a T>,
68  {
69    Error::new(ErrorUnknownField::with_alts(field, alternates).into())
70  }
71
72  /// Creates a new error for a struct or variant that does not adhere to the supported shape.
73  pub fn unsupported_shape(shape: &str) -> Self {
74    Error::new(ErrorKind::UnsupportedShape(shape.into()))
75  }
76
77  pub fn unsupported_format(format: &str) -> Self {
78    Error::new(ErrorKind::UnexpectedFormat(format.into()))
79  }
80
81  /// Creates a new error for a field which has an unexpected literal type.
82  pub fn unexpected_type(ty: &str) -> Self {
83    Error::new(ErrorKind::UnexpectedType(ty.into()))
84  }
85
86  /// Creates a new error for a field which has an unexpected literal type. This will automatically
87  /// extract the literal type name from the passed-in `Lit` and set the span to encompass only the
88  /// literal value.
89  pub fn unexpected_lit_type(lit: &Lit) -> Self {
90    Error::unexpected_type(match *lit {
91      Lit::Str(_) => "string",
92      Lit::ByteStr(_) => "byte string",
93      Lit::Byte(_) => "byte",
94      Lit::Char(_) => "char",
95      Lit::Int(_) => "int",
96      Lit::Float(_) => "float",
97      Lit::Bool(_) => "bool",
98      Lit::Verbatim(_) => "verbatim",
99    })
100    .with_span(lit)
101  }
102
103  /// Creates a new error for a value which doesn't match a set of expected literals.
104  pub fn unknown_value(value: &str) -> Self {
105    Error::new(ErrorKind::UnknownValue(value.into()))
106  }
107
108  /// Creates a new error for a list which did not get enough items to proceed.
109  pub fn too_few_items(min: usize) -> Self {
110    Error::new(ErrorKind::TooFewItems(min))
111  }
112
113  /// Creates a new error when a list got more items than it supports. The `max` argument
114  /// is the largest number of items the receiver could accept.
115  pub fn too_many_items(max: usize) -> Self {
116    Error::new(ErrorKind::TooManyItems(max))
117  }
118
119  /// Bundle a set of multiple errors into a single `Error` instance.
120  ///
121  /// # Panics
122  /// This function will panic if `errors.is_empty() == true`.
123  pub fn multiple(mut errors: Vec<Error>) -> Self {
124    if errors.len() > 1 {
125      Error::new(ErrorKind::Multiple(errors))
126    } else if errors.len() == 1 {
127      errors
128        .pop()
129        .expect("Error array of length 1 has a first item")
130    } else {
131      panic!("Can't deal with 0 errors")
132    }
133  }
134}
135
136impl From<syn::Error> for Error {
137  fn from(e: syn::Error) -> Self {
138    let mut ret = Error::new(ErrorKind::Parse(e.to_string()));
139    ret.span = Some(e.span());
140    ret
141  }
142}
143
144impl Error {
145  /// Create a new error about a literal string that doesn't match a set of known
146  /// or permissible values. This function can be made public if the API proves useful
147  /// beyond impls for `syn` types.
148  pub(crate) fn unknown_lit_str_value(value: &LitStr) -> Self {
149    Error::unknown_value(&value.value()).with_span(value)
150  }
151}
152
153/// Error instance methods
154impl Error {
155  /// Check if this error is associated with a span in the token stream.
156  pub fn has_span(&self) -> bool {
157    self.span.is_some()
158  }
159
160  /// Tie a span to the error if none is already present. This is used in `darling::FromMeta`
161  /// and other traits to attach errors to the most specific possible location in the input
162  /// source code.
163  ///
164  /// All `darling`-built impls, either from the crate or from the proc macro, will call this
165  /// when appropriate during parsing, so it should not be necessary to call this unless you have
166  /// overridden:
167  ///
168  /// * `FromMeta::from_meta`
169  /// * `FromMeta::from_nested_meta`
170  /// * `FromMeta::from_value`
171  pub fn with_span<T: Spanned>(mut self, node: &T) -> Self {
172    if !self.has_span() {
173      self.span = Some(node.span());
174    }
175
176    self
177  }
178
179  /// Recursively converts a tree of errors to a flattened list.
180  pub fn flatten(self) -> Self {
181    Error::multiple(self.into_vec())
182  }
183
184  fn into_vec(self) -> Vec<Self> {
185    if let ErrorKind::Multiple(errors) = self.kind {
186      let mut flat = Vec::new();
187      for error in errors {
188        flat.extend(error.prepend_at(self.locations.clone()).into_vec());
189      }
190
191      flat
192    } else {
193      vec![self]
194    }
195  }
196
197  /// Adds a location to the error, such as a field or variant.
198  /// Locations must be added in reverse order of specificity.
199  pub fn at<T: fmt::Display>(mut self, location: T) -> Self {
200    self.locations.insert(0, location.to_string());
201    self
202  }
203
204  /// Gets the number of individual errors in this error.
205  ///
206  /// This function never returns `0`, as it's impossible to construct
207  /// a multi-error from an empty `Vec`.
208  pub fn len(&self) -> usize {
209    self.kind.len()
210  }
211
212  /// Adds a location chain to the head of the error's existing locations.
213  fn prepend_at(mut self, mut locations: Vec<String>) -> Self {
214    if !locations.is_empty() {
215      locations.extend(self.locations);
216      self.locations = locations;
217    }
218
219    self
220  }
221
222  /// Gets the location slice.
223  #[cfg(test)]
224  pub(crate) fn location(&self) -> Vec<&str> {
225    self.locations.iter().map(|i| i.as_str()).collect()
226  }
227
228  /// Write this error and any children as compile errors into a `TokenStream` to
229  /// be returned by the proc-macro.
230  ///
231  /// Return these tokens unmodified to avoid disturbing the attached span information.
232  pub fn write_errors(self) -> TokenStream {
233    self
234      .flatten()
235      .into_iter()
236      .map(|e| e.single_to_syn_error().to_compile_error())
237      .collect()
238  }
239
240  fn single_to_syn_error(self) -> ::syn::Error {
241    match self.span {
242      Some(span) => ::syn::Error::new(span, self.kind),
243      None => ::syn::Error::new(Span::call_site(), self),
244    }
245  }
246}
247
248impl StdError for Error {
249  fn description(&self) -> &str {
250    &self.kind.description()
251  }
252
253  fn cause(&self) -> Option<&StdError> {
254    None
255  }
256}
257
258impl fmt::Display for Error {
259  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
260    write!(f, "{}", self.kind)?;
261    if !self.locations.is_empty() {
262      write!(f, " at {}", self.locations.join("/"))?;
263    }
264
265    Ok(())
266  }
267}
268
269// Don't want to publicly commit to Error supporting equality yet, but
270// not having it makes testing very difficult. Note that spans are not
271// considered for equality since that would break testing in most cases.
272#[cfg(test)]
273impl PartialEq for Error {
274  fn eq(&self, other: &Self) -> bool {
275    self.kind == other.kind && self.locations == other.locations
276  }
277}
278
279#[cfg(test)]
280impl Eq for Error {}
281
282impl IntoIterator for Error {
283  type Item = Error;
284  type IntoIter = IntoIter;
285
286  fn into_iter(self) -> IntoIter {
287    if let ErrorKind::Multiple(errors) = self.kind {
288      IntoIter {
289        inner: IntoIterEnum::Multiple(errors.into_iter()),
290      }
291    } else {
292      IntoIter {
293        inner: IntoIterEnum::Single(iter::once(self)),
294      }
295    }
296  }
297}
298
299enum IntoIterEnum {
300  Single(iter::Once<Error>),
301  Multiple(vec::IntoIter<Error>),
302}
303
304impl Iterator for IntoIterEnum {
305  type Item = Error;
306
307  fn next(&mut self) -> Option<Self::Item> {
308    match *self {
309      IntoIterEnum::Single(ref mut content) => content.next(),
310      IntoIterEnum::Multiple(ref mut content) => content.next(),
311    }
312  }
313}
314
315/// An iterator that moves out of an `Error`.
316pub struct IntoIter {
317  inner: IntoIterEnum,
318}
319
320impl Iterator for IntoIter {
321  type Item = Error;
322
323  fn next(&mut self) -> Option<Error> {
324    self.inner.next()
325  }
326}
327
328#[cfg(test)]
329mod tests {
330  use super::Error;
331
332  #[test]
333  fn flatten_noop() {
334    let err = Error::duplicate_field("hello").at("world");
335    assert_eq!(err.clone().flatten(), err);
336  }
337
338  #[test]
339  fn flatten_simple() {
340    let err = Error::multiple(vec![
341      Error::unknown_field("hello").at("world"),
342      Error::missing_field("hell_no").at("world"),
343    ])
344    .at("foo")
345    .flatten();
346
347    assert!(err.location().is_empty());
348
349    let mut err_iter = err.into_iter();
350
351    let first = err_iter.next();
352    assert!(first.is_some());
353    assert_eq!(first.unwrap().location(), vec!["foo", "world"]);
354
355    let second = err_iter.next();
356    assert!(second.is_some());
357
358    assert_eq!(second.unwrap().location(), vec!["foo", "world"]);
359
360    assert!(err_iter.next().is_none());
361  }
362
363  #[test]
364  fn len_single() {
365    let err = Error::duplicate_field("hello");
366    assert_eq!(1, err.len());
367  }
368
369  #[test]
370  fn len_multiple() {
371    let err = Error::multiple(vec![
372      Error::duplicate_field("hello"),
373      Error::missing_field("hell_no"),
374    ]);
375    assert_eq!(2, err.len());
376  }
377
378  #[test]
379  fn len_nested() {
380    let err = Error::multiple(vec![
381      Error::duplicate_field("hello"),
382      Error::multiple(vec![
383        Error::duplicate_field("hi"),
384        Error::missing_field("bye"),
385        Error::multiple(vec![Error::duplicate_field("whatsup")]),
386      ]),
387    ]);
388
389    assert_eq!(4, err.len());
390  }
391}