1use core::fmt;
2use std::{collections::BTreeMap, marker::PhantomData, str::FromStr};
3
4use crate::{array::JsonArray, code_map::Mapped, CodeMap, Kind, KindSet, Object, Value};
5
6pub trait TryFromJson: Sized {
11 type Error;
13
14 fn try_from_json(value: &Value, code_map: &CodeMap) -> Result<Self, Self::Error> {
21 Self::try_from_json_at(value, code_map, 0)
22 }
23
24 fn try_from_json_at(
31 value: &Value,
32 code_map: &CodeMap,
33 offset: usize,
34 ) -> Result<Self, Self::Error>;
35}
36
37impl<T: TryFromJson> TryFromJson for Box<T> {
38 type Error = T::Error;
39
40 fn try_from_json_at(
41 json: &Value,
42 code_map: &CodeMap,
43 offset: usize,
44 ) -> Result<Self, Self::Error> {
45 T::try_from_json_at(json, code_map, offset).map(Box::new)
46 }
47}
48
49impl<T: TryFromJson> TryFromJson for Option<T> {
50 type Error = T::Error;
51
52 fn try_from_json_at(
53 json: &Value,
54 code_map: &CodeMap,
55 offset: usize,
56 ) -> Result<Self, Self::Error> {
57 match json {
58 Value::Null => Ok(None),
59 other => T::try_from_json_at(other, code_map, offset).map(Some),
60 }
61 }
62}
63
64pub trait TryFromJsonObject: Sized {
69 type Error;
70
71 fn try_from_json_object(object: &Object, code_map: &CodeMap) -> Result<Self, Self::Error> {
78 Self::try_from_json_object_at(object, code_map, 0)
79 }
80
81 fn try_from_json_object_at(
88 object: &Object,
89 code_map: &CodeMap,
90 offset: usize,
91 ) -> Result<Self, Self::Error>;
92}
93
94impl<T: TryFromJsonObject> TryFromJsonObject for Box<T> {
95 type Error = T::Error;
96
97 fn try_from_json_object_at(
98 object: &Object,
99 code_map: &CodeMap,
100 offset: usize,
101 ) -> Result<Self, Self::Error> {
102 T::try_from_json_object_at(object, code_map, offset).map(Box::new)
103 }
104}
105
106#[derive(Debug)]
111pub struct Unexpected {
112 pub expected: KindSet,
114
115 pub found: Kind,
117}
118
119impl fmt::Display for Unexpected {
120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121 write!(
122 f,
123 "expected {}, found {}",
124 self.expected.as_disjunction(),
125 self.found
126 )
127 }
128}
129
130impl TryFromJson for () {
131 type Error = Mapped<Unexpected>;
132
133 fn try_from_json_at(
134 json: &Value,
135 _code_map: &CodeMap,
136 offset: usize,
137 ) -> Result<Self, Self::Error> {
138 match json {
139 Value::Null => Ok(()),
140 other => Err(Mapped::new(
141 offset,
142 Unexpected {
143 expected: KindSet::NULL,
144 found: other.kind(),
145 },
146 )),
147 }
148 }
149}
150
151impl TryFromJson for bool {
152 type Error = Mapped<Unexpected>;
153
154 fn try_from_json_at(
155 json: &Value,
156 _code_map: &CodeMap,
157 offset: usize,
158 ) -> Result<Self, Self::Error> {
159 match json {
160 Value::Boolean(value) => Ok(*value),
161 other => Err(Mapped::new(
162 offset,
163 Unexpected {
164 expected: KindSet::BOOLEAN,
165 found: other.kind(),
166 },
167 )),
168 }
169 }
170}
171
172pub struct NumberType<T>(PhantomData<T>);
173
174impl<T> Clone for NumberType<T> {
175 fn clone(&self) -> Self {
176 *self
177 }
178}
179
180impl<T> Copy for NumberType<T> {}
181
182impl<T> Default for NumberType<T> {
183 fn default() -> Self {
184 Self(PhantomData)
185 }
186}
187
188impl<T> fmt::Debug for NumberType<T> {
189 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190 write!(f, "NumberType")
191 }
192}
193
194impl<T> fmt::Display for NumberType<T> {
195 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196 write!(f, "NumberType")
197 }
198}
199
200pub enum TryIntoNumberError<T> {
201 Unexpected(Unexpected),
202 OutOfBounds(T),
203}
204
205impl<T> TryIntoNumberError<T> {
206 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> TryIntoNumberError<U> {
207 match self {
208 Self::Unexpected(e) => TryIntoNumberError::Unexpected(e),
209 Self::OutOfBounds(t) => TryIntoNumberError::OutOfBounds(f(t)),
210 }
211 }
212}
213
214impl std::error::Error for Unexpected {}
215
216macro_rules! number_from_json {
217 ($($ty:ident),*) => {
218 $(
219 impl TryFromJson for $ty {
220 type Error = Mapped<TryIntoNumberError<NumberType<$ty>>>;
221
222 fn try_from_json_at(json: &Value, _code_map: &CodeMap, offset: usize) -> Result<Self, Self::Error> {
223 match json {
224 Value::Number(value) => value.parse().map_err(|_| Mapped::new(offset, TryIntoNumberError::OutOfBounds(NumberType::default()))),
225 other => Err(Mapped::new(offset, TryIntoNumberError::Unexpected(Unexpected {
226 expected: KindSet::NUMBER,
227 found: other.kind()
228 })))
229 }
230 }
231 }
232 )*
233 };
234}
235
236number_from_json!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, f32, f64);
237
238impl TryFromJson for String {
239 type Error = Mapped<Unexpected>;
240
241 fn try_from_json_at(
242 json: &Value,
243 _code_map: &CodeMap,
244 offset: usize,
245 ) -> Result<Self, Self::Error> {
246 match json {
247 Value::String(value) => Ok(value.to_string()),
248 other => Err(Mapped::new(
249 offset,
250 Unexpected {
251 expected: KindSet::STRING,
252 found: other.kind(),
253 },
254 )),
255 }
256 }
257}
258
259impl<T: TryFromJson> TryFromJson for Vec<T>
260where
261 T::Error: From<Mapped<Unexpected>>,
262{
263 type Error = T::Error;
264
265 fn try_from_json_at(
266 json: &Value,
267 code_map: &CodeMap,
268 offset: usize,
269 ) -> Result<Self, Self::Error> {
270 match json {
271 Value::Array(value) => value
272 .iter_mapped(code_map, offset)
273 .map(|item| T::try_from_json_at(item.value, code_map, item.offset))
274 .collect::<Result<Vec<_>, _>>(),
275 other => Err(Mapped::new(
276 offset,
277 Unexpected {
278 expected: KindSet::ARRAY,
279 found: other.kind(),
280 },
281 )
282 .into()),
283 }
284 }
285}
286
287impl<K: FromStr + Ord, V: TryFromJson> TryFromJson for BTreeMap<K, V>
288where
289 V::Error: From<Mapped<Unexpected>> + From<Mapped<K::Err>>,
290{
291 type Error = V::Error;
292
293 fn try_from_json_at(
294 json: &Value,
295 code_map: &CodeMap,
296 offset: usize,
297 ) -> Result<Self, Self::Error> {
298 match json {
299 Value::Object(object) => {
300 let mut result = BTreeMap::new();
301
302 for entry in object.iter_mapped(code_map, offset) {
303 result.insert(
304 entry
305 .value
306 .key
307 .value
308 .parse()
309 .map_err(|e| Mapped::new(entry.value.key.offset, e))?,
310 V::try_from_json_at(
311 entry.value.value.value,
312 code_map,
313 entry.value.value.offset,
314 )?,
315 );
316 }
317
318 Ok(result)
319 }
320 other => Err(Mapped::new(
321 offset,
322 Unexpected {
323 expected: KindSet::OBJECT,
324 found: other.kind(),
325 },
326 )
327 .into()),
328 }
329 }
330}