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
}
116

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

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

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

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

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

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

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

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

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

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

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

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

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

            
299
impl Position {
300
206730
    pub(crate) fn from_src_end(src: &str) -> Position {
301
3787681
        let line = 1 + src.chars().filter(|&c| c == '\n').count();
302
1879427
        let col = 1 + src.chars().rev().take_while(|&c| c != '\n').count();
303

            
304
206730
        Self { line, col }
305
206730
    }
306
}
307

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

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

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

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

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

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

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

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

            
386
19479
        Error::InvalidValueForType {
387
19479
            expected: exp.to_string(),
388
19479
            found: UnexpectedSerdeTypeValue(unexp).to_string(),
389
19479
        }
390
19479
    }
391

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

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

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

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

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

            
429
impl StdError for SpannedError {}
430

            
431
impl StdError for Error {}
432

            
433
impl From<Utf8Error> for Error {
434
556
    fn from(e: Utf8Error) -> Self {
435
556
        Error::Utf8Error(e)
436
556
    }
437
}
438

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

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

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

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

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

            
477
8
                for alt in alts {
478
4
                    write!(f, ", {}", Identifier(alt))?;
479
                }
480

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

            
487
struct Identifier<'a>(&'a str);
488

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

            
495
96
        let mut chars = self.0.chars();
496

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

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

            
509
    use serde::{de::Error as DeError, de::Unexpected, ser::Error as SerError};
510

            
511
    use super::{Error, Position, Span, SpannedError};
512

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

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

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