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
// -------------------------------------------------------------------------
// Error Handling and Field Type
// -------------------------------------------------------------------------

use crate::{CowStr, Value};

/// A content-less variant of the [`Value`] enum, used for reporting errors, see [`MerdeError::MismatchedType`].
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ValueType {
    /// The JSON value is `null`.
    Null,

    /// The JSON value is `true` or `false`.
    Bool,

    /// The JSON value fits in an `i64`.
    Int,

    /// The JSON value no longer fits in an `i64`.
    BigInt,

    /// The JSON value has decimal places.
    Float,

    /// The JSON value is a string.
    String,

    /// The JSON value is an array.
    Array,

    /// The JSON value is an object. Keys must be strings.
    Map,
}

/// A grab-bag of errors that can occur when deserializing.
/// This isn't super clean, not my proudest moment.
#[derive(Debug)]
#[non_exhaustive]
pub enum MerdeError {
    /// We expected a certain type but got a different one.
    ///
    /// Note that the default implementations of [crate::ValueDeserialize] have tolerances:
    /// if we expect a `u32` but get a floating-point number, we'll round it.
    MismatchedType {
        /// The expected type.
        expected: ValueType,

        /// The type we got.
        found: ValueType,
    },

    /// We expected an object to have a certain property, but it was missing.
    MissingProperty(CowStr<'static>),

    /// We tried to access an array index that was out of bounds.
    IndexOutOfBounds {
        /// The index we tried to access.
        index: usize,
        /// The length of the array.
        len: usize,
    },

    /// We encountered a property that we didn't expect.
    UnknownProperty(String),

    /// For example, we had a `u8` field but the JSON value was bigger than `u8::MAX`.
    OutOfRange,

    /// A field was missing (but we don't know its name)
    MissingValue,

    /// While calling out to [`FromStr::from_str`](std::str::FromStr::from_str) to build a [`HashMap`](std::collections::HashMap), we got an error.
    InvalidKey,

    /// While parsing a datetime, we got an error
    InvalidDateTimeValue,

    /// An I/O error occurred.
    Io(std::io::Error),
}

impl From<std::io::Error> for MerdeError {
    fn from(e: std::io::Error) -> Self {
        MerdeError::Io(e)
    }
}

impl std::fmt::Display for MerdeError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            MerdeError::MismatchedType { expected, found } => {
                write!(f, "Expected {:?}, found {:?}", expected, found)
            }
            MerdeError::MissingProperty(prop) => {
                write!(f, "Missing property: {}", prop)
            }
            MerdeError::IndexOutOfBounds { index, len: length } => {
                write!(
                    f,
                    "Index out of bounds: index {} is not valid for length {}",
                    index, length
                )
            }
            MerdeError::UnknownProperty(prop) => {
                write!(f, "Unknown property: {}", prop)
            }
            MerdeError::OutOfRange => {
                write!(f, "Value is out of range")
            }
            MerdeError::MissingValue => {
                write!(f, "Missing value")
            }
            MerdeError::InvalidKey => {
                write!(f, "Invalid key")
            }
            MerdeError::InvalidDateTimeValue => {
                write!(f, "Invalid date/time value")
            }
            MerdeError::Io(e) => {
                write!(f, "I/O error: {}", e)
            }
        }
    }
}

impl std::error::Error for MerdeError {}

impl Value<'_> {
    /// Returns the [ValueType] for a given [Value].
    pub fn value_type(&self) -> ValueType {
        match self {
            Value::Null => ValueType::Null,
            Value::Bool(_) => ValueType::Bool,
            Value::Int(_) => ValueType::Int,
            Value::Float(_) => ValueType::Float,
            Value::Str(_) => ValueType::String,
            Value::Array(_) => ValueType::Array,
            Value::Map(_) => ValueType::Map,
        }
    }
}