1use alloc::string::{String, ToString};
2use core::{
3 fmt,
4 str::{self, Utf8Error},
5};
6
7use serde::{
8 de,
9 ser::{self, StdError},
10};
11use unicode_ident::is_xid_continue;
12
13use crate::parse::{is_ident_first_char, is_ident_raw_char};
14
15#[cfg(feature = "std")]
16use std::io;
17
18#[allow(clippy::module_name_repetitions)]
21#[derive(Clone, Debug, PartialEq, Eq)]
22pub struct SpannedError {
23 pub code: Error,
24 pub span: Span,
25}
26
27pub type Result<T, E = Error> = core::result::Result<T, E>;
28pub type SpannedResult<T> = core::result::Result<T, SpannedError>;
29
30#[derive(Clone, Debug, PartialEq, Eq)]
31#[non_exhaustive]
32pub enum Error {
33 Fmt,
34 Io(String),
35 Message(String),
36 #[deprecated(
37 since = "0.9.0",
38 note = "ambiguous base64 byte strings are replaced by strongly typed Rusty b\"byte strings\""
39 )]
40 Base64Error(base64::DecodeError),
41 Eof,
42 ExpectedArray,
43 ExpectedArrayEnd,
44 ExpectedAttribute,
45 ExpectedAttributeEnd,
46 ExpectedBoolean,
47 ExpectedComma,
48 ExpectedChar,
49 ExpectedByteLiteral,
50 ExpectedFloat,
51 FloatUnderscore,
52 ExpectedInteger,
53 ExpectedOption,
54 ExpectedOptionEnd,
55 ExpectedMap,
56 ExpectedMapColon,
57 ExpectedMapEnd,
58 ExpectedDifferentStructName {
59 expected: &'static str,
60 found: String,
61 },
62 ExpectedStructLike,
63 ExpectedNamedStructLike(&'static str),
64 ExpectedStructLikeEnd,
65 ExpectedUnit,
66 ExpectedString,
67 ExpectedByteString,
68 ExpectedStringEnd,
69 ExpectedIdentifier,
70
71 InvalidEscape(&'static str),
72
73 IntegerOutOfBounds,
74 InvalidIntegerDigit {
75 digit: char,
76 base: u8,
77 },
78
79 NoSuchExtension(String),
80
81 UnclosedBlockComment,
82 UnclosedLineComment,
83 UnderscoreAtBeginning,
84 UnexpectedChar(char),
85
86 Utf8Error(Utf8Error),
87 TrailingCharacters,
88
89 InvalidValueForType {
90 expected: String,
91 found: String,
92 },
93 ExpectedDifferentLength {
94 expected: String,
95 found: usize,
96 },
97 NoSuchEnumVariant {
98 expected: &'static [&'static str],
99 found: String,
100 outer: Option<String>,
101 },
102 NoSuchStructField {
103 expected: &'static [&'static str],
104 found: String,
105 outer: Option<String>,
106 },
107 MissingStructField {
108 field: &'static str,
109 outer: Option<String>,
110 },
111 DuplicateStructField {
112 field: &'static str,
113 outer: Option<String>,
114 },
115 InvalidIdentifier(String),
116 SuggestRawIdentifier(String),
117 ExpectedRawValue,
118 ExceededRecursionLimit,
119 ExpectedStructName(String),
120}
121
122impl fmt::Display for SpannedError {
123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124 write!(f, "{}: {}", self.span, self.code)
125 }
126}
127
128impl fmt::Display for Error {
129 #[allow(clippy::too_many_lines)]
130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131 match *self {
132 Error::Fmt => f.write_str("Formatting RON failed"),
133 Error::Io(ref s) | Error::Message(ref s) => f.write_str(s),
134 #[allow(deprecated)]
135 Error::Base64Error(ref e) => write!(f, "Invalid base64: {}", e),
136 Error::Eof => f.write_str("Unexpected end of RON"),
137 Error::ExpectedArray => f.write_str("Expected opening `[`"),
138 Error::ExpectedArrayEnd => f.write_str("Expected closing `]`"),
139 Error::ExpectedAttribute => f.write_str("Expected an `#![enable(...)]` attribute"),
140 Error::ExpectedAttributeEnd => {
141 f.write_str("Expected closing `)]` after the enable attribute")
142 }
143 Error::ExpectedBoolean => f.write_str("Expected boolean"),
144 Error::ExpectedComma => f.write_str("Expected comma"),
145 Error::ExpectedChar => f.write_str("Expected char"),
146 Error::ExpectedByteLiteral => f.write_str("Expected byte literal"),
147 Error::ExpectedFloat => f.write_str("Expected float"),
148 Error::FloatUnderscore => f.write_str("Unexpected underscore in float"),
149 Error::ExpectedInteger => f.write_str("Expected integer"),
150 Error::ExpectedOption => f.write_str("Expected option"),
151 Error::ExpectedOptionEnd | Error::ExpectedStructLikeEnd => {
152 f.write_str("Expected closing `)`")
153 }
154 Error::ExpectedMap => f.write_str("Expected opening `{`"),
155 Error::ExpectedMapColon => f.write_str("Expected colon"),
156 Error::ExpectedMapEnd => f.write_str("Expected closing `}`"),
157 Error::ExpectedDifferentStructName {
158 expected,
159 ref found,
160 } => write!(
161 f,
162 "Expected struct {} but found {}",
163 Identifier(expected),
164 Identifier(found)
165 ),
166 Error::ExpectedStructLike => f.write_str("Expected opening `(`"),
167 Error::ExpectedNamedStructLike(name) => {
168 if name.is_empty() {
169 f.write_str("Expected only opening `(`, no name, for un-nameable struct")
170 } else {
171 write!(f, "Expected opening `(` for struct {}", Identifier(name))
172 }
173 }
174 Error::ExpectedUnit => f.write_str("Expected unit"),
175 Error::ExpectedString => f.write_str("Expected string"),
176 Error::ExpectedByteString => f.write_str("Expected byte string"),
177 Error::ExpectedStringEnd => f.write_str("Expected end of string"),
178 Error::ExpectedIdentifier => f.write_str("Expected identifier"),
179 Error::InvalidEscape(s) => f.write_str(s),
180 Error::IntegerOutOfBounds => f.write_str("Integer is out of bounds"),
181 Error::InvalidIntegerDigit { digit, base } => {
182 write!(f, "Invalid digit {:?} for base {} integers", digit, base)
183 }
184 Error::NoSuchExtension(ref name) => {
185 write!(f, "No RON extension named {}", Identifier(name))
186 }
187 Error::Utf8Error(ref e) => fmt::Display::fmt(e, f),
188 Error::UnclosedBlockComment => f.write_str("Unclosed block comment"),
189 Error::UnclosedLineComment => f.write_str(
190 "`ron::value::RawValue` cannot end in unclosed line comment, \
191 try using a block comment or adding a newline",
192 ),
193 Error::UnderscoreAtBeginning => {
194 f.write_str("Unexpected leading underscore in a number")
195 }
196 Error::UnexpectedChar(c) => write!(f, "Unexpected char {:?}", c),
197 Error::TrailingCharacters => f.write_str("Non-whitespace trailing characters"),
198 Error::InvalidValueForType {
199 ref expected,
200 ref found,
201 } => {
202 write!(f, "Expected {} but found {} instead", expected, found)
203 }
204 Error::ExpectedDifferentLength {
205 ref expected,
206 found,
207 } => {
208 write!(f, "Expected {} but found ", expected)?;
209
210 match found {
211 0 => f.write_str("zero elements")?,
212 1 => f.write_str("one element")?,
213 n => write!(f, "{} elements", n)?,
214 }
215
216 f.write_str(" instead")
217 }
218 Error::NoSuchEnumVariant {
219 expected,
220 ref found,
221 ref outer,
222 } => {
223 f.write_str("Unexpected ")?;
224
225 if outer.is_none() {
226 f.write_str("enum ")?;
227 }
228
229 write!(f, "variant named {}", Identifier(found))?;
230
231 if let Some(outer) = outer {
232 write!(f, " in enum {}", Identifier(outer))?;
233 }
234
235 write!(
236 f,
237 ", {}",
238 OneOf {
239 alts: expected,
240 none: "variants"
241 }
242 )
243 }
244 Error::NoSuchStructField {
245 expected,
246 ref found,
247 ref outer,
248 } => {
249 write!(f, "Unexpected field named {}", Identifier(found))?;
250
251 if let Some(outer) = outer {
252 write!(f, " in {}", Identifier(outer))?;
253 }
254
255 write!(
256 f,
257 ", {}",
258 OneOf {
259 alts: expected,
260 none: "fields"
261 }
262 )
263 }
264 Error::MissingStructField { field, ref outer } => {
265 write!(f, "Unexpected missing field named {}", Identifier(field))?;
266
267 match outer {
268 Some(outer) => write!(f, " in {}", Identifier(outer)),
269 None => Ok(()),
270 }
271 }
272 Error::DuplicateStructField { field, ref outer } => {
273 write!(f, "Unexpected duplicate field named {}", Identifier(field))?;
274
275 match outer {
276 Some(outer) => write!(f, " in {}", Identifier(outer)),
277 None => Ok(()),
278 }
279 }
280 Error::InvalidIdentifier(ref invalid) => write!(f, "Invalid identifier {:?}", invalid),
281 Error::SuggestRawIdentifier(ref identifier) => write!(
282 f,
283 "Found invalid std identifier {:?}, try the raw identifier `r#{}` instead",
284 identifier, identifier
285 ),
286 Error::ExpectedRawValue => f.write_str("Expected a `ron::value::RawValue`"),
287 Error::ExceededRecursionLimit => f.write_str(
288 "Exceeded recursion limit, try increasing `ron::Options::recursion_limit` \
289 and using `serde_stacker` to protect against a stack overflow",
290 ),
291 Error::ExpectedStructName(ref name) => write!(
292 f,
293 "Expected the explicit struct name {}, but none was found",
294 Identifier(name)
295 ),
296 }
297 }
298}
299
300#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
301pub struct Position {
302 pub line: usize,
303 pub col: usize,
304}
305
306impl Position {
307 pub(crate) fn from_src_end(src: &str) -> Position {
308 let line = 1 + src.chars().filter(|&c| c == '\n').count();
309 let col = 1 + src.chars().rev().take_while(|&c| c != '\n').count();
310
311 Self { line, col }
312 }
313}
314
315impl fmt::Display for Position {
316 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317 write!(f, "{}:{}", self.line, self.col)
318 }
319}
320
321#[derive(Clone, Debug, PartialEq, Eq)]
322pub struct Span {
326 pub start: Position,
327 pub end: Position,
328}
329
330impl fmt::Display for Span {
331 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
332 if self.start == self.end {
333 write!(f, "{}", self.start)
334 } else {
335 write!(f, "{}-{}", self.start, self.end)
336 }
337 }
338}
339
340impl ser::Error for Error {
341 #[cold]
342 fn custom<T: fmt::Display>(msg: T) -> Self {
343 Error::Message(msg.to_string())
344 }
345}
346
347impl de::Error for Error {
348 #[cold]
349 fn custom<T: fmt::Display>(msg: T) -> Self {
350 Error::Message(msg.to_string())
351 }
352
353 #[cold]
354 fn invalid_type(unexp: de::Unexpected, exp: &dyn de::Expected) -> Self {
355 Self::invalid_value(unexp, exp)
357 }
358
359 #[cold]
360 fn invalid_value(unexp: de::Unexpected, exp: &dyn de::Expected) -> Self {
361 struct UnexpectedSerdeTypeValue<'a>(de::Unexpected<'a>);
362
363 impl<'a> fmt::Display for UnexpectedSerdeTypeValue<'a> {
364 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
365 match self.0 {
366 de::Unexpected::Bool(b) => write!(f, "the boolean `{}`", b),
367 de::Unexpected::Unsigned(i) => write!(f, "the unsigned integer `{}`", i),
368 de::Unexpected::Signed(i) => write!(f, "the signed integer `{}`", i),
369 de::Unexpected::Float(n) => write!(f, "the floating point number `{}`", n),
370 de::Unexpected::Char(c) => write!(f, "the UTF-8 character `{}`", c),
371 de::Unexpected::Str(s) => write!(f, "the string {:?}", s),
372 de::Unexpected::Bytes(b) => write!(f, "the byte string b\"{}\"", {
373 b.iter()
374 .flat_map(|c| core::ascii::escape_default(*c))
375 .map(char::from)
376 .collect::<String>()
377 }),
378 de::Unexpected::Unit => write!(f, "a unit value"),
379 de::Unexpected::Option => write!(f, "an optional value"),
380 de::Unexpected::NewtypeStruct => write!(f, "a newtype struct"),
381 de::Unexpected::Seq => write!(f, "a sequence"),
382 de::Unexpected::Map => write!(f, "a map"),
383 de::Unexpected::Enum => write!(f, "an enum"),
384 de::Unexpected::UnitVariant => write!(f, "a unit variant"),
385 de::Unexpected::NewtypeVariant => write!(f, "a newtype variant"),
386 de::Unexpected::TupleVariant => write!(f, "a tuple variant"),
387 de::Unexpected::StructVariant => write!(f, "a struct variant"),
388 de::Unexpected::Other(other) => f.write_str(other),
389 }
390 }
391 }
392
393 Error::InvalidValueForType {
394 expected: exp.to_string(),
395 found: UnexpectedSerdeTypeValue(unexp).to_string(),
396 }
397 }
398
399 #[cold]
400 fn invalid_length(len: usize, exp: &dyn de::Expected) -> Self {
401 Error::ExpectedDifferentLength {
402 expected: exp.to_string(),
403 found: len,
404 }
405 }
406
407 #[cold]
408 fn unknown_variant(variant: &str, expected: &'static [&'static str]) -> Self {
409 Error::NoSuchEnumVariant {
410 expected,
411 found: variant.to_string(),
412 outer: None,
413 }
414 }
415
416 #[cold]
417 fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self {
418 Error::NoSuchStructField {
419 expected,
420 found: field.to_string(),
421 outer: None,
422 }
423 }
424
425 #[cold]
426 fn missing_field(field: &'static str) -> Self {
427 Error::MissingStructField { field, outer: None }
428 }
429
430 #[cold]
431 fn duplicate_field(field: &'static str) -> Self {
432 Error::DuplicateStructField { field, outer: None }
433 }
434}
435
436impl StdError for SpannedError {}
437
438impl StdError for Error {}
439
440impl From<Utf8Error> for Error {
441 fn from(e: Utf8Error) -> Self {
442 Error::Utf8Error(e)
443 }
444}
445
446impl From<fmt::Error> for Error {
447 fn from(_: fmt::Error) -> Self {
448 Error::Fmt
449 }
450}
451
452#[cfg(feature = "std")]
453impl From<io::Error> for Error {
454 fn from(e: io::Error) -> Self {
455 Error::Io(e.to_string())
456 }
457}
458
459impl From<SpannedError> for Error {
460 fn from(e: SpannedError) -> Self {
461 e.code
462 }
463}
464
465struct OneOf {
466 alts: &'static [&'static str],
467 none: &'static str,
468}
469
470impl fmt::Display for OneOf {
471 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
472 match self.alts {
473 [] => write!(f, "there are no {}", self.none),
474 [a1] => write!(f, "expected {} instead", Identifier(a1)),
475 [a1, a2] => write!(
476 f,
477 "expected either {} or {} instead",
478 Identifier(a1),
479 Identifier(a2)
480 ),
481 [a1, ref alts @ .., an] => {
482 write!(f, "expected one of {}", Identifier(a1))?;
483
484 for alt in alts {
485 write!(f, ", {}", Identifier(alt))?;
486 }
487
488 write!(f, ", or {} instead", Identifier(an))
489 }
490 }
491 }
492}
493
494struct Identifier<'a>(&'a str);
495
496impl<'a> fmt::Display for Identifier<'a> {
497 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
498 if self.0.is_empty() || !self.0.chars().all(is_ident_raw_char) {
499 return write!(f, "{:?}_[invalid identifier]", self.0);
500 }
501
502 let mut chars = self.0.chars();
503
504 if !chars.next().map_or(false, is_ident_first_char) || !chars.all(is_xid_continue) {
505 write!(f, "`r#{}`", self.0)
506 } else {
507 write!(f, "`{}`", self.0)
508 }
509 }
510}
511
512#[cfg(test)]
513mod tests {
514 use alloc::{format, string::String};
515
516 use serde::{de::Error as DeError, de::Unexpected, ser::Error as SerError};
517
518 use super::{Error, Position, Span, SpannedError};
519
520 #[test]
521 fn error_messages() {
522 check_error_message(&Error::from(core::fmt::Error), "Formatting RON failed");
523 #[cfg(feature = "std")]
524 check_error_message(
525 &Error::from(std::io::Error::new(
526 std::io::ErrorKind::InvalidData,
527 "my-error",
528 )),
529 "my-error",
530 );
531 check_error_message(&<Error as SerError>::custom("my-ser-error"), "my-ser-error");
532 check_error_message(&<Error as DeError>::custom("my-de-error"), "my-de-error");
533 #[allow(deprecated)]
534 check_error_message(
535 &Error::Base64Error(base64::DecodeError::InvalidPadding),
536 "Invalid base64: Invalid padding",
537 );
538 check_error_message(&Error::Eof, "Unexpected end of RON");
539 check_error_message(&Error::ExpectedArray, "Expected opening `[`");
540 check_error_message(&Error::ExpectedArrayEnd, "Expected closing `]`");
541 check_error_message(
542 &Error::ExpectedAttribute,
543 "Expected an `#![enable(...)]` attribute",
544 );
545 check_error_message(
546 &Error::ExpectedAttributeEnd,
547 "Expected closing `)]` after the enable attribute",
548 );
549 check_error_message(&Error::ExpectedBoolean, "Expected boolean");
550 check_error_message(&Error::ExpectedComma, "Expected comma");
551 check_error_message(&Error::ExpectedChar, "Expected char");
552 check_error_message(&Error::ExpectedByteLiteral, "Expected byte literal");
553 check_error_message(&Error::ExpectedFloat, "Expected float");
554 check_error_message(&Error::FloatUnderscore, "Unexpected underscore in float");
555 check_error_message(&Error::ExpectedInteger, "Expected integer");
556 check_error_message(&Error::ExpectedOption, "Expected option");
557 check_error_message(&Error::ExpectedOptionEnd, "Expected closing `)`");
558 check_error_message(&Error::ExpectedStructLikeEnd, "Expected closing `)`");
559 check_error_message(&Error::ExpectedMap, "Expected opening `{`");
560 check_error_message(&Error::ExpectedMapColon, "Expected colon");
561 check_error_message(&Error::ExpectedMapEnd, "Expected closing `}`");
562 check_error_message(
563 &Error::ExpectedDifferentStructName {
564 expected: "raw+identifier",
565 found: String::from("identifier"),
566 },
567 "Expected struct `r#raw+identifier` but found `identifier`",
568 );
569 check_error_message(&Error::ExpectedStructLike, "Expected opening `(`");
570 check_error_message(
571 &Error::ExpectedNamedStructLike(""),
572 "Expected only opening `(`, no name, for un-nameable struct",
573 );
574 check_error_message(
575 &Error::ExpectedNamedStructLike("_ident"),
576 "Expected opening `(` for struct `_ident`",
577 );
578 check_error_message(&Error::ExpectedUnit, "Expected unit");
579 check_error_message(&Error::ExpectedString, "Expected string");
580 check_error_message(&Error::ExpectedByteString, "Expected byte string");
581 check_error_message(&Error::ExpectedStringEnd, "Expected end of string");
582 check_error_message(&Error::ExpectedIdentifier, "Expected identifier");
583 check_error_message(&Error::InvalidEscape("Invalid escape"), "Invalid escape");
584 check_error_message(&Error::IntegerOutOfBounds, "Integer is out of bounds");
585 check_error_message(
586 &Error::InvalidIntegerDigit {
587 digit: 'q',
588 base: 16,
589 },
590 "Invalid digit 'q' for base 16 integers",
591 );
592 check_error_message(
593 &Error::NoSuchExtension(String::from("unknown")),
594 "No RON extension named `unknown`",
595 );
596 check_error_message(&Error::UnclosedBlockComment, "Unclosed block comment");
597 check_error_message(
598 &Error::UnclosedLineComment,
599 "`ron::value::RawValue` cannot end in unclosed line comment, \
600 try using a block comment or adding a newline",
601 );
602 check_error_message(
603 &Error::UnderscoreAtBeginning,
604 "Unexpected leading underscore in a number",
605 );
606 check_error_message(&Error::UnexpectedChar('🦀'), "Unexpected char \'🦀\'");
607 #[allow(invalid_from_utf8)]
608 check_error_message(
609 &Error::Utf8Error(core::str::from_utf8(b"error: \xff\xff\xff\xff").unwrap_err()),
610 "invalid utf-8 sequence of 1 bytes from index 7",
611 );
612 check_error_message(
613 &Error::TrailingCharacters,
614 "Non-whitespace trailing characters",
615 );
616 check_error_message(
617 &Error::invalid_value(Unexpected::Enum, &"struct `Hi`"),
618 "Expected struct `Hi` but found an enum instead",
619 );
620 check_error_message(
621 &Error::invalid_length(0, &"two bees"),
622 "Expected two bees but found zero elements instead",
623 );
624 check_error_message(
625 &Error::invalid_length(1, &"two bees"),
626 "Expected two bees but found one element instead",
627 );
628 check_error_message(
629 &Error::invalid_length(3, &"two bees"),
630 "Expected two bees but found 3 elements instead",
631 );
632 check_error_message(
633 &Error::unknown_variant("unknown", &[]),
634 "Unexpected enum variant named `unknown`, there are no variants",
635 );
636 check_error_message(
637 &Error::NoSuchEnumVariant {
638 expected: &["A", "B+C"],
639 found: String::from("D"),
640 outer: Some(String::from("E")),
641 },
642 "Unexpected variant named `D` in enum `E`, \
643 expected either `A` or `r#B+C` instead",
644 );
645 check_error_message(
646 &Error::unknown_field("unknown", &[]),
647 "Unexpected field named `unknown`, there are no fields",
648 );
649 check_error_message(
650 &Error::NoSuchStructField {
651 expected: &["a"],
652 found: String::from("b"),
653 outer: Some(String::from("S")),
654 },
655 "Unexpected field named `b` in `S`, expected `a` instead",
656 );
657 check_error_message(
658 &Error::NoSuchStructField {
659 expected: &["a", "b+c", "d"],
660 found: String::from("e"),
661 outer: Some(String::from("S")),
662 },
663 "Unexpected field named `e` in `S`, \
664 expected one of `a`, `r#b+c`, or `d` instead",
665 );
666 check_error_message(
667 &Error::missing_field("a"),
668 "Unexpected missing field named `a`",
669 );
670 check_error_message(
671 &Error::MissingStructField {
672 field: "",
673 outer: Some(String::from("S+T")),
674 },
675 "Unexpected missing field named \"\"_[invalid identifier] in `r#S+T`",
676 );
677 check_error_message(
678 &Error::duplicate_field("a"),
679 "Unexpected duplicate field named `a`",
680 );
681 check_error_message(
682 &Error::DuplicateStructField {
683 field: "b+c",
684 outer: Some(String::from("S+T")),
685 },
686 "Unexpected duplicate field named `r#b+c` in `r#S+T`",
687 );
688 check_error_message(
689 &Error::InvalidIdentifier(String::from("why+🦀+not")),
690 "Invalid identifier \"why+🦀+not\"",
691 );
692 check_error_message(
693 &Error::SuggestRawIdentifier(String::from("raw+ident")),
694 "Found invalid std identifier \"raw+ident\", \
695 try the raw identifier `r#raw+ident` instead",
696 );
697 check_error_message(
698 &Error::ExpectedRawValue,
699 "Expected a `ron::value::RawValue`",
700 );
701 check_error_message(
702 &Error::ExceededRecursionLimit,
703 "Exceeded recursion limit, try increasing `ron::Options::recursion_limit` \
704 and using `serde_stacker` to protect against a stack overflow",
705 );
706 check_error_message(
707 &Error::ExpectedStructName(String::from("Struct")),
708 "Expected the explicit struct name `Struct`, but none was found",
709 );
710 }
711
712 fn check_error_message<T: core::fmt::Display>(err: &T, msg: &str) {
713 assert_eq!(format!("{}", err), msg);
714 }
715
716 #[test]
717 fn spanned_error_into_code() {
718 assert_eq!(
719 Error::from(SpannedError {
720 code: Error::Eof,
721 span: Span {
722 start: Position { line: 1, col: 1 },
723 end: Position { line: 1, col: 5 },
724 }
725 }),
726 Error::Eof
727 );
728 assert_eq!(
729 Error::from(SpannedError {
730 code: Error::ExpectedRawValue,
731 span: Span {
732 start: Position { line: 1, col: 1 },
733 end: Position { line: 1, col: 5 },
734 }
735 }),
736 Error::ExpectedRawValue
737 );
738 }
739}