1 use std::fmt;
2 
3 use error::Error;
4 
5 type DeriveInputShape = String;
6 type FieldName = String;
7 type MetaFormat = String;
8 
9 #[derive(Debug)]
10 // Don't want to publicly commit to ErrorKind supporting equality yet, but
11 // not having it makes testing very difficult.
12 #[cfg_attr(test, derive(Clone, PartialEq, Eq))]
13 pub(in error) enum ErrorKind {
14     /// An arbitrary error message.
15     Custom(String),
16     DuplicateField(FieldName),
17     MissingField(FieldName),
18     UnsupportedShape(DeriveInputShape),
19     UnknownField(ErrorUnknownField),
20     UnexpectedFormat(MetaFormat),
21     UnexpectedType(String),
22     UnknownValue(String),
23     TooFewItems(usize),
24     TooManyItems(usize),
25     /// A set of errors.
26     Multiple(Vec<Error>),
27 
28     // TODO make this variant take `!` so it can't exist
29     #[doc(hidden)]
30     __NonExhaustive,
31 }
32 
33 impl ErrorKind {
description(&self) -> &str34     pub fn description(&self) -> &str {
35         use self::ErrorKind::*;
36 
37         match *self {
38             Custom(ref s) => s,
39             DuplicateField(_) => "Duplicate field",
40             MissingField(_) => "Missing field",
41             UnknownField(_) => "Unexpected field",
42             UnsupportedShape(_) => "Unsupported shape",
43             UnexpectedFormat(_) => "Unexpected meta-item format",
44             UnexpectedType(_) => "Unexpected literal type",
45             UnknownValue(_) => "Unknown literal value",
46             TooFewItems(_) => "Too few items",
47             TooManyItems(_) => "Too many items",
48             Multiple(_) => "Multiple errors",
49             __NonExhaustive => unreachable!(),
50         }
51     }
52 
53     /// Deeply counts the number of errors this item represents.
len(&self) -> usize54     pub fn len(&self) -> usize {
55         if let ErrorKind::Multiple(ref items) = *self {
56             items.iter().map(Error::len).sum()
57         } else {
58             1
59         }
60     }
61 }
62 
63 impl fmt::Display for ErrorKind {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result64     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65         use self::ErrorKind::*;
66 
67         match *self {
68             Custom(ref s) => s.fmt(f),
69             DuplicateField(ref field) => write!(f, "Duplicate field `{}`", field),
70             MissingField(ref field) => write!(f, "Missing field `{}`", field),
71             UnknownField(ref field) => field.fmt(f),
72             UnsupportedShape(ref shape) => write!(f, "Unsupported shape `{}`", shape),
73             UnexpectedFormat(ref format) => write!(f, "Unexpected meta-item format `{}`", format),
74             UnexpectedType(ref ty) => write!(f, "Unexpected literal type `{}`", ty),
75             UnknownValue(ref val) => write!(f, "Unknown literal value `{}`", val),
76             TooFewItems(ref min) => write!(f, "Too few items: Expected at least {}", min),
77             TooManyItems(ref max) => write!(f, "Too many items: Expected no more than {}", max),
78             Multiple(ref items) if items.len() == 1 => items[0].fmt(f),
79             Multiple(ref items) => {
80                 write!(f, "Multiple errors: (")?;
81                 let mut first = true;
82                 for item in items {
83                     if !first {
84                         write!(f, ", ")?;
85                     } else {
86                         first = false;
87                     }
88 
89                     item.fmt(f)?;
90                 }
91 
92                 write!(f, ")")
93             }
94             __NonExhaustive => unreachable!(),
95         }
96     }
97 }
98 
99 impl From<ErrorUnknownField> for ErrorKind {
from(err: ErrorUnknownField) -> Self100     fn from(err: ErrorUnknownField) -> Self {
101         ErrorKind::UnknownField(err)
102     }
103 }
104 
105 /// An error for an unknown field, with a possible "did-you-mean" suggestion to get
106 /// the user back on the right track.
107 #[derive(Debug)]
108 // Don't want to publicly commit to ErrorKind supporting equality yet, but
109 // not having it makes testing very difficult.
110 #[cfg_attr(test, derive(Clone, PartialEq, Eq))]
111 pub(in error) struct ErrorUnknownField {
112     name: String,
113     did_you_mean: Option<String>,
114 }
115 
116 impl ErrorUnknownField {
new<I: Into<String>>(name: I, did_you_mean: Option<String>) -> Self117     pub fn new<I: Into<String>>(name: I, did_you_mean: Option<String>) -> Self {
118         ErrorUnknownField {
119             name: name.into(),
120             did_you_mean,
121         }
122     }
123 
with_alts<'a, T, I>(field: &str, alternates: I) -> Self where T: AsRef<str> + 'a, I: IntoIterator<Item = &'a T>,124     pub fn with_alts<'a, T, I>(field: &str, alternates: I) -> Self
125     where
126         T: AsRef<str> + 'a,
127         I: IntoIterator<Item = &'a T>,
128     {
129         ErrorUnknownField::new(field, did_you_mean(field, alternates))
130     }
131 
132     #[cfg(feature = "diagnostics")]
to_diagnostic(self, span: Option<::proc_macro2::Span>) -> ::proc_macro::Diagnostic133     pub fn to_diagnostic(self, span: Option<::proc_macro2::Span>) -> ::proc_macro::Diagnostic {
134         let base = span
135             .unwrap_or_else(::proc_macro2::Span::call_site)
136             .unwrap()
137             .error(self.top_line());
138         match self.did_you_mean {
139             Some(alt_name) => base.help(format!("did you mean `{}`?", alt_name)),
140             None => base,
141         }
142     }
143 
144     #[cfg(feature = "diagnostics")]
top_line(&self) -> String145     fn top_line(&self) -> String {
146         format!("Unknown field: `{}`", self.name)
147     }
148 }
149 
150 impl From<String> for ErrorUnknownField {
from(name: String) -> Self151     fn from(name: String) -> Self {
152         ErrorUnknownField::new(name, None)
153     }
154 }
155 
156 impl<'a> From<&'a str> for ErrorUnknownField {
from(name: &'a str) -> Self157     fn from(name: &'a str) -> Self {
158         ErrorUnknownField::new(name, None)
159     }
160 }
161 
162 impl fmt::Display for ErrorUnknownField {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result163     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164         write!(f, "Unknown field: `{}`", self.name)?;
165 
166         if let Some(ref did_you_mean) = self.did_you_mean {
167             write!(f, ". Did you mean `{}`?", did_you_mean)?;
168         }
169 
170         Ok(())
171     }
172 }
173 
174 #[cfg(feature = "suggestions")]
did_you_mean<'a, T, I>(field: &str, alternates: I) -> Option<String> where T: AsRef<str> + 'a, I: IntoIterator<Item = &'a T>,175 fn did_you_mean<'a, T, I>(field: &str, alternates: I) -> Option<String>
176 where
177     T: AsRef<str> + 'a,
178     I: IntoIterator<Item = &'a T>,
179 {
180     let mut candidate: Option<(f64, &str)> = None;
181     for pv in alternates {
182         let confidence = ::strsim::jaro_winkler(field, pv.as_ref());
183         if confidence > 0.8 && (candidate.is_none() || (candidate.as_ref().unwrap().0 < confidence))
184         {
185             candidate = Some((confidence, pv.as_ref()));
186         }
187     }
188     match candidate {
189         None => None,
190         Some((_, candidate)) => Some(candidate.into()),
191     }
192 }
193 
194 #[cfg(not(feature = "suggestions"))]
did_you_mean<'a, T, I>(_field: &str, _alternates: I) -> Option<String> where T: AsRef<str> + 'a, I: IntoIterator<Item = &'a T>,195 fn did_you_mean<'a, T, I>(_field: &str, _alternates: I) -> Option<String>
196 where
197     T: AsRef<str> + 'a,
198     I: IntoIterator<Item = &'a T>,
199 {
200     None
201 }
202