1
use alloc::string::{String, ToString};
2
use core::{
3
    fmt,
4
    str::{self, Utf8Error},
5
};
6

            
7
use serde::{
8
    de,
9
    ser::{self, StdError},
10
};
11
use unicode_ident::is_xid_continue;
12

            
13
use crate::parse::{is_ident_first_char, is_ident_raw_char};
14

            
15
#[cfg(feature = "std")]
16
use std::io;
17

            
18
/// This type represents all possible errors that can occur when
19
/// serializing or deserializing RON data.
20
#[allow(clippy::module_name_repetitions)]
21
#[derive(Clone, Debug, PartialEq, Eq)]
22
pub struct SpannedError {
23
    pub code: Error,
24
    pub span: Span,
25
}
26

            
27
pub type Result<T, E = Error> = core::result::Result<T, E>;
28
pub type SpannedResult<T> = core::result::Result<T, SpannedError>;
29

            
30
#[derive(Clone, Debug, PartialEq, Eq)]
31
#[non_exhaustive]
32
pub enum Error {
33
    Fmt,
34
    Io(String),
35
    Message(String),
36
    Eof,
37
    ExpectedArray,
38
    ExpectedArrayEnd,
39
    ExpectedAttribute,
40
    ExpectedAttributeEnd,
41
    ExpectedBoolean,
42
    ExpectedComma,
43
    ExpectedChar,
44
    ExpectedByteLiteral,
45
    ExpectedFloat,
46
    FloatUnderscore,
47
    ExpectedInteger,
48
    ExpectedOption,
49
    ExpectedOptionEnd,
50
    ExpectedMap,
51
    ExpectedMapColon,
52
    ExpectedMapEnd,
53
    ExpectedDifferentStructName {
54
        expected: &'static str,
55
        found: String,
56
    },
57
    ExpectedStructLike,
58
    ExpectedNamedStructLike(&'static str),
59
    ExpectedStructLikeEnd,
60
    ExpectedUnit,
61
    ExpectedString,
62
    ExpectedByteString,
63
    ExpectedStringEnd,
64
    ExpectedIdentifier,
65

            
66
    InvalidEscape(&'static str),
67

            
68
    IntegerOutOfBounds,
69
    InvalidIntegerDigit {
70
        digit: char,
71
        base: u8,
72
    },
73

            
74
    NoSuchExtension(String),
75

            
76
    UnclosedBlockComment,
77
    UnclosedLineComment,
78
    UnderscoreAtBeginning,
79
    UnexpectedChar(char),
80

            
81
    Utf8Error(Utf8Error),
82
    TrailingCharacters,
83

            
84
    InvalidValueForType {
85
        expected: String,
86
        found: String,
87
    },
88
    ExpectedDifferentLength {
89
        expected: String,
90
        found: usize,
91
    },
92
    NoSuchEnumVariant {
93
        expected: &'static [&'static str],
94
        found: String,
95
        outer: Option<String>,
96
    },
97
    NoSuchStructField {
98
        expected: &'static [&'static str],
99
        found: String,
100
        outer: Option<String>,
101
    },
102
    MissingStructField {
103
        field: &'static str,
104
        outer: Option<String>,
105
    },
106
    DuplicateStructField {
107
        field: &'static str,
108
        outer: Option<String>,
109
    },
110
    InvalidIdentifier(String),
111
    SuggestRawIdentifier(String),
112
    ExpectedRawValue,
113
    ExceededRecursionLimit,
114
    ExpectedStructName(String),
115
    ExpectedRangeSyntax,
116
}
117

            
118
impl fmt::Display for SpannedError {
119
1470
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120
1470
        write!(f, "{}: {}", self.span, self.code)
121
1470
    }
