Skip to main content

immutable_json/
api.rs

1use crate::array::Array;
2use crate::error::Error;
3use crate::object::Object;
4use crate::serde::{from_value, to_value};
5use std::fmt::Display;
6use std::hash::{Hash, Hasher};
7use std::str::FromStr;
8
9/// A JSON number.
10#[derive(Clone, Copy, Debug)]
11pub enum Number {
12    Decimal(f64),
13    Integer(i128),
14}
15
16/// A JSON value.
17#[derive(Clone, Debug, Eq)]
18pub enum Value {
19    Array(Array),
20    Bool(bool),
21    Null,
22    Number(Number),
23    Object(Object),
24    String(String),
25}
26
27impl Eq for Number {}
28
29impl Hash for Number {
30    fn hash<H: Hasher>(&self, state: &mut H) {
31        match self {
32            Number::Decimal(v) => v.to_string().hash(state),
33            Number::Integer(v) => state.write_i128(*v),
34        }
35    }
36}
37
38impl PartialEq for Number {
39    fn eq(&self, other: &Self) -> bool {
40        match (self, other) {
41            (Number::Decimal(s), Number::Decimal(o)) => s == o,
42            (Number::Integer(s), Number::Integer(o)) => s == o,
43            _ => false,
44        }
45    }
46}
47
48impl Number {
49    pub fn as_decimal(&self) -> Option<f64> {
50        match self {
51            Number::Decimal(v) => Some(*v),
52            Number::Integer(_) => None,
53        }
54    }
55
56    pub fn as_integer(&self) -> Option<i128> {
57        match self {
58            Number::Decimal(_) => None,
59            Number::Integer(v) => Some(*v),
60        }
61    }
62
63    pub fn is_decimal(&self) -> bool {
64        matches!(self, Number::Decimal(_))
65    }
66
67    pub fn is_integer(&self) -> bool {
68        matches!(self, Number::Integer(_))
69    }
70}
71
72impl PartialEq for Value {
73    fn eq(&self, other: &Self) -> bool {
74        match self {
75            Value::Array(v) => Some(v) == other.as_array().as_ref(),
76            Value::Bool(v) => Some(v) == other.as_bool().as_ref(),
77            Value::Null => other.is_null(),
78            Value::Number(v) => Some(v) == other.as_number().as_ref(),
79            Value::Object(v) => Some(v) == other.as_object().as_ref(),
80            Value::String(v) => Some(v) == other.as_string().as_ref(),
81        }
82    }
83}
84
85impl Display for Value {
86    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87        write!(
88            f,
89            "{}",
90            to_value(self).map_or("".to_string(), |v| v.to_string())
91        )
92    }
93}
94
95impl FromStr for Value {
96    type Err = Error;
97
98    fn from_str(s: &str) -> Result<Self, Self::Err> {
99        let v: serde_json::Value = serde_json::from_str(s)?;
100
101        match from_value(&v) {
102            Some(c) => Ok(c),
103            None => Err(Error::ConvertFrom),
104        }
105    }
106}
107
108impl Hash for Value {
109    fn hash<H: Hasher>(&self, state: &mut H) {
110        match self {
111            Value::Array(v) => v.hash(state),
112            Value::Bool(v) => v.hash(state),
113            Value::Null => state.write_u8(0),
114            Value::Number(v) => v.hash(state),
115            Value::Object(v) => v.hash(state),
116            Value::String(v) => v.hash(state),
117        }
118    }
119}
120
121impl TryFrom<serde_json::Value> for Value {
122    type Error = Error;
123
124    fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
125        match from_value(&value) {
126            Some(v) => Ok(v),
127            None => Err(Error::ConvertFrom),
128        }
129    }
130}
131
132impl TryFrom<Value> for serde_json::Value {
133    type Error = Error;
134
135    fn try_from(value: Value) -> Result<Self, Self::Error> {
136        match to_value(&value) {
137            Some(v) => Ok(v),
138            None => Err(Error::ConvertTo),
139        }
140    }
141}
142
143impl Value {
144    pub fn as_array(&self) -> Option<Array> {
145        match self {
146            Self::Array(a) => Some(a.clone()),
147            _ => None,
148        }
149    }
150
151    pub fn as_bool(&self) -> Option<bool> {
152        match self {
153            Self::Bool(b) => Some(*b),
154            _ => None,
155        }
156    }
157
158    pub fn as_decimal(&self) -> Option<f64> {
159        match self {
160            Self::Number(n) => Number::as_decimal(n),
161            _ => None,
162        }
163    }
164
165    pub fn as_integer(&self) -> Option<i128> {
166        match self {
167            Self::Number(n) => Number::as_integer(n),
168            _ => None,
169        }
170    }
171
172    pub fn as_number(&self) -> Option<Number> {
173        match self {
174            Self::Number(n) => Some(*n),
175            _ => None,
176        }
177    }
178
179    pub fn as_object(&self) -> Option<Object> {
180        match self {
181            Self::Object(o) => Some(o.clone()),
182            _ => None,
183        }
184    }
185
186    pub fn as_string(&self) -> Option<String> {
187        match self {
188            Self::String(s) => Some(s.clone()),
189            _ => None,
190        }
191    }
192
193    pub fn is_array(&self) -> bool {
194        matches!(self, Self::Array(_))
195    }
196
197    pub fn is_bool(&self) -> bool {
198        matches!(self, Self::Bool(_))
199    }
200
201    pub fn is_decimal(&self) -> bool {
202        match self {
203            Self::Number(n) => Number::is_decimal(n),
204            _ => false,
205        }
206    }
207
208    pub fn is_integer(&self) -> bool {
209        match self {
210            Self::Number(n) => Number::is_integer(n),
211            _ => false,
212        }
213    }
214
215    pub fn is_null(&self) -> bool {
216        matches!(self, Self::Null)
217    }
218
219    pub fn is_number(&self) -> bool {
220        matches!(self, Self::Number(_))
221    }
222
223    pub fn is_object(&self) -> bool {
224        matches!(self, Self::Object(_))
225    }
226
227    pub fn is_scalar(&self) -> bool {
228        self.is_null() || self.is_bool() || self.is_number() || self.is_string()
229    }
230
231    pub fn is_string(&self) -> bool {
232        matches!(self, Self::String(_))
233    }
234
235    pub fn is_structure(&self) -> bool {
236        self.is_array() || self.is_object()
237    }
238}