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
use std::fmt;
use std::io::ErrorKind;
use std::result::Result as StdResult;

/// Either a parsing error or an IO error.
pub enum IoError {
    /// A phpser parsing error
    Phpser(Error),
    /// An IO error, excluding unexpected EOF error
    Io(std::io::Error),
}

impl From<Error> for IoError {
    fn from(err: Error) -> Self {
        Self::Phpser(err)
    }
}
impl From<std::io::Error> for IoError {
    fn from(err: std::io::Error) -> Self {
        if err.kind() == ErrorKind::UnexpectedEof {
            Self::Phpser(Error::UnexpectedEof)
        } else {
            Self::Io(err)
        }
    }
}

/// A parsing error.
#[derive(Debug, Clone, Copy)]
pub enum Error {
    /// unexpected end of document
    UnexpectedEof,
    /// str is used as string type, but serialized input is not valid UTF-8
    BadEncoding(usize),
    /// encountered invalid token
    BadToken(usize),
    /// encountered malformed or out-of-range number
    BadNumber(usize),
    /// array key must be int or string
    BadArrayKeyType(usize),
    /// object key must be string
    BadObjectKeyType(usize),
}

impl Error {
    /// Returns the offset of this error, if relevant.
    pub fn offset(self) -> Option<usize> {
        match self {
            Self::UnexpectedEof => None,
            Self::BadEncoding(offset) => Some(offset),
            Self::BadToken(offset) => Some(offset),
            Self::BadNumber(offset) => Some(offset),
            Self::BadArrayKeyType(offset) => Some(offset),
            Self::BadObjectKeyType(offset) => Some(offset),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Self::UnexpectedEof => write!(f, "unexpected end of document"),
            Self::BadEncoding(_) => write!(
                f,
                "str is used as string type, but serialized input is not valid UTF-8"
            ),
            Self::BadToken(_) => write!(f, "encountered invalid token"),
            Self::BadNumber(_) => write!(f, "encountered malformed or out-of-range number"),
            Self::BadArrayKeyType(_) => write!(f, "array key must be int or string"),
            Self::BadObjectKeyType(_) => write!(f, "object key must be string"),
        }?;
        if let Some(offset) = self.offset() {
            write!(f, " at offset {}", offset)?;
        }
        Ok(())
    }
}

/// A parsing result.
pub type Result<T = (), E = Error> = StdResult<T, E>;

/// Result with a parsing error or an IO error.
pub type IoResult<T = ()> = Result<T, IoError>;