122
}
123

            
124
impl fmt::Display for Error {
125
    #[allow(clippy::too_many_lines)]
126
2298
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127
2298
        match *self {
128
4
            Error::Fmt => f.write_str("Formatting RON failed"),
129
12
            Error::Io(ref s) | Error::Message(ref s) => f.write_str(s),
130
298
            Error::Eof => f.write_str("Unexpected end of RON"),
131
4
            Error::ExpectedArray => f.write_str("Expected opening `[`"),
132
4
            Error::ExpectedArrayEnd => f.write_str("Expected closing `]`"),
133
4
            Error::ExpectedAttribute => f.write_str("Expected an `#![enable(...)]` attribute"),
134
            Error::ExpectedAttributeEnd => {
135
4
                f.write_str("Expected closing `)]` after the enable attribute")
136
            }
137
4
            Error::ExpectedBoolean => f.write_str("Expected boolean"),
138
4
            Error::ExpectedComma => f.write_str("Expected comma"),
139
4
            Error::ExpectedChar => f.write_str("Expected char"),
140
298
            Error::ExpectedByteLiteral => f.write_str("Expected byte literal"),
141
4
            Error::ExpectedFloat => f.write_str("Expected float"),
142
4
            Error::FloatUnderscore => f.write_str("Unexpected underscore in float"),
143
4
            Error::ExpectedInteger => f.write_str("Expected integer"),
144
4
            Error::ExpectedOption => f.write_str("Expected option"),
145
            Error::ExpectedOptionEnd | Error::ExpectedStructLikeEnd => {
146
8
                f.write_str("Expected closing `)`")
147
            }
148
4
            Error::ExpectedMap => f.write_str("Expected opening `{`"),
149
4
            Error::ExpectedMapColon => f.write_str("Expected colon"),
150
4
            Error::ExpectedMapEnd => f.write_str("Expected closing `}`"),
151
            Error::ExpectedDifferentStructName {
152
4
                expected,
153
4
                ref found,
154
4
            } => write!(
155
4
                f,
156
                "Expected struct {} but found {}",
157
4
                Identifier(expected),
158
4
                Identifier(found)
159
            ),
160
4
            Error::ExpectedStructLike => f.write_str("Expected opening `(`"),
161
596
            Error::ExpectedNamedStructLike(name) => {
162
596
                if name.is_empty() {
163
592
                    f.write_str("Expected only opening `(`, no name, for un-nameable struct")
164
                } else {
165
4
                    write!(f, "Expected opening `(` for struct {}", Identifier(name))
166
                }
167
            }
168
4
            Error::ExpectedUnit => f.write_str("Expected unit"),
169
4
            Error::ExpectedString => f.write_str("Expected string"),
170
298
            Error::ExpectedByteString => f.write_str("Expected byte string"),
171
4
            Error::ExpectedStringEnd => f.write_str("Expected end of string"),
172
4
            Error::ExpectedIdentifier => f.write_str("Expected identifier"),
173
4
            Error::InvalidEscape(s) => f.write_str(s),
174
4
            Error::IntegerOutOfBounds => f.write_str("Integer is out of bounds"),
175
4
            Error::InvalidIntegerDigit { digit, base } => {
176
4
                write!(f, "Invalid digit {:?} for base {} integers", digit, base)
177
            }
178
4
            Error::NoSuchExtension(ref name) => {
179
4
                write!(f, "No RON extension named {}", Identifier(name))
180
            }
181
4
            Error::Utf8Error(ref e) => fmt::Display::fmt(e, f),
182
4
            Error::UnclosedBlockComment => f.write_str("Unclosed block comment"),
183
4
            Error::UnclosedLineComment => f.write_str(
184
4
                "`ron::value::RawValue` cannot end in unclosed line comment, \
185
4
                try using a block comment or adding a newline",
186
            ),
187
            Error::UnderscoreAtBeginning => {
188
4
                f.write_str("Unexpected leading underscore in a number")
189
            }
190
592
            Error::UnexpectedChar(c) => write!(f, "Unexpected char {:?}", c),
191
4
            Error::TrailingCharacters => f.write_str("Non-whitespace trailing characters"),
192
            Error::InvalidValueForType {
193
8
                ref expected,
194
8
                ref found,
195
            } => {
196
8
                write!(f, "Expected {} but found {} instead", expected, found)
197
            }
198
            Error::ExpectedDifferentLength {
199
12
                ref expected,
200
12
                found,
201
            } => {
202
12
                write!(f, "Expected {} but found ", expected)?;
203

            
204
12
                match found {
205
4
                    0 => f.write_str("zero elements")?,
206
4
                    1 => f.write_str("one element")?,
207
4
                    n => write!(f, "{} elements", n)?,
208
                }
209

            
210
12
                f.write_str(" instead")
211
            }
212
            Error::NoSuchEnumVariant {
213
8
                expected,
214
8
                ref found,
215
8
                ref outer,
216
            } => {
217
8
                f.write_str("Unexpected ")?;
218

            
219
8
                if outer.is_none() {
220
4
                    f.write_str("enum ")?;
221
4
                }
222

            
223
8
                write!(f, "variant named {}", Identifier(found))?;
224

            
225
8
                if let Some(outer) = outer {
226
4
                    write!(f, " in enum {}", Identifier(outer))?;
227
4
                }
228

            
229
8
                write!(
230
8
                    f,
231
                    ", {}",
232
8
                    OneOf {
233
8
                        alts: expected,
234
8
                        none: "variants"
235
8
                    }
236
                )
237
            }
238
            Error::NoSuchStructField {
239
12
                expected,
240
12
                ref found,
241
12
                ref outer,
242
            } => {
243
12
                write!(f, "Unexpected field named {}", Identifier(found))?;
244

            
245
12
                if let Some(outer) = outer {
246
8
                    write!(f, " in {}", Identifier(outer))?;
247
4
                }
248

            
249
12
                write!(
250
12
                    f,
251
                    ", {}",
252
12
                    OneOf {
253
12
                        alts: expected,
254
12
                        none: "fields"
255
12
                    }
256
                )
257
            }
258
8
            Error::MissingStructField { field, ref outer } => {
259
8
                write!(f, "Unexpected missing field named {}", Identifier(field))?;
260

            
261
8
                match outer {
262
4
                    Some(outer) => write!(f, " in {}", Identifier(outer)),
263
4
                    None => Ok(()),
264
                }
265
            }
266
8
            Error::DuplicateStructField { field, ref outer } => {
267
8
                write!(f, "Unexpected duplicate field named {}", Identifier(field))?;
268

            
269
8
                match outer {
270
4
                    Some(outer) => write!(f, " in {}", Identifier(outer)),
271
4
                    None => Ok(()),
272
                }
273
            }
274
4
            Error::InvalidIdentifier(ref invalid) => write!(f, "Invalid identifier {:?}", invalid),
275
4
            Error::SuggestRawIdentifier(ref identifier) => write!(
276
4
                f,
277
                "Found invalid std identifier {:?}, try the raw identifier `r#{}` instead",
278
                identifier, identifier
279
            ),
280
4
            Error::ExpectedRawValue => f.write_str("Expected a `ron::value::RawValue`"),
281
4
            Error::ExceededRecursionLimit => f.write_str(
282
4
                "Exceeded recursion limit, try increasing `ron::Options::recursion_limit` \
283
4
                and using `serde_stacker` to protect against a stack overflow",
284
            ),
285
4
            Error::ExpectedStructName(ref name) => write!(
286
4
                f,
287
                "Expected the explicit struct name {}, but none was found",
288
4
                Identifier(name)
289
            ),
290
            Error::ExpectedRangeSyntax => f.write_str("Expected `..` or `..=` for range syntax"),
291
        }
292
2298
    }
