1extern crate core;
13use self::core::fmt::{self,Display,Formatter};
14#[cfg(feature="std")]
15use std::error::Error;
16
17
18macro_rules! description {($err:ty, $desc:expr) => {
19 #[cfg(not(feature="std"))]
20 impl $err {
21 #[allow(missing_docs)]
22 pub fn description(&self) -> &'static str {
23 ($desc)(self)
24 }
25 }
26 #[cfg(feature="std")]
27 impl Error for $err {
28 fn description(&self) -> &'static str {
29 ($desc)(self)
30 }
31 }
32 impl Display for $err {
33 fn fmt(&self, fmtr: &mut Formatter) -> fmt::Result {
34 write!(fmtr, "{}", self.description())
35 }
36 }
37}}
38
39
40macro_rules! single_cause {(#[$doc1:meta] #[$doc2:meta] $err:ident => $desc:expr) => {
41 #[$doc1]
43 #[$doc2]
44 #[derive(Clone,Copy, Debug, PartialEq,Eq)]
45 pub struct $err;
46 description!{$err, |_| $desc }
47}}
48
49
50single_cause!{
51 InvalidUtf16FirstUnit => "is a trailing surrogate"
54}
55
56single_cause!{
57 EmptyStrError => "is empty"
60}
61
62single_cause!{
63 NonAsciiError => "is not an ASCII character"
66}
67
68single_cause!{
69 NonBMPError => "is not a codepoint in the basic multilingual plane"
72}
73
74
75
76macro_rules! simple {(#[$tydoc:meta] $err:ident {
77 $($(#[$vardoc:meta])* ::$variant:ident => $string:expr),+,
78 } ) => {
79 #[$tydoc]
80 #[derive(Clone,Copy, Debug, PartialEq,Eq)]
81 pub enum $err {
82 $($(#[$vardoc])* $variant),*
83 }
84 description!{$err, |e: &$err| match *e {$($err::$variant=>$string),*} }
85}}
86
87
88simple!{InvalidCodepoint {
90 ::Utf16Reserved => "is reserved for UTF-16 surrogate pairs",
92 ::TooHigh => "is higher than the highest codepoint",
94 }}
95use self::InvalidCodepoint::*;
96impl InvalidCodepoint {
97 pub fn error_range(self) -> (u32,u32) {match self {
99 Utf16Reserved => (0xd8_00, 0xdf_ff),
100 TooHigh => (0x00_10_ff_ff, 0xff_ff_ff_ff),
101 }}
102}
103
104
105simple!{InvalidUtf16Array {
107 ::FirstIsTrailingSurrogate => "the first unit is a trailing surrogate, which is never valid",
109 ::SecondIsNotTrailingSurrogate => "the second unit is needed but is not a trailing surrogate",
111 }}
112
113simple!{InvalidUtf16Tuple {
115 ::FirstIsTrailingSurrogate => "the first unit is a trailing / low surrogate, which is never valid",
119 ::SuperfluousSecond => "the second unit is superfluous",
121 ::MissingSecond => "the first unit requires a second unit",
123 ::InvalidSecond => "the required second unit is not a trailing / low surrogate",
127 }}
128
129
130simple!{InvalidUtf16Slice {
132 ::EmptySlice => "the slice is empty",
134 ::FirstLowSurrogate => "the first unit is a trailing surrogate",
136 ::MissingSecond => "the first and only unit requires a second one",
138 ::SecondNotLowSurrogate => "the required second unit is not a trailing surrogate",
140 }}
141
142simple!{Utf16PairError {
144 ::UnexpectedTrailingSurrogate => "a trailing surrogate was not preceeded by a leading surrogate",
146 ::UnmatchedLeadingSurrogate => "a leading surrogate was followed by an unit that was not a trailing surrogate",
148 ::Incomplete => "a trailing surrogate was expected when the end was reached",
150 }}
151
152
153simple!{FromStrError {
155 ::MultipleCodepoints => "has more than one codepoint",
157 ::Empty => "is empty",
159 }}
160
161
162simple!{InvalidUtf8FirstByte {
164 ::TooLongSeqence => "is greater than 247 (UTF-8 sequences cannot be longer than four bytes)",
166 ::ContinuationByte => "is a continuation of a previous sequence",
168 }}
169use self::InvalidUtf8FirstByte::*;
170
171
172
173macro_rules! complex {
174($err:ty
175 {$($sub:ty => $to:expr,)*}
176 {$($desc:pat => $string:expr),+,}
177 => $use_cause:expr =>
178 {$($cause:pat => $result:expr),+,} $(#[$causedoc:meta])*
179) => {
180 $(impl From<$sub> for $err {
181 fn from(error: $sub) -> $err {
182 $to(error)
183 }
184 })*
185 #[cfg(not(feature="std"))]
186 impl $err {
187 #[allow(missing_docs)]
188 pub fn description(&self) -> &'static str {
189 match *self{ $($desc => $string,)* }
190 }
191 fn cause(&self) -> Option<&Display> {None}
193 }
194 #[cfg(feature="std")]
195 impl Error for $err {
196 fn description(&self) -> &'static str {
197 match *self{ $($desc => $string,)* }
198 }
199 $(#[$causedoc])*
200 fn cause(&self) -> Option<&Error> {
201 match *self{ $($cause => $result,)* }
202 }
203 }
204 impl Display for $err {
205 fn fmt(&self, fmtr: &mut Formatter) -> fmt::Result {
206 match (self.cause(), $use_cause) {
207 (Some(d),true) => write!(fmtr, "{}: {}", self.description(), d),
208 _ => write!(fmtr, "{}", self.description()),
209 }
210 }
211 }
212}}
213
214
215#[derive(Clone,Copy, Debug, PartialEq,Eq)]
218pub enum InvalidUtf8 {
219 FirstByte(InvalidUtf8FirstByte),
221 NotAContinuationByte(usize),
224 OverLong,
229}
230use self::InvalidUtf8::*;
231complex!{InvalidUtf8 {
232 InvalidUtf8FirstByte => FirstByte,
233 } {
234 FirstByte(TooLongSeqence) => "the first byte is greater than 239 (UTF-8 sequences cannot be longer than four bytes)",
235 FirstByte(ContinuationByte) => "the first byte is a continuation of a previous sequence",
236 OverLong => "the sequence contains too many zeros and could be shorter",
237 NotAContinuationByte(_) => "the sequence is too short",
238 } => false => {
239 FirstByte(ref cause) => Some(cause),
240 _ => None,
241 }}
243
244
245#[derive(Clone,Copy, Debug, PartialEq,Eq)]
247pub enum InvalidUtf8Array {
248 Utf8(InvalidUtf8),
250 Codepoint(InvalidCodepoint),
252}
253complex!{InvalidUtf8Array {
254 InvalidUtf8 => InvalidUtf8Array::Utf8,
255 InvalidCodepoint => InvalidUtf8Array::Codepoint,
256 } {
257 InvalidUtf8Array::Utf8(_) => "the sequence is invalid UTF-8",
258 InvalidUtf8Array::Codepoint(_) => "the encoded codepoint is invalid",
259 } => true => {
260 InvalidUtf8Array::Utf8(ref u) => Some(u),
261 InvalidUtf8Array::Codepoint(ref c) => Some(c),
262 }}
264
265
266#[derive(Clone,Copy, Debug, PartialEq,Eq)]
268pub enum InvalidUtf8Slice {
269 Utf8(InvalidUtf8),
271 Codepoint(InvalidCodepoint),
273 TooShort(usize),
275}
276complex!{InvalidUtf8Slice {
277 InvalidUtf8 => InvalidUtf8Slice::Utf8,
278 InvalidCodepoint => InvalidUtf8Slice::Codepoint,
279 } {
280 InvalidUtf8Slice::Utf8(_) => "the sequence is invalid UTF-8",
281 InvalidUtf8Slice::Codepoint(_) => "the encoded codepoint is invalid",
282 InvalidUtf8Slice::TooShort(1) => "the slice is empty",
283 InvalidUtf8Slice::TooShort(_) => "the slice is shorter than the sequence",
284 } => true => {
285 InvalidUtf8Slice::Utf8(ref u) => Some(u),
286 InvalidUtf8Slice::Codepoint(ref c) => Some(c),
287 InvalidUtf8Slice::TooShort(_) => None,
288 }
289}