1use crate::error::{Error, Result};
16use erltf::term::OwnedTerm;
17use erltf::types::Atom;
18use serde::de::{DeserializeSeed, EnumAccess, MapAccess, SeqAccess, VariantAccess, Visitor};
19use serde::{Deserialize, Deserializer as SerdeDeserializer};
20use std::collections::BTreeMap;
21use std::collections::btree_map;
22use std::sync::OnceLock;
23
24pub fn from_bytes<T: for<'a> Deserialize<'a>>(bytes: &[u8]) -> Result<T> {
25 let term = erltf::decode(bytes).map_err(|e| Error::Erltf(e.into()))?;
26 from_term(&term)
27}
28
29pub fn from_term<'a, T: Deserialize<'a>>(term: &'a OwnedTerm) -> Result<T> {
30 let mut deserializer = Deserializer { term };
31 T::deserialize(&mut deserializer)
32}
33
34pub fn from_proplist<'a, T: Deserialize<'a>>(term: &'a OwnedTerm) -> Result<T> {
35 match term {
36 OwnedTerm::List(elements) => {
37 let deserializer = ProplistDeserializer::new(elements);
38 T::deserialize(deserializer)
39 }
40 OwnedTerm::Nil => {
41 let deserializer = ProplistDeserializer::new(&[]);
42 T::deserialize(deserializer)
43 }
44 _ => Err(Error::TypeMismatch {
45 expected: "proplist (list of tuples)".into(),
46 found: format!("{:?}", term),
47 }),
48 }
49}
50
51pub struct Deserializer<'de> {
52 term: &'de OwnedTerm,
53}
54
55impl<'de> Deserializer<'de> {
56 fn expect_atom(&self, expected: &str) -> Result<&Atom> {
57 match self.term {
58 OwnedTerm::Atom(atom) => {
59 if atom.as_str() == expected {
60 Ok(atom)
61 } else {
62 Err(Error::TypeMismatch {
63 expected: format!("atom '{}'", expected),
64 found: format!("atom '{}'", atom.as_str()),
65 })
66 }
67 }
68 _ => Err(Error::TypeMismatch {
69 expected: format!("atom '{}'", expected),
70 found: format!("{:?}", self.term),
71 }),
72 }
73 }
74}
75
76impl<'de> SerdeDeserializer<'de> for &mut Deserializer<'de> {
77 type Error = Error;
78
79 fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
80 match self.term {
81 OwnedTerm::Atom(atom) => match atom.as_str() {
82 "true" => visitor.visit_bool(true),
83 "false" => visitor.visit_bool(false),
84 "nil" => visitor.visit_unit(),
85 "undefined" => visitor.visit_none(),
86 _ => visitor.visit_str(atom.as_str()),
87 },
88 OwnedTerm::Integer(i) => visitor.visit_i64(*i),
89 OwnedTerm::Float(f) => visitor.visit_f64(*f),
90 OwnedTerm::Binary(b) => {
91 if let Ok(s) = std::str::from_utf8(b) {
92 visitor.visit_str(s)
93 } else {
94 visitor.visit_bytes(b)
95 }
96 }
97 OwnedTerm::String(s) => visitor.visit_str(s),
98 OwnedTerm::List(l) => visitor.visit_seq(SeqDeserializer::new(l)),
99 OwnedTerm::Tuple(t) => visitor.visit_seq(SeqDeserializer::new(t)),
100 OwnedTerm::Map(m) => visitor.visit_map(MapDeserializer::new(m)),
101 OwnedTerm::Nil => visitor.visit_seq(SeqDeserializer::new(&[])),
102 _ => Err(Error::UnsupportedType(format!("{:?}", self.term))),
103 }
104 }
105
106 fn deserialize_bool<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
107 match self.term {
108 OwnedTerm::Atom(atom) => match atom.as_str() {
109 "true" => visitor.visit_bool(true),
110 "false" => visitor.visit_bool(false),
111 _ => Err(Error::TypeMismatch {
112 expected: "bool atom".into(),
113 found: format!("{:?}", atom),
114 }),
115 },
116 _ => Err(Error::TypeMismatch {
117 expected: "bool atom".into(),
118 found: format!("{:?}", self.term),
119 }),
120 }
121 }
122
123 fn deserialize_i8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
124 match self.term {
125 OwnedTerm::Integer(i) => i8::try_from(*i)
126 .map_err(|_| Error::InvalidValue(format!("integer {} out of range for i8", i)))
127 .and_then(|v| visitor.visit_i8(v)),
128 _ => Err(Error::TypeMismatch {
129 expected: "integer".into(),
130 found: format!("{:?}", self.term),
131 }),
132 }
133 }
134
135 fn deserialize_i16<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
136 match self.term {
137 OwnedTerm::Integer(i) => i16::try_from(*i)
138 .map_err(|_| Error::InvalidValue(format!("integer {} out of range for i16", i)))
139 .and_then(|v| visitor.visit_i16(v)),
140 _ => Err(Error::TypeMismatch {
141 expected: "integer".into(),
142 found: format!("{:?}", self.term),
143 }),
144 }
145 }
146
147 fn deserialize_i32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
148 match self.term {
149 OwnedTerm::Integer(i) => i32::try_from(*i)
150 .map_err(|_| Error::InvalidValue(format!("integer {} out of range for i32", i)))
151 .and_then(|v| visitor.visit_i32(v)),
152 _ => Err(Error::TypeMismatch {
153 expected: "integer".into(),
154 found: format!("{:?}", self.term),
155 }),
156 }
157 }
158
159 fn deserialize_i64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
160 match self.term {
161 OwnedTerm::Integer(i) => visitor.visit_i64(*i),
162 _ => Err(Error::TypeMismatch {
163 expected: "integer".into(),
164 found: format!("{:?}", self.term),
165 }),
166 }
167 }
168
169 fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
170 match self.term {
171 OwnedTerm::Integer(i) => u8::try_from(*i)
172 .map_err(|_| Error::InvalidValue(format!("integer {} out of range for u8", i)))
173 .and_then(|v| visitor.visit_u8(v)),
174 _ => Err(Error::TypeMismatch {
175 expected: "integer".into(),
176 found: format!("{:?}", self.term),
177 }),
178 }
179 }
180
181 fn deserialize_u16<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
182 match self.term {
183 OwnedTerm::Integer(i) => u16::try_from(*i)
184 .map_err(|_| Error::InvalidValue(format!("integer {} out of range for u16", i)))
185 .and_then(|v| visitor.visit_u16(v)),
186 _ => Err(Error::TypeMismatch {
187 expected: "integer".into(),
188 found: format!("{:?}", self.term),
189 }),
190 }
191 }
192
193 fn deserialize_u32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
194 match self.term {
195 OwnedTerm::Integer(i) => u32::try_from(*i)
196 .map_err(|_| Error::InvalidValue(format!("integer {} out of range for u32", i)))
197 .and_then(|v| visitor.visit_u32(v)),
198 _ => Err(Error::TypeMismatch {
199 expected: "integer".into(),
200 found: format!("{:?}", self.term),
201 }),
202 }
203 }
204
205 fn deserialize_u64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
206 match self.term {
207 OwnedTerm::Integer(i) => u64::try_from(*i)
208 .map_err(|_| Error::InvalidValue(format!("integer {} out of range for u64", i)))
209 .and_then(|v| visitor.visit_u64(v)),
210 OwnedTerm::BigInt(big) if big.sign.is_positive() && big.digits.len() <= 8 => {
211 let mut bytes = [0u8; 8];
212 bytes[..big.digits.len()].copy_from_slice(&big.digits);
213 let value = u64::from_le_bytes(bytes);
214 visitor.visit_u64(value)
215 }
216 _ => Err(Error::TypeMismatch {
217 expected: "integer or unsigned bigint".into(),
218 found: format!("{:?}", self.term),
219 }),
220 }
221 }
222
223 fn deserialize_f32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
224 match self.term {
225 OwnedTerm::Float(f) => visitor.visit_f32(*f as f32),
226 _ => Err(Error::TypeMismatch {
227 expected: "float".into(),
228 found: format!("{:?}", self.term),
229 }),
230 }
231 }
232
233 fn deserialize_f64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
234 match self.term {
235 OwnedTerm::Float(f) => visitor.visit_f64(*f),
236 _ => Err(Error::TypeMismatch {
237 expected: "float".into(),
238 found: format!("{:?}", self.term),
239 }),
240 }
241 }
242
243 fn deserialize_char<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
244 match self.term {
245 OwnedTerm::String(s) => {
246 let mut chars = s.chars();
247 if let Some(c) = chars.next()
248 && chars.next().is_none()
249 {
250 return visitor.visit_char(c);
251 }
252 Err(Error::InvalidValue("expected single char".into()))
253 }
254 _ => Err(Error::TypeMismatch {
255 expected: "string".into(),
256 found: format!("{:?}", self.term),
257 }),
258 }
259 }
260
261 fn deserialize_str<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
262 match self.term {
263 OwnedTerm::Binary(b) => {
264 let s = std::str::from_utf8(b).map_err(|e| Error::InvalidValue(e.to_string()))?;
265 visitor.visit_borrowed_str(s)
266 }
267 OwnedTerm::String(s) => visitor.visit_borrowed_str(s),
268 OwnedTerm::Atom(a) => visitor.visit_borrowed_str(a.as_str()),
269 _ => Err(Error::TypeMismatch {
270 expected: "string or binary".into(),
271 found: format!("{:?}", self.term),
272 }),
273 }
274 }
275
276 fn deserialize_string<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
277 self.deserialize_str(visitor)
278 }
279
280 fn deserialize_bytes<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
281 match self.term {
282 OwnedTerm::Binary(b) => visitor.visit_borrowed_bytes(b),
283 _ => Err(Error::TypeMismatch {
284 expected: "binary".into(),
285 found: format!("{:?}", self.term),
286 }),
287 }
288 }
289
290 fn deserialize_byte_buf<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
291 self.deserialize_bytes(visitor)
292 }
293
294 fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
295 match self.term {
296 OwnedTerm::Atom(atom) if atom.as_str() == "undefined" => visitor.visit_none(),
297 _ => visitor.visit_some(self),
298 }
299 }
300
301 fn deserialize_unit<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
302 self.expect_atom("nil")?;
303 visitor.visit_unit()
304 }
305
306 fn deserialize_unit_struct<V: Visitor<'de>>(
307 self,
308 name: &'static str,
309 visitor: V,
310 ) -> Result<V::Value> {
311 self.expect_atom(name)?;
312 visitor.visit_unit()
313 }
314
315 fn deserialize_newtype_struct<V: Visitor<'de>>(
316 self,
317 _name: &'static str,
318 visitor: V,
319 ) -> Result<V::Value> {
320 visitor.visit_newtype_struct(self)
321 }
322
323 fn deserialize_seq<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
324 match self.term {
325 OwnedTerm::List(l) => visitor.visit_seq(SeqDeserializer::new(l)),
326 OwnedTerm::Nil => visitor.visit_seq(SeqDeserializer::new(&[])),
327 _ => Err(Error::TypeMismatch {
328 expected: "list".into(),
329 found: format!("{:?}", self.term),
330 }),
331 }
332 }
333
334 fn deserialize_tuple<V: Visitor<'de>>(self, _len: usize, visitor: V) -> Result<V::Value> {
335 match self.term {
336 OwnedTerm::Tuple(t) => visitor.visit_seq(SeqDeserializer::new(t)),
337 _ => Err(Error::TypeMismatch {
338 expected: "tuple".into(),
339 found: format!("{:?}", self.term),
340 }),
341 }
342 }
343
344 fn deserialize_tuple_struct<V: Visitor<'de>>(
345 self,
346 _name: &'static str,
347 _len: usize,
348 visitor: V,
349 ) -> Result<V::Value> {
350 match self.term {
351 OwnedTerm::Tuple(t) => visitor.visit_seq(SeqDeserializer::new(t)),
352 _ => Err(Error::TypeMismatch {
353 expected: "tuple".into(),
354 found: format!("{:?}", self.term),
355 }),
356 }
357 }
358
359 fn deserialize_map<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
360 match self.term {
361 OwnedTerm::Map(m) => visitor.visit_map(MapDeserializer::new(m)),
362 _ => Err(Error::TypeMismatch {
363 expected: "map".into(),
364 found: format!("{:?}", self.term),
365 }),
366 }
367 }
368
369 fn deserialize_struct<V: Visitor<'de>>(
370 self,
371 _name: &'static str,
372 _fields: &'static [&'static str],
373 visitor: V,
374 ) -> Result<V::Value> {
375 self.deserialize_map(visitor)
376 }
377
378 fn deserialize_enum<V: Visitor<'de>>(
379 self,
380 _name: &'static str,
381 _variants: &'static [&'static str],
382 visitor: V,
383 ) -> Result<V::Value> {
384 match self.term {
385 OwnedTerm::Atom(_) => visitor.visit_enum(EnumDeserializer { term: self.term }),
386 OwnedTerm::Tuple(elements) if !elements.is_empty() => {
387 visitor.visit_enum(EnumDeserializer { term: self.term })
388 }
389 _ => Err(Error::TypeMismatch {
390 expected: "atom or tuple".into(),
391 found: format!("{:?}", self.term),
392 }),
393 }
394 }
395
396 fn deserialize_identifier<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
397 self.deserialize_str(visitor)
398 }
399
400 fn deserialize_ignored_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
401 visitor.visit_unit()
402 }
403}
404
405struct SeqDeserializer<'de> {
406 iter: std::slice::Iter<'de, OwnedTerm>,
407}
408
409impl<'de> SeqDeserializer<'de> {
410 fn new(slice: &'de [OwnedTerm]) -> Self {
411 SeqDeserializer { iter: slice.iter() }
412 }
413}
414
415impl<'de> SeqAccess<'de> for SeqDeserializer<'de> {
416 type Error = Error;
417
418 fn next_element_seed<T: DeserializeSeed<'de>>(&mut self, seed: T) -> Result<Option<T::Value>> {
419 match self.iter.next() {
420 Some(term) => {
421 let mut de = Deserializer { term };
422 seed.deserialize(&mut de).map(Some)
423 }
424 None => Ok(None),
425 }
426 }
427}
428
429struct MapDeserializer<'de> {
430 iter: btree_map::Iter<'de, OwnedTerm, OwnedTerm>,
431 value: Option<&'de OwnedTerm>,
432}
433
434impl<'de> MapDeserializer<'de> {
435 fn new(map: &'de BTreeMap<OwnedTerm, OwnedTerm>) -> Self {
436 MapDeserializer {
437 iter: map.iter(),
438 value: None,
439 }
440 }
441}
442
443impl<'de> MapAccess<'de> for MapDeserializer<'de> {
444 type Error = Error;
445
446 fn next_key_seed<K: DeserializeSeed<'de>>(&mut self, seed: K) -> Result<Option<K::Value>> {
447 match self.iter.next() {
448 Some((key, value)) => {
449 self.value = Some(value);
450 let mut de = Deserializer { term: key };
451 seed.deserialize(&mut de).map(Some)
452 }
453 None => Ok(None),
454 }
455 }
456
457 fn next_value_seed<V: DeserializeSeed<'de>>(&mut self, seed: V) -> Result<V::Value> {
458 match self.value.take() {
459 Some(value) => {
460 let mut de = Deserializer { term: value };
461 seed.deserialize(&mut de)
462 }
463 None => Err(Error::Message("next_value called without next_key".into())),
464 }
465 }
466}
467
468struct EnumDeserializer<'de> {
469 term: &'de OwnedTerm,
470}
471
472impl<'de> EnumAccess<'de> for EnumDeserializer<'de> {
473 type Error = Error;
474 type Variant = VariantDeserializer<'de>;
475
476 fn variant_seed<V: DeserializeSeed<'de>>(self, seed: V) -> Result<(V::Value, Self::Variant)> {
477 match self.term {
478 OwnedTerm::Atom(_) => {
479 let mut de = Deserializer { term: self.term };
480 let val = seed.deserialize(&mut de)?;
481 Ok((val, VariantDeserializer { rest: &[] }))
482 }
483 OwnedTerm::Tuple(elements) if !elements.is_empty() => {
484 let mut de = Deserializer { term: &elements[0] };
485 let val = seed.deserialize(&mut de)?;
486 let rest = if elements.len() > 1 {
487 &elements[1..]
488 } else {
489 &elements[0..0]
490 };
491 Ok((val, VariantDeserializer { rest }))
492 }
493 _ => Err(Error::TypeMismatch {
494 expected: "enum (atom or tuple)".into(),
495 found: format!("{:?}", self.term),
496 }),
497 }
498 }
499}
500
501struct VariantDeserializer<'de> {
502 rest: &'de [OwnedTerm],
503}
504
505impl<'de> VariantAccess<'de> for VariantDeserializer<'de> {
506 type Error = Error;
507
508 fn unit_variant(self) -> Result<()> {
509 if self.rest.is_empty() {
510 Ok(())
511 } else {
512 Err(Error::TypeMismatch {
513 expected: "unit variant".into(),
514 found: format!("variant with {} elements", self.rest.len()),
515 })
516 }
517 }
518
519 fn newtype_variant_seed<T: DeserializeSeed<'de>>(self, seed: T) -> Result<T::Value> {
520 if self.rest.len() == 1 {
521 let mut de = Deserializer {
522 term: &self.rest[0],
523 };
524 seed.deserialize(&mut de)
525 } else {
526 Err(Error::TypeMismatch {
527 expected: "newtype variant with 1 element".into(),
528 found: format!("variant with {} elements", self.rest.len()),
529 })
530 }
531 }
532
533 fn tuple_variant<V: Visitor<'de>>(self, _len: usize, visitor: V) -> Result<V::Value> {
534 visitor.visit_seq(SeqDeserializer::new(self.rest))
535 }
536
537 fn struct_variant<V: Visitor<'de>>(
538 self,
539 _fields: &'static [&'static str],
540 visitor: V,
541 ) -> Result<V::Value> {
542 if self.rest.len() == 1 {
543 match &self.rest[0] {
544 OwnedTerm::Map(m) => visitor.visit_map(MapDeserializer::new(m)),
545 _ => Err(Error::TypeMismatch {
546 expected: "struct variant (map)".into(),
547 found: format!("{:?}", self.rest[0]),
548 }),
549 }
550 } else {
551 Err(Error::TypeMismatch {
552 expected: "struct variant with 1 map element".into(),
553 found: format!("variant with {} elements", self.rest.len()),
554 })
555 }
556 }
557}
558
559pub struct ProplistDeserializer<'de> {
560 elements: &'de [OwnedTerm],
561}
562
563impl<'de> ProplistDeserializer<'de> {
564 pub fn new(elements: &'de [OwnedTerm]) -> Self {
565 ProplistDeserializer { elements }
566 }
567}
568
569impl<'de> SerdeDeserializer<'de> for ProplistDeserializer<'de> {
570 type Error = Error;
571
572 fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
573 visitor.visit_map(ProplistMapAccess {
574 elements: self.elements,
575 index: 0,
576 current_value: ProplistValue::None,
577 })
578 }
579
580 fn deserialize_map<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
581 visitor.visit_map(ProplistMapAccess {
582 elements: self.elements,
583 index: 0,
584 current_value: ProplistValue::None,
585 })
586 }
587
588 fn deserialize_struct<V: Visitor<'de>>(
589 self,
590 _name: &'static str,
591 _fields: &'static [&'static str],
592 visitor: V,
593 ) -> Result<V::Value> {
594 self.deserialize_map(visitor)
595 }
596
597 serde::forward_to_deserialize_any! {
598 bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string
599 bytes byte_buf option unit unit_struct newtype_struct seq tuple
600 tuple_struct enum identifier ignored_any
601 }
602}
603
604struct ProplistMapAccess<'de> {
605 elements: &'de [OwnedTerm],
606 index: usize,
607 current_value: ProplistValue<'de>,
608}
609
610enum ProplistValue<'de> {
611 None,
612 Ref(&'de OwnedTerm),
613 BareAtom,
614}
615
616impl<'de> MapAccess<'de> for ProplistMapAccess<'de> {
617 type Error = Error;
618
619 fn next_key_seed<K: DeserializeSeed<'de>>(&mut self, seed: K) -> Result<Option<K::Value>> {
620 while self.index < self.elements.len() {
621 let element = &self.elements[self.index];
622 self.index += 1;
623
624 match element {
625 OwnedTerm::Tuple(t) if t.len() == 2 => {
626 self.current_value = ProplistValue::Ref(&t[1]);
627 let mut de = Deserializer { term: &t[0] };
628 return seed.deserialize(&mut de).map(Some);
629 }
630 OwnedTerm::Atom(_) => {
631 self.current_value = ProplistValue::BareAtom;
632 let mut de = Deserializer { term: element };
633 return seed.deserialize(&mut de).map(Some);
634 }
635 _ => continue,
636 }
637 }
638 Ok(None)
639 }
640
641 fn next_value_seed<V: DeserializeSeed<'de>>(&mut self, seed: V) -> Result<V::Value> {
642 match std::mem::replace(&mut self.current_value, ProplistValue::None) {
643 ProplistValue::Ref(value) => {
644 let mut de = Deserializer { term: value };
645 seed.deserialize(&mut de)
646 }
647 ProplistValue::BareAtom => {
648 static TRUE_TERM: OnceLock<OwnedTerm> = OnceLock::new();
649 let true_term = TRUE_TERM.get_or_init(|| OwnedTerm::Atom(Atom::new("true")));
650 let mut de = Deserializer { term: true_term };
651 seed.deserialize(&mut de)
652 }
653 ProplistValue::None => Err(Error::Message("next_value called without next_key".into())),
654 }
655 }
656}