293
}
294

            
295
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
296
pub struct Position {
297
    pub line: usize,
298
    pub col: usize,
299
}
300

            
301
impl Position {
302
223282
    pub(crate) fn from_src_end(src: &str) -> Position {
303
4019751
        let line = 1 + src.chars().filter(|&c| c == '\n').count();
304
2001729
        let col = 1 + src.chars().rev().take_while(|&c| c != '\n').count();
305

            
306
223282
        Self { line, col }
307
223282
    }
308
}
309

            
310
impl fmt::Display for Position {
311
2058
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
312
2058
        write!(f, "{}:{}", self.line, self.col)
313
2058
    }
314
}
315

            
316
#[derive(Clone, Debug, PartialEq, Eq)]
317
/// Spans select a range of text between two positions.
318
/// Spans are used in [`SpannedError`] to indicate the start and end positions
319
/// of the parser cursor before and after it encountered an error in parsing.
320
pub struct Span {
321
    pub start: Position,
322
    pub end: Position,
323
}
324

            
325
impl fmt::Display for Span {
326
1470
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
327
1470
        if self.start == self.end {
328
882
            write!(f, "{}", self.start)
329
        } else {
330
588
            write!(f, "{}-{}", self.start, self.end)
331
        }
332
1470
    }
333
}
334

            
335
impl ser::Error for Error {
336
    #[cold]
337
14
    fn custom<T: fmt::Display>(msg: T) -> Self {
338
14
        Error::Message(msg.to_string())
339
14
    }
340
}
341

            
342
impl de::Error for Error {
343
    #[cold]
344
361
    fn custom<T: fmt::Display>(msg: T) -> Self {
345
361
        Error::Message(msg.to_string())
346
361
    }
347

            
348
    #[cold]
349
23607
    fn invalid_type(unexp: de::Unexpected, exp: &dyn de::Expected) -> Self {
350
        // Invalid type and invalid value are merged given their similarity in ron
351
23607
        Self::invalid_value(unexp, exp)
352
23607
    }
353

            
354
    #[cold]
355
25009
    fn invalid_value(unexp: de::Unexpected, exp: &dyn de::Expected) -> Self {
356
        struct UnexpectedSerdeTypeValue<'a>(de::Unexpected<'a>);
357

            
358
        impl<'a> fmt::Display for UnexpectedSerdeTypeValue<'a> {
359
25009
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360
25009
                match self.0 {
361
12
                    de::Unexpected::Bool(b) => write!(f, "the boolean `{}`", b),
362
5808
                    de::Unexpected::Unsigned(i) => write!(f, "the unsigned integer `{}`", i),
363
                    de::Unexpected::Signed(i) => write!(f, "the signed integer `{}`", i),
364
                    de::Unexpected::Float(n) => write!(f, "the floating point number `{}`", n),
365
                    de::Unexpected::Char(c) => write!(f, "the UTF-8 character `{}`", c),
366
3528
                    de::Unexpected::Str(s) => write!(f, "the string {:?}", s),
367
294
                    de::Unexpected::Bytes(b) => write!(f, "the byte string b\"{}\"", {
368
294
                        b.iter()
369
1176
                            .flat_map(|c| core::ascii::escape_default(*c))
370
294
                            .map(char::from)
371
294
                            .collect::<String>()
372
                    }),
373
6984
                    de::Unexpected::Unit => write!(f, "a unit value"),
374
                    de::Unexpected::Option => write!(f, "an optional value"),
375
                    de::Unexpected::NewtypeStruct => write!(f, "a newtype struct"),
376
2058
                    de::Unexpected::Seq => write!(f, "a sequence"),
377
5586
                    de::Unexpected::Map => write!(f, "a map"),
378
4
                    de::Unexpected::Enum => write!(f, "an enum"),
379
                    de::Unexpected::UnitVariant => write!(f, "a unit variant"),
380
                    de::Unexpected::NewtypeVariant => write!(f, "a newtype variant"),
381
                    de::Unexpected::TupleVariant => write!(f, "a tuple variant"),
382
                    de::Unexpected::StructVariant => write!(f, "a struct variant"),
383
735
                    de::Unexpected::Other(other) => f.write_str(other),
384
                }
385
25009
            }
386
        }
