1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//! All errors that can happen while parsing can be found here.

use arrayvec::{ArrayVec, CapacityError};
use chrono;
use std::{io, num, str};

use lexer::STRING_LENGTH;

quick_error! {
    /// Errors that can happen while parsing.
    #[derive(Debug)]
    pub enum ParseError {
        /// Encountered an error while lexing.
        Lexer(err: LexError) {
            from()
            description(err.description())
            display("Could not parse due to an error in the lexer: {}", err)
            cause(err)
        }
        /// Found an unexpected token.
        UnexpectedToken {
            description("Unexpected token")
            display("Encountered unexpected token")
        }
        /// Found an unexptected sentence type.
        UnexpectedSentenceType {
            description("Unexpected sentence type")
            display("Encountered unexpected sentence type")
        }
        /// Failed to parse a `FloatLiteral` to a `NaiveTime`.
        Time(err: chrono::format::ParseError) {
            from()
            description("Time parsing error")
            display("Failed to parse FloatLiteral as time: {}", err)
            cause(err)
        }
        /// Failed to parse a `StringLiteral` to a `CardDir`.
        UnexpectedDir(dir: ArrayVec<[u8; STRING_LENGTH]>) {
            description("Unexpected direction")
            display("Could not parse {:?} as direction", dir)
        }
        /// Failed to convert to `str`.
        /// This should not happen if the lexer only returns ascii bytes.
        Utf8(err: str::Utf8Error) {
            from()
            description(err.description())
            display("{}", err)
            cause(err)
        }
        /// Found an invalid value.
        /// E.g. a station id not between 0 and 1023, a float with the wrong
        /// format for a coordinate, ...
        InvalidValue(msg: &'static str) {
            description("Invalid value")
            display("Invalid value, {}", msg)
        }
        /// Failed to parse an integer.
        Int(err: num::ParseIntError) {
            from()
            description(err.description())
            display("{}", err)
            cause(err)
        }
        /// Failed to parse a float.
        Float(err: num::ParseFloatError) {
            from()
            description(err.description())
            display("{}", err)
            cause(err)
        }
        /// Found an invalid coordinate, e.g. latitude outside of the range -90° to +90°.
        InvalidCoord(val: f64, max: f64) {
            description("Invalid coordinate")
            display("Invalid coordinate: {} should be between {:.0} and {:.0}", val, max*-1.0, max)
        }
        /// Found an unexpected unit.
        InvalidUnit {
            description("Unexpected unit")
            display("Found an unexpected unit")
        }
    }
}

quick_error!{
    /// Errors that can happen while lexing the raw input.
    #[derive(Debug)]
    pub enum LexError {
        /// An invalid character.
        InvalidCharacter(c: u8) {
            description("Invalid character")
            display("Encountered invalid character \"{}\"", *c as char)
        }
        /// The checksum is invalid.
        /// The two values are the expected and the actual checksum.
        /// `InvalidChecksum(expected: u8, actual: u8)`
        InvalidChecksum(expected: u8, actual: u8) {
            description("Invalid checksum")
            display("Expected checksum \"{:X}\" , found checksum \"{}\"", expected, actual)
        }
        /// I/O Error
        Io(err: io::Error) {
            from()
            description(err.description())
            display("Encountered I/O error while lexing: {}", err)
            cause(err)
        }
        /// The EOF was found in an unexpected location.
        /// This can happen in the header and the checksum, when there aren't
        /// enough bytes after the starting sign.
        UnexpectedEof(token: &'static str) {
            description("Unexpected EOF")
            display("Encountered unexpected EOF in {}", token)
        }
        /// A token could not be completed.
        /// Some reasons for that are a `'-'` without a following digit and
        /// a non hex-digit in the two chars following `'*'`.
        IncompleteToken(token: &'static str) {
            description("Incomplete token")
            display("Could not complete token of type {}", token)
        }
        /// An array overflowed while trying to push values into it.
        ArrayOverflow(err: CapacityError<u8>) {
            from()
            description(err.description())
            display("Array buffer overflow: {}", err)
            cause(err)
        }
        /// Failed to parse an integer.
        Int(err: num::ParseIntError) {
            from()
            description(err.description())
            display("{}", err)
            cause(err)
        }
        /// Failed to parse some bytes to a `str` because they are not even utf8
        /// even though only ascii is expected.
        NotEvenUtf8(err: str::Utf8Error) {
            from()
            description(err.description())
            display("Expected ascii but did not even get valid utf8: {}", err)
            cause(err)
        }
    }
}

impl From<(u8, u8)> for LexError {
    fn from((expected, actual): (u8, u8)) -> Self {
        LexError::InvalidChecksum(expected, actual)
    }
}