387

            
388
25009
        Error::InvalidValueForType {
389
25009
            expected: exp.to_string(),
390
25009
            found: UnexpectedSerdeTypeValue(unexp).to_string(),
391
25009
        }
392
25009
    }
393

            
394
    #[cold]
395
822
    fn invalid_length(len: usize, exp: &dyn de::Expected) -> Self {
396
822
        Error::ExpectedDifferentLength {
397
822
            expected: exp.to_string(),
398
822
            found: len,
399
822
        }
400
822
    }
401

            
402
    #[cold]
403
1330
    fn unknown_variant(variant: &str, expected: &'static [&'static str]) -> Self {
404
1330
        Error::NoSuchEnumVariant {
405
1330
            expected,
406
1330
            found: variant.to_string(),
407
1330
            outer: None,
408
1330
        }
409
1330
    }
410

            
411
    #[cold]
412
3538
    fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self {
413
3538
        Error::NoSuchStructField {
414
3538
            expected,
415
3538
            found: field.to_string(),
416
3538
            outer: None,
417
3538
        }
418
3538
    }
419

            
420
    #[cold]
421
5596
    fn missing_field(field: &'static str) -> Self {
422
5596
        Error::MissingStructField { field, outer: None }
423
5596
    }
424

            
425
    #[cold]
426
3172
    fn duplicate_field(field: &'static str) -> Self {
427
3172
        Error::DuplicateStructField { field, outer: None }
428
3172
    }
429
}
430

            
431
impl StdError for SpannedError {}
432

            
433
impl StdError for Error {}
434

            
435
impl From<Utf8Error> for Error {
436
588
    fn from(e: Utf8Error) -> Self {
437
588
        Error::Utf8Error(e)
438
588
    }
439
}
440

            
441
impl From<fmt::Error> for Error {
442
4
    fn from(_: fmt::Error) -> Self {
443
4
        Error::Fmt
444
4
    }
445
}
446

            
447
#[cfg(feature = "std")]
448
impl From<io::Error> for Error {
449
886
    fn from(e: io::Error) -> Self {
450
886
        Error::Io(e.to_string())
451
886
    }
452
}
453

            
454
impl From<SpannedError> for Error {
455
8
    fn from(e: SpannedError) -> Self {
456
8
        e.code
457
8
    }
458
}
459

            
460
struct OneOf {
461
    alts: &'static [&'static str],
462
    none: &'static str,
463
}
464

            
465
impl fmt::Display for OneOf {
466
20
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
467
20
        match self.alts {
468
20
            [] => write!(f, "there are no {}", self.none),
469
4
            [a1] => write!(f, "expected {} instead", Identifier(a1)),
470
4
            [a1, a2] => write!(
471
4
                f,
472
                "expected either {} or {} instead",
473
4
                Identifier(a1),
474
4
                Identifier(a2)
475
            ),
476
4
            [a1, ref alts @ .., an] => {
477
4
                write!(f, "expected one of {}", Identifier(a1))?;
478

            
479
4
                for alt in alts {
480
4
                    write!(f, ", {}", Identifier(alt))?;
481
                }
482

            
483
4
                write!(f, ", or {} instead", Identifier(an))
484
            }
485
        }
486
20
    }
487
}
488

            
489
struct Identifier<'a>(&'a str);
490

            
491
impl<'a> fmt::Display for Identifier<'a> {
492
100
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
493
100
        if self.0.is_empty() || !self.0.chars().all(is_ident_raw_char) {
494
4
            return write!(f, "{:?}_[invalid identifier]", self.0);
495
96
        }
496

            
497
96
        let mut chars = self.0.chars();
498

            
499
96
        if !chars.next().map_or(false, is_ident_first_char) || !chars.all(is_xid_continue) {
500
24
            write!(f, "`r#{}`", self.0)
501
        } else {
502
72
            write!(f, "`{}`", self.0)
503
        }
504
100
    }
505
}
506

            
507
#[cfg(test)]
508
mod tests {
509
    use alloc::{format, string::String};
510

            
511
    use serde::{de::Error as DeError, de::Unexpected, ser::Error as SerError};
512

            
513
    use super::{Error, Position, Span, SpannedError};
514

            
515
    #[test]
516
4
    fn error_messages() {
517
4
        check_error_message(&Error::from(core::fmt::Error), "Formatting RON failed");
518
        #[cfg(feature = "std")]
519
4
        check_error_message(
520
4
            &Error::from(std::io::Error::new(
521
4
                std::io::ErrorKind::InvalidData,
522
4
                "my-error",
523
4
            )),
524
4
            "my-error",
525
        );
526
4
        check_error_message(&<Error as SerError>::custom("my-ser-error"), "my-ser-error");
527
4
        check_error_message(&<Error as DeError>::custom("my-de-error"), "my-de-error");
528
4
        check_error_message(&Error::Eof, "Unexpected end of RON");
529
4
        check_error_message(&Error::ExpectedArray, "Expected opening `[`");
530
4
        check_error_message(&Error::ExpectedArrayEnd, "Expected closing `]`");
531
4
        check_error_message(
532
4
            &Error::ExpectedAttribute,
533
4
            "Expected an `#![enable(...)]` attribute",
534
        );
535
4
        check_error_message(
536
4
            &Error::ExpectedAttributeEnd,
537
4
            "Expected closing `)]` after the enable attribute",
538
        );
539
4
        check_error_message(&Error::ExpectedBoolean, "Expected boolean");
540
4
        check_error_message(&Error::ExpectedComma, "Expected comma");
541
4
        check_error_message(&Error::ExpectedChar, "Expected char");
542
4
        check_error_message(&Error::ExpectedByteLiteral, "Expected byte literal");
543
4
        check_error_message(&Error::ExpectedFloat, "Expected float");
544
4
        check_error_message(&Error::FloatUnderscore, "Unexpected underscore in float");
545
4
        check_error_message(&Error::ExpectedInteger, "Expected integer");
546
4
        check_error_message(&Error::ExpectedOption, "Expected option");
547
4
        check_error_message(&Error::ExpectedOptionEnd, "Expected closing `)`");
548
4
        check_error_message(&Error::ExpectedStructLikeEnd, "Expected closing `)`");
549
4
        check_error_message(&Error::ExpectedMap, "Expected opening `{`");
550
4
        check_error_message(&Error::ExpectedMapColon, "Expected colon");
551
4
        check_error_message(&Error::ExpectedMapEnd, "Expected closing `}`");
552
4
        check_error_message(
553
4
            &Error::ExpectedDifferentStructName {
554
4
                expected: "raw+identifier",
555
4
                found: String::from("identifier"),
556
4
            },
557
4
            "Expected struct `r#raw+identifier` but found `identifier`",
558
        );
559
4
        check_error_message(&Error::ExpectedStructLike, "Expected opening `(`");
560
4
        check_error_message(
561
4
            &Error::ExpectedNamedStructLike(""),
562
4
            "Expected only opening `(`, no name, for un-nameable struct",
563
        );
564
4
        check_error_message(
565
4
            &Error::ExpectedNamedStructLike("_ident"),
566
4
            "Expected opening `(` for struct `_ident`",
567
        );
568
4
        check_error_message(&Error::ExpectedUnit, "Expected unit");
569
4
        check_error_message(&Error::ExpectedString, "Expected string");
570
4
        check_error_message(&Error::ExpectedByteString, "Expected byte string");
571
4
        check_error_message(&Error::ExpectedStringEnd, "Expected end of string");
572
4
        check_error_message(&Error::ExpectedIdentifier, "Expected identifier");
573
4
        check_error_message(&Error::InvalidEscape("Invalid escape"), "Invalid escape");
574
4
        check_error_message(&Error::IntegerOutOfBounds, "Integer is out of bounds");
575
4
        check_error_message(
576
4
            &Error::InvalidIntegerDigit {
577
4
                digit: 'q',
578
4
                base: 16,
579
4
            },
580
4
            "Invalid digit 'q' for base 16 integers",
581
        );
582
4
        check_error_message(
583
4
            &Error::NoSuchExtension(String::from("unknown")),
584
4
            "No RON extension named `unknown`",
585
        );
586
4
        check_error_message(&Error::UnclosedBlockComment, "Unclosed block comment");
587
4
        check_error_message(
588
4
            &Error::UnclosedLineComment,
589
4
            "`ron::value::RawValue` cannot end in unclosed line comment, \
590
4
        try using a block comment or adding a newline",
591
        );
592
4
        check_error_message(
593
4
            &Error::UnderscoreAtBeginning,
594
4
            "Unexpected leading underscore in a number",
595
        );
596
4
        check_error_message(&Error::UnexpectedChar('🦀'), "Unexpected char \'🦀\'");
597
        #[allow(invalid_from_utf8)]
598
4
        check_error_message(
599
4
            &Error::Utf8Error(core::str::from_utf8(b"error: \xff\xff\xff\xff").unwrap_err()),
600
4
            "invalid utf-8 sequence of 1 bytes from index 7",
601
        );
602
4
        check_error_message(
603
4
            &Error::TrailingCharacters,
604
4
            "Non-whitespace trailing characters",
605
        );
606
4
        check_error_message(
607
4
            &Error::invalid_value(Unexpected::Enum, &"struct `Hi`"),
608
4
            "Expected struct `Hi` but found an enum instead",
609
        );
610
4
        check_error_message(
611
4
            &Error::invalid_length(0, &"two bees"),
612
4
            "Expected two bees but found zero elements instead",
613
        );
614
4
        check_error_message(
615
4
            &Error::invalid_length(1, &"two bees"),
616
4
            "Expected two bees but found one element instead",
617
        );
618
4
        check_error_message(
619
4
            &Error::invalid_length(3, &"two bees"),
620
4
            "Expected two bees but found 3 elements instead",
621
        );
622
4
        check_error_message(
623
4
            &Error::unknown_variant("unknown", &[]),
624
4
            "Unexpected enum variant named `unknown`, there are no variants",
625
        );
626
4
        check_error_message(
627
4
            &Error::NoSuchEnumVariant {
628
4
                expected: &["A", "B+C"],
629
4
                found: String::from("D"),
630
4
                outer: Some(String::from("E")),
631
4
            },
632
4
            "Unexpected variant named `D` in enum `E`, \
633
4
            expected either `A` or `r#B+C` instead",
634
        );
635
4
        check_error_message(
636
4
            &Error::unknown_field("unknown", &[]),
637
4
            "Unexpected field named `unknown`, there are no fields",
638
        );
639
4
        check_error_message(
640
4
            &Error::NoSuchStructField {
641
4
                expected: &["a"],
642
4
                found: String::from("b"),
643
4
                outer: Some(String::from("S")),
644
4
            },
645
4
            "Unexpected field named `b` in `S`, expected `a` instead",
646
        );
647
4
        check_error_message(
648
4
            &Error::NoSuchStructField {
649
4
                expected: &["a", "b+c", "d"],
650
4
                found: String::from("e"),
651
4
                outer: Some(String::from("S")),
652
4
            },
653
4
            "Unexpected field named `e` in `S`, \
654
4
            expected one of `a`, `r#b+c`, or `d` instead",
655
        );
656
4
        check_error_message(
657
4
            &Error::missing_field("a"),
658
4
            "Unexpected missing field named `a`",
659
        );
660
4
        check_error_message(
661
4
            &Error::MissingStructField {
662
4
                field: "",
663
4
                outer: Some(String::from("S+T")),
664
4
            },
665
4
            "Unexpected missing field named \"\"_[invalid identifier] in `r#S+T`",
666
        );
667
4
        check_error_message(
668
4
            &Error::duplicate_field("a"),
669
4
            "Unexpected duplicate field named `a`",
670
        );
671
4
        check_error_message(
672
4
            &Error::DuplicateStructField {
673
4
                field: "b+c",
674
4
                outer: Some(String::from("S+T")),
675
4
            },
676
4
            "Unexpected duplicate field named `r#b+c` in `r#S+T`",
677
        );
678
4
        check_error_message(
679
4
            &Error::InvalidIdentifier(String::from("why+🦀+not")),
680
4
            "Invalid identifier \"why+🦀+not\"",
681
        );
682
4
        check_error_message(
683
4
            &Error::SuggestRawIdentifier(String::from("raw+ident")),
684
4
            "Found invalid std identifier \"raw+ident\", \
685
4
            try the raw identifier `r#raw+ident` instead",
686
        );
687
4
        check_error_message(
688
4
            &Error::ExpectedRawValue,
689
4
            "Expected a `ron::value::RawValue`",
690
        );
691
4
        check_error_message(
692
4
            &Error::ExceededRecursionLimit,
693
4
            "Exceeded recursion limit, try increasing `ron::Options::recursion_limit` \
694
4
            and using `serde_stacker` to protect against a stack overflow",
695
        );
696
4
        check_error_message(
697
4
            &Error::ExpectedStructName(String::from("Struct")),
698
4
            "Expected the explicit struct name `Struct`, but none was found",
699
        );
700
4
    }
701

            
702
236
    fn check_error_message<T: core::fmt::Display>(err: &T, msg: &str) {
703
236
        assert_eq!(format!("{}", err), msg);
704
236
    }
705

            
706
    #[test]
707
4
    fn spanned_error_into_code() {
708
4
        assert_eq!(
709
4
            Error::from(SpannedError {
710
4
                code: Error::Eof,
711
4
                span: Span {
712
4
                    start: Position { line: 1, col: 1 },
713
4
                    end: Position { line: 1, col: 5 },
714
4
                }
715
4
            }),
716
            Error::Eof
717
        );
718
4
        assert_eq!(
719
4
            Error::from(SpannedError {
720
4
                code: Error::ExpectedRawValue,
721
4
                span: Span {
722
4
                    start: Position { line: 1, col: 1 },
723
4
                    end: Position { line: 1, col: 5 },
724
4
                }
725
4
            }),
726
            Error::ExpectedRawValue
727
        );
728
4
    }
729
}