Skip to main content

apple_plist/value/
de.rs

1//! The serde bridge from [`Value`] trees to Rust values: the
2//! deserialization-side type switch.
3
4#[cfg(test)]
5use std::collections::BTreeMap;
6use std::{fmt, vec};
7
8use serde::de::{
9    self, Deserialize, DeserializeOwned, DeserializeSeed, Deserializer, EnumAccess, MapAccess,
10    SeqAccess, Unexpected, VariantAccess, Visitor,
11};
12use serde::forward_to_deserialize_any;
13
14use crate::date::Date;
15use crate::depth::MAX_PARSE_DEPTH;
16use crate::error::{Error, Result};
17use crate::scalar;
18use crate::uid::Uid;
19use crate::value::ser::{
20    DATE_NEWTYPE, UID_NEWTYPE, format_sentinel_date, narrow_f32, parse_sentinel_date,
21};
22use crate::value::{Dictionary, Integer, Real, Value};
23
24/// Converts an owned [`Value`] tree into any [`DeserializeOwned`] type,
25/// always in strict mode (the lax string coercions are reserved for the
26/// OpenStep decode path).
27///
28/// # Errors
29///
30/// Returns [`Error::TypeMismatch`] when a value's kind cannot satisfy the
31/// requested target, [`Error::MaxDepthExceeded`] for trees nested beyond
32/// [`MAX_PARSE_DEPTH`] containers, and [`Error::Message`] for the failures
33/// serde itself reports (integer range overflow, missing struct fields,
34/// unknown enum variants, arity mismatches). Borrowing targets such as
35/// `&str` are unreachable through the [`DeserializeOwned`] bound: the tree
36/// is owned, so only owned visit methods are ever called.
37///
38/// # Examples
39///
40/// ```
41/// use apple_plist::Value;
42///
43/// let answer: i64 = apple_plist::from_value(Value::from(42u8))?;
44/// assert_eq!(answer, 42);
45/// # Ok::<(), apple_plist::Error>(())
46/// ```
47pub fn from_value<T>(value: Value) -> Result<T>
48where
49    T: DeserializeOwned,
50{
51    T::deserialize(ValueDeserializer::new(value, false))
52}
53
54const fn guard_entry(depth: usize) -> Result<()> {
55    if depth > MAX_PARSE_DEPTH {
56        Err(Error::MaxDepthExceeded)
57    } else {
58        Ok(())
59    }
60}
61
62/// Counts one container frame: entering the 129th nested container fails,
63/// matching the parsers' shared cap.
64const fn guard_descent(depth: usize) -> Result<usize> {
65    if depth >= MAX_PARSE_DEPTH {
66        Err(Error::MaxDepthExceeded)
67    } else {
68        Ok(depth + 1)
69    }
70}
71
72fn unexpected_value(value: &Value) -> Unexpected<'_> {
73    match value {
74        Value::Dictionary(_) => Unexpected::Map,
75        Value::Array(_) => Unexpected::Seq,
76        Value::String(s) => Unexpected::Str(s),
77        Value::Integer(Integer::Signed(signed)) => Unexpected::Signed(*signed),
78        Value::Integer(Integer::Unsigned(unsigned)) => Unexpected::Unsigned(*unsigned),
79        Value::Real(real) => Unexpected::Float(real.value()),
80        Value::Boolean(b) => Unexpected::Bool(*b),
81        Value::Data(data) => Unexpected::Bytes(data),
82        Value::Date(_) => Unexpected::Other("date"),
83        Value::Uid(_) => Unexpected::Other("UID"),
84    }
85}
86
87fn visit_array<'de, V>(values: Vec<Value>, depth: usize, lax: bool, visitor: V) -> Result<V::Value>
88where
89    V: Visitor<'de>,
90{
91    let len = values.len();
92    let mut access = SeqAccessor {
93        iter: values.into_iter(),
94        depth,
95        lax,
96    };
97    let result = visitor.visit_seq(&mut access)?;
98    if access.iter.len() == 0 {
99        Ok(result)
100    } else {
101        Err(de::Error::invalid_length(len, &"fewer elements in array"))
102    }
103}
104
105fn visit_dictionary<'de, V>(
106    dict: Dictionary,
107    depth: usize,
108    lax: bool,
109    visitor: V,
110) -> Result<V::Value>
111where
112    V: Visitor<'de>,
113{
114    let len = dict.len();
115    let mut access = MapAccessor {
116        iter: dict.into_iter(),
117        pending_value: None,
118        depth,
119        lax,
120    };
121    let result = visitor.visit_map(&mut access)?;
122    if access.iter.len() == 0 && access.pending_value.is_none() {
123        Ok(result)
124    } else {
125        Err(de::Error::invalid_length(
126            len,
127            &"fewer entries in dictionary",
128        ))
129    }
130}
131
132/// The [`Deserializer`] walking an owned [`Value`] tree: the value-kind
133/// type switch.
134///
135/// `lax` enables the string-to-scalar coercions applied to OpenStep
136/// documents only; `depth` carries the container nesting count toward the
137/// shared [`MAX_PARSE_DEPTH`] cap.
138pub(crate) struct ValueDeserializer {
139    value: Value,
140    depth: usize,
141    lax: bool,
142}
143
144impl ValueDeserializer {
145    /// Roots a deserializer over `value`; the decode ladder passes
146    /// `lax = true` if and only if format detection reported OpenStep.
147    pub(crate) const fn new(value: Value, lax: bool) -> Self {
148        Self {
149            value,
150            depth: 0,
151            lax,
152        }
153    }
154
155    const fn at(value: Value, depth: usize, lax: bool) -> Self {
156        Self { value, depth, lax }
157    }
158
159    fn integer_target<'de, V>(
160        self,
161        visitor: V,
162        expected: &'static str,
163        signed: bool,
164    ) -> Result<V::Value>
165    where
166        V: Visitor<'de>,
167    {
168        guard_entry(self.depth)?;
169        let found = self.value.type_name();
170        match self.value {
171            Value::Integer(Integer::Signed(value)) => visitor.visit_i64(value),
172            Value::Integer(Integer::Unsigned(value)) => visitor.visit_u64(value),
173            Value::Uid(uid) => visitor.visit_u64(uid.get()),
174            Value::String(s) if self.lax => {
175                if signed {
176                    visitor.visit_i64(scalar::parse_i64(&s, 10)?)
177                } else {
178                    visitor.visit_u64(scalar::parse_u64(&s, 10)?)
179                }
180            }
181            _ => Err(Error::TypeMismatch { expected, found }),
182        }
183    }
184
185    fn float_target<'de, V>(self, visitor: V, expected: &'static str) -> Result<V::Value>
186    where
187        V: Visitor<'de>,
188    {
189        guard_entry(self.depth)?;
190        let found = self.value.type_name();
191        match self.value {
192            Value::Real(real) => visitor.visit_f64(real.value()),
193            Value::String(s) if self.lax => visitor.visit_f64(scalar::parse_f64(&s)?),
194            _ => Err(Error::TypeMismatch { expected, found }),
195        }
196    }
197
198    fn string_target<'de, V>(self, visitor: V, expected: &'static str) -> Result<V::Value>
199    where
200        V: Visitor<'de>,
201    {
202        guard_entry(self.depth)?;
203        let found = self.value.type_name();
204        match self.value {
205            Value::String(s) => visitor.visit_string(s),
206            _ => Err(Error::TypeMismatch { expected, found }),
207        }
208    }
209
210    /// The UID arm behind the [`Uid`] sentinel.
211    fn uid_sentinel<'de, V>(self, visitor: V) -> Result<V::Value>
212    where
213        V: Visitor<'de>,
214    {
215        let found = self.value.type_name();
216        match self.value {
217            Value::Uid(uid) => visitor.visit_u64(uid.get()),
218            Value::Integer(Integer::Signed(value)) if value < 0 => visitor.visit_i64(value),
219            Value::Integer(Integer::Signed(value)) => visitor.visit_u64(value.cast_unsigned()),
220            Value::Integer(Integer::Unsigned(value)) => visitor.visit_u64(value),
221            Value::String(s) if self.lax => visitor.visit_u64(scalar::parse_u64(&s, 10)?),
222            _ => Err(Error::TypeMismatch {
223                expected: "UID",
224                found,
225            }),
226        }
227    }
228
229    /// The date arm plus the lax text-layout parse behind the [`Date`]
230    /// sentinel.
231    fn date_sentinel<'de, V>(self, visitor: V) -> Result<V::Value>
232    where
233        V: Visitor<'de>,
234    {
235        let found = self.value.type_name();
236        match self.value {
237            Value::Date(date) => visitor.visit_string(format_sentinel_date(date)),
238            Value::String(s) if self.lax => Date::parse_text_layout(&s).map_or_else(
239                || Err(Error::ParseScalar(format!("invalid date literal: {s}"))),
240                |date| visitor.visit_string(format_sentinel_date(date)),
241            ),
242            _ => Err(Error::TypeMismatch {
243                expected: "date",
244                found,
245            }),
246        }
247    }
248}
249
250macro_rules! deserialize_signed_integer {
251    ($($method:ident: $expected:literal,)*) => {$(
252        fn $method<V>(self, visitor: V) -> Result<V::Value>
253        where
254            V: Visitor<'de>,
255        {
256            self.integer_target(visitor, $expected, true)
257        }
258    )*};
259}
260
261macro_rules! deserialize_unsigned_integer {
262    ($($method:ident: $expected:literal,)*) => {$(
263        fn $method<V>(self, visitor: V) -> Result<V::Value>
264        where
265            V: Visitor<'de>,
266        {
267            self.integer_target(visitor, $expected, false)
268        }
269    )*};
270}
271
272impl<'de> Deserializer<'de> for ValueDeserializer {
273    type Error = Error;
274
275    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
276    where
277        V: Visitor<'de>,
278    {
279        guard_entry(self.depth)?;
280        let Self { value, depth, lax } = self;
281        match value {
282            Value::Dictionary(dict) => visit_dictionary(dict, guard_descent(depth)?, lax, visitor),
283            Value::Array(values) => visit_array(values, guard_descent(depth)?, lax, visitor),
284            // Lax never applies here: decoding into `any` keeps the string.
285            Value::String(s) => visitor.visit_string(s),
286            Value::Integer(Integer::Signed(signed)) if signed < 0 => visitor.visit_i64(signed),
287            Value::Integer(Integer::Signed(signed)) => visitor.visit_u64(signed.cast_unsigned()),
288            Value::Integer(Integer::Unsigned(unsigned)) => visitor.visit_u64(unsigned),
289            Value::Real(real) if real.wide() => visitor.visit_f64(real.value()),
290            Value::Real(real) => visitor.visit_f32(narrow_f32(real)),
291            Value::Boolean(b) => visitor.visit_bool(b),
292            Value::Data(data) => visitor.visit_byte_buf(data),
293            Value::Date(date) => visitor.visit_newtype_struct(DatePayloadDeserializer { date }),
294            Value::Uid(uid) => visitor.visit_newtype_struct(UidPayloadDeserializer { uid }),
295        }
296    }
297
298    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
299    where
300        V: Visitor<'de>,
301    {
302        guard_entry(self.depth)?;
303        let found = self.value.type_name();
304        match self.value {
305            Value::Boolean(b) => visitor.visit_bool(b),
306            Value::String(s) if self.lax => visitor.visit_bool(scalar::parse_bool(&s)?),
307            _ => Err(Error::TypeMismatch {
308                expected: "bool",
309                found,
310            }),
311        }
312    }
313
314    deserialize_signed_integer! {
315        deserialize_i8: "i8",
316        deserialize_i16: "i16",
317        deserialize_i32: "i32",
318        deserialize_i64: "i64",
319        deserialize_i128: "i128",
320    }
321
322    deserialize_unsigned_integer! {
323        deserialize_u8: "u8",
324        deserialize_u16: "u16",
325        deserialize_u32: "u32",
326        deserialize_u64: "u64",
327        deserialize_u128: "u128",
328    }
329
330    fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
331    where
332        V: Visitor<'de>,
333    {
334        self.float_target(visitor, "f32")
335    }
336
337    fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
338    where
339        V: Visitor<'de>,
340    {
341        self.float_target(visitor, "f64")
342    }
343
344    fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
345    where
346        V: Visitor<'de>,
347    {
348        self.string_target(visitor, "char")
349    }
350
351    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
352    where
353        V: Visitor<'de>,
354    {
355        self.string_target(visitor, "string")
356    }
357
358    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
359    where
360        V: Visitor<'de>,
361    {
362        self.string_target(visitor, "string")
363    }
364
365    fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
366    where
367        V: Visitor<'de>,
368    {
369        guard_entry(self.depth)?;
370        let Self { value, depth, lax } = self;
371        let found = value.type_name();
372        match value {
373            Value::Data(data) => visitor.visit_byte_buf(data),
374            Value::Array(values) => visit_array(values, guard_descent(depth)?, lax, visitor),
375            // A string never coerces to bytes, in strict or lax mode.
376            _ => Err(Error::TypeMismatch {
377                expected: "bytes",
378                found,
379            }),
380        }
381    }
382
383    fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
384    where
385        V: Visitor<'de>,
386    {
387        self.deserialize_bytes(visitor)
388    }
389
390    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
391    where
392        V: Visitor<'de>,
393    {
394        guard_entry(self.depth)?;
395        visitor.visit_some(self)
396    }
397
398    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
399    where
400        V: Visitor<'de>,
401    {
402        guard_entry(self.depth)?;
403        drop(visitor);
404        Err(Error::TypeMismatch {
405            expected: "unit",
406            found: self.value.type_name(),
407        })
408    }
409
410    fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
411    where
412        V: Visitor<'de>,
413    {
414        guard_entry(self.depth)?;
415        drop(visitor);
416        Err(Error::TypeMismatch {
417            expected: name,
418            found: self.value.type_name(),
419        })
420    }
421
422    fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
423    where
424        V: Visitor<'de>,
425    {
426        guard_entry(self.depth)?;
427        match name {
428            UID_NEWTYPE => self.uid_sentinel(visitor),
429            DATE_NEWTYPE => self.date_sentinel(visitor),
430            _ => visitor.visit_newtype_struct(self),
431        }
432    }
433
434    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
435    where
436        V: Visitor<'de>,
437    {
438        guard_entry(self.depth)?;
439        let Self { value, depth, lax } = self;
440        let found = value.type_name();
441        match value {
442            Value::Array(values) => visit_array(values, guard_descent(depth)?, lax, visitor),
443            // Data is a leaf in the depth model: its bytes do not descend.
444            Value::Data(data) => {
445                let bytes = data
446                    .into_iter()
447                    .map(|byte| Value::Integer(Integer::from(byte)))
448                    .collect();
449                visit_array(bytes, depth, lax, visitor)
450            }
451            _ => Err(Error::TypeMismatch {
452                expected: "sequence",
453                found,
454            }),
455        }
456    }
457
458    fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>
459    where
460        V: Visitor<'de>,
461    {
462        self.deserialize_seq(visitor)
463    }
464
465    fn deserialize_tuple_struct<V>(
466        self,
467        _name: &'static str,
468        _len: usize,
469        visitor: V,
470    ) -> Result<V::Value>
471    where
472        V: Visitor<'de>,
473    {
474        self.deserialize_seq(visitor)
475    }
476
477    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
478    where
479        V: Visitor<'de>,
480    {
481        guard_entry(self.depth)?;
482        let Self { value, depth, lax } = self;
483        let found = value.type_name();
484        match value {
485            Value::Dictionary(dict) => visit_dictionary(dict, guard_descent(depth)?, lax, visitor),
486            _ => Err(Error::TypeMismatch {
487                expected: "map",
488                found,
489            }),
490        }
491    }
492
493    fn deserialize_struct<V>(
494        self,
495        name: &'static str,
496        _fields: &'static [&'static str],
497        visitor: V,
498    ) -> Result<V::Value>
499    where
500        V: Visitor<'de>,
501    {
502        guard_entry(self.depth)?;
503        let Self { value, depth, lax } = self;
504        let found = value.type_name();
505        match value {
506            Value::Dictionary(dict) => visit_dictionary(dict, guard_descent(depth)?, lax, visitor),
507            _ => Err(Error::TypeMismatch {
508                expected: name,
509                found,
510            }),
511        }
512    }
513
514    fn deserialize_enum<V>(
515        self,
516        name: &'static str,
517        _variants: &'static [&'static str],
518        visitor: V,
519    ) -> Result<V::Value>
520    where
521        V: Visitor<'de>,
522    {
523        guard_entry(self.depth)?;
524        let Self { value, depth, lax } = self;
525        let found = value.type_name();
526        match value {
527            Value::String(variant) => visitor.visit_enum(EnumDeserializer {
528                variant,
529                payload: None,
530                depth,
531                lax,
532            }),
533            Value::Dictionary(dict) => {
534                let depth = guard_descent(depth)?;
535                let mut entries = dict.into_iter();
536                match (entries.next(), entries.next()) {
537                    (Some((variant, payload)), None) => visitor.visit_enum(EnumDeserializer {
538                        variant,
539                        payload: Some(payload),
540                        depth,
541                        lax,
542                    }),
543                    _ => Err(Error::Message(
544                        "expected a single-key dictionary for an enum variant".to_owned(),
545                    )),
546                }
547            }
548            _ => Err(Error::TypeMismatch {
549                expected: name,
550                found,
551            }),
552        }
553    }
554
555    fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
556    where
557        V: Visitor<'de>,
558    {
559        self.string_target(visitor, "identifier")
560    }
561
562    fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
563    where
564        V: Visitor<'de>,
565    {
566        self.deserialize_any(visitor)
567    }
568
569    fn is_human_readable(&self) -> bool {
570        true
571    }
572}
573
574struct SeqAccessor {
575    iter: vec::IntoIter<Value>,
576    depth: usize,
577    lax: bool,
578}
579
580impl<'de> SeqAccess<'de> for SeqAccessor {
581    type Error = Error;
582
583    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
584    where
585        T: DeserializeSeed<'de>,
586    {
587        self.iter.next().map_or(Ok(None), |value| {
588            seed.deserialize(ValueDeserializer::at(value, self.depth, self.lax))
589                .map(Some)
590        })
591    }
592
593    fn size_hint(&self) -> Option<usize> {
594        Some(self.iter.len())
595    }
596}
597
598struct MapAccessor {
599    iter: indexmap::map::IntoIter<String, Value>,
600    pending_value: Option<Value>,
601    depth: usize,
602    lax: bool,
603}
604
605impl<'de> MapAccess<'de> for MapAccessor {
606    type Error = Error;
607
608    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
609    where
610        K: DeserializeSeed<'de>,
611    {
612        self.iter.next().map_or(Ok(None), |(key, value)| {
613            self.pending_value = Some(value);
614            // Keys never lax-coerce: dictionary keys are converted, not parsed.
615            seed.deserialize(ValueDeserializer::at(Value::String(key), self.depth, false))
616                .map(Some)
617        })
618    }
619
620    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
621    where
622        V: DeserializeSeed<'de>,
623    {
624        self.pending_value.take().map_or_else(
625            || {
626                Err(Error::Message(
627                    "map value requested before its key".to_owned(),
628                ))
629            },
630            |value| seed.deserialize(ValueDeserializer::at(value, self.depth, self.lax)),
631        )
632    }
633
634    fn size_hint(&self) -> Option<usize> {
635        Some(
636            self.iter
637                .len()
638                .saturating_add(usize::from(self.pending_value.is_some())),
639        )
640    }
641}
642
643struct EnumDeserializer {
644    variant: String,
645    payload: Option<Value>,
646    depth: usize,
647    lax: bool,
648}
649
650impl<'de> EnumAccess<'de> for EnumDeserializer {
651    type Error = Error;
652    type Variant = VariantDeserializer;
653
654    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, VariantDeserializer)>
655    where
656        V: DeserializeSeed<'de>,
657    {
658        let variant = seed.deserialize(ValueDeserializer::at(
659            Value::String(self.variant),
660            self.depth,
661            self.lax,
662        ))?;
663        Ok((
664            variant,
665            VariantDeserializer {
666                payload: self.payload,
667                depth: self.depth,
668                lax: self.lax,
669            },
670        ))
671    }
672}
673
674struct VariantDeserializer {
675    payload: Option<Value>,
676    depth: usize,
677    lax: bool,
678}
679
680impl<'de> VariantAccess<'de> for VariantDeserializer {
681    type Error = Error;
682
683    fn unit_variant(self) -> Result<()> {
684        self.payload.map_or(Ok(()), |value| {
685            Err(de::Error::invalid_type(
686                unexpected_value(&value),
687                &"unit variant",
688            ))
689        })
690    }
691
692    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
693    where
694        T: DeserializeSeed<'de>,
695    {
696        self.payload.map_or_else(
697            || {
698                Err(de::Error::invalid_type(
699                    Unexpected::UnitVariant,
700                    &"newtype variant",
701                ))
702            },
703            |value| seed.deserialize(ValueDeserializer::at(value, self.depth, self.lax)),
704        )
705    }
706
707    fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value>
708    where
709        V: Visitor<'de>,
710    {
711        match self.payload {
712            Some(Value::Array(values)) => {
713                visit_array(values, guard_descent(self.depth)?, self.lax, visitor)
714            }
715            Some(other) => Err(de::Error::invalid_type(
716                unexpected_value(&other),
717                &"tuple variant",
718            )),
719            None => Err(de::Error::invalid_type(
720                Unexpected::UnitVariant,
721                &"tuple variant",
722            )),
723        }
724    }
725
726    fn struct_variant<V>(self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value>
727    where
728        V: Visitor<'de>,
729    {
730        match self.payload {
731            Some(Value::Dictionary(dict)) => {
732                visit_dictionary(dict, guard_descent(self.depth)?, self.lax, visitor)
733            }
734            Some(other) => Err(de::Error::invalid_type(
735                unexpected_value(&other),
736                &"struct variant",
737            )),
738            None => Err(de::Error::invalid_type(
739                Unexpected::UnitVariant,
740                &"struct variant",
741            )),
742        }
743    }
744}
745
746/// Replays a [`Date`] as its sentinel payload string inside
747/// `visit_newtype_struct`, so `deserialize_any` rejects every target that
748/// does not opt into the newtype callback — a date decodes only into a
749/// dedicated date type.
750struct DatePayloadDeserializer {
751    date: Date,
752}
753
754impl<'de> Deserializer<'de> for DatePayloadDeserializer {
755    type Error = Error;
756
757    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
758    where
759        V: Visitor<'de>,
760    {
761        visitor.visit_string(format_sentinel_date(self.date))
762    }
763
764    forward_to_deserialize_any! {
765        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes byte_buf
766        option unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier
767        ignored_any
768    }
769}
770
771/// Replays a [`Uid`] as its `u64` payload inside `visit_newtype_struct`;
772/// integer targets take the dedicated downgrade path instead.
773struct UidPayloadDeserializer {
774    uid: Uid,
775}
776
777impl<'de> Deserializer<'de> for UidPayloadDeserializer {
778    type Error = Error;
779
780    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
781    where
782        V: Visitor<'de>,
783    {
784        visitor.visit_u64(self.uid.get())
785    }
786
787    forward_to_deserialize_any! {
788        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes byte_buf
789        option unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier
790        ignored_any
791    }
792}
793
794struct ValueVisitor;
795
796impl<'de> Visitor<'de> for ValueVisitor {
797    type Value = Value;
798
799    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
800        formatter.write_str("any property-list value")
801    }
802
803    fn visit_bool<E>(self, value: bool) -> Result<Value, E> {
804        Ok(Value::Boolean(value))
805    }
806
807    fn visit_i64<E>(self, value: i64) -> Result<Value, E> {
808        Ok(Value::Integer(Integer::Signed(value)))
809    }
810
811    fn visit_u64<E>(self, value: u64) -> Result<Value, E> {
812        Ok(Value::Integer(Integer::Unsigned(value)))
813    }
814
815    fn visit_i128<E>(self, value: i128) -> Result<Value, E>
816    where
817        E: de::Error,
818    {
819        i64::try_from(value)
820            .map(|signed| Value::Integer(Integer::Signed(signed)))
821            .or_else(|_| {
822                u64::try_from(value).map(|unsigned| Value::Integer(Integer::Unsigned(unsigned)))
823            })
824            .map_err(|_| E::custom("integer does not fit the 64-bit property-list range"))
825    }
826
827    fn visit_u128<E>(self, value: u128) -> Result<Value, E>
828    where
829        E: de::Error,
830    {
831        u64::try_from(value)
832            .map(|unsigned| Value::Integer(Integer::Unsigned(unsigned)))
833            .map_err(|_| E::custom("integer does not fit the 64-bit property-list range"))
834    }
835
836    fn visit_f32<E>(self, value: f32) -> Result<Value, E> {
837        Ok(Value::Real(Real::from(value)))
838    }
839
840    fn visit_f64<E>(self, value: f64) -> Result<Value, E> {
841        Ok(Value::Real(Real::from(value)))
842    }
843
844    fn visit_char<E>(self, value: char) -> Result<Value, E> {
845        Ok(Value::String(value.to_string()))
846    }
847
848    fn visit_str<E>(self, value: &str) -> Result<Value, E> {
849        Ok(Value::String(value.to_owned()))
850    }
851
852    fn visit_string<E>(self, value: String) -> Result<Value, E> {
853        Ok(Value::String(value))
854    }
855
856    fn visit_bytes<E>(self, value: &[u8]) -> Result<Value, E> {
857        Ok(Value::Data(value.to_vec()))
858    }
859
860    fn visit_byte_buf<E>(self, value: Vec<u8>) -> Result<Value, E> {
861        Ok(Value::Data(value))
862    }
863
864    fn visit_some<D>(self, deserializer: D) -> Result<Value, D::Error>
865    where
866        D: Deserializer<'de>,
867    {
868        Value::deserialize(deserializer)
869    }
870
871    fn visit_seq<A>(self, mut seq: A) -> Result<Value, A::Error>
872    where
873        A: SeqAccess<'de>,
874    {
875        let mut values = Vec::new();
876        while let Some(element) = seq.next_element()? {
877            values.push(element);
878        }
879        Ok(Value::Array(values))
880    }
881
882    fn visit_map<A>(self, mut map: A) -> Result<Value, A::Error>
883    where
884        A: MapAccess<'de>,
885    {
886        let mut dict = Dictionary::new();
887        while let Some((key, value)) = map.next_entry::<String, Self::Value>()? {
888            drop(dict.insert(key, value));
889        }
890        Ok(Value::Dictionary(dict))
891    }
892
893    /// The sentinel probe: only [`Uid`] (`u64` payload) and [`Date`]
894    /// (RFC 3339 string payload) arrive through the newtype callback, so the
895    /// payload type disambiguates and `Value` round-trips losslessly.
896    fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Value, D::Error>
897    where
898        D: Deserializer<'de>,
899    {
900        match Value::deserialize(deserializer)? {
901            Value::Integer(integer) => integer.as_unsigned().map_or_else(
902                || {
903                    Err(de::Error::custom(
904                        "uid sentinel payload must be an unsigned integer",
905                    ))
906                },
907                |uid| Ok(Value::Uid(Uid::from(uid))),
908            ),
909            Value::String(payload) => {
910                parse_sentinel_date(&payload)
911                    .map(Value::Date)
912                    .ok_or_else(|| {
913                        de::Error::invalid_value(
914                            Unexpected::Str(&payload),
915                            &"an rfc 3339 date sentinel payload",
916                        )
917                    })
918            }
919            other => Err(de::Error::invalid_type(
920                unexpected_value(&other),
921                &"a UID or date sentinel payload",
922            )),
923        }
924    }
925}
926
927impl<'de> Deserialize<'de> for Value {
928    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
929    where
930        D: Deserializer<'de>,
931    {
932        deserializer.deserialize_any(ValueVisitor)
933    }
934}
935
936struct IntegerVisitor;
937
938impl Visitor<'_> for IntegerVisitor {
939    type Value = Integer;
940
941    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
942        formatter.write_str("a property-list integer")
943    }
944
945    fn visit_i64<E>(self, value: i64) -> Result<Integer, E> {
946        Ok(Integer::Signed(value))
947    }
948
949    fn visit_u64<E>(self, value: u64) -> Result<Integer, E> {
950        Ok(Integer::Unsigned(value))
951    }
952
953    fn visit_i128<E>(self, value: i128) -> Result<Integer, E>
954    where
955        E: de::Error,
956    {
957        i64::try_from(value)
958            .map(Integer::Signed)
959            .or_else(|_| u64::try_from(value).map(Integer::Unsigned))
960            .map_err(|_| E::custom("integer does not fit the 64-bit property-list range"))
961    }
962
963    fn visit_u128<E>(self, value: u128) -> Result<Integer, E>
964    where
965        E: de::Error,
966    {
967        u64::try_from(value)
968            .map(Integer::Unsigned)
969            .map_err(|_| E::custom("integer does not fit the 64-bit property-list range"))
970    }
971}
972
973impl<'de> Deserialize<'de> for Integer {
974    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
975    where
976        D: Deserializer<'de>,
977    {
978        deserializer.deserialize_any(IntegerVisitor)
979    }
980}
981
982struct RealVisitor;
983
984impl Visitor<'_> for RealVisitor {
985    type Value = Real;
986
987    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
988        formatter.write_str("a property-list real")
989    }
990
991    fn visit_f32<E>(self, value: f32) -> Result<Real, E> {
992        Ok(Real::from(value))
993    }
994
995    fn visit_f64<E>(self, value: f64) -> Result<Real, E> {
996        Ok(Real::from(value))
997    }
998}
999
1000impl<'de> Deserialize<'de> for Real {
1001    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1002    where
1003        D: Deserializer<'de>,
1004    {
1005        deserializer.deserialize_any(RealVisitor)
1006    }
1007}
1008
1009struct UidVisitor;
1010
1011impl<'de> Visitor<'de> for UidVisitor {
1012    type Value = Uid;
1013
1014    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1015        formatter.write_str("an unsigned integer UID")
1016    }
1017
1018    fn visit_u64<E>(self, value: u64) -> Result<Uid, E> {
1019        Ok(Uid::from(value))
1020    }
1021
1022    fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Uid, D::Error>
1023    where
1024        D: Deserializer<'de>,
1025    {
1026        deserializer.deserialize_u64(self)
1027    }
1028}
1029
1030impl<'de> Deserialize<'de> for Uid {
1031    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1032    where
1033        D: Deserializer<'de>,
1034    {
1035        deserializer.deserialize_newtype_struct(UID_NEWTYPE, UidVisitor)
1036    }
1037}
1038
1039struct DateVisitor;
1040
1041impl<'de> Visitor<'de> for DateVisitor {
1042    type Value = Date;
1043
1044    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1045        formatter.write_str("an rfc 3339 date string")
1046    }
1047
1048    fn visit_str<E>(self, value: &str) -> Result<Date, E>
1049    where
1050        E: de::Error,
1051    {
1052        parse_sentinel_date(value).ok_or_else(|| E::invalid_value(Unexpected::Str(value), &self))
1053    }
1054
1055    fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Date, D::Error>
1056    where
1057        D: Deserializer<'de>,
1058    {
1059        deserializer.deserialize_str(self)
1060    }
1061}
1062
1063impl<'de> Deserialize<'de> for Date {
1064    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1065    where
1066        D: Deserializer<'de>,
1067    {
1068        deserializer.deserialize_newtype_struct(DATE_NEWTYPE, DateVisitor)
1069    }
1070}
1071
1072#[cfg(test)]
1073mod tests {
1074    #![expect(
1075        clippy::unwrap_used,
1076        clippy::panic,
1077        reason = "test code: unwrap/panic are the assertions"
1078    )]
1079
1080    use serde::{Deserialize, Serialize};
1081
1082    use super::*;
1083    use crate::value::ser::to_value;
1084
1085    fn dict<const N: usize>(entries: [(&str, Value); N]) -> Value {
1086        entries
1087            .into_iter()
1088            .map(|(key, value)| (key.to_owned(), value))
1089            .collect()
1090    }
1091
1092    fn rfc(s: &str) -> Date {
1093        Date::parse_rfc3339(s).unwrap()
1094    }
1095
1096    fn lax<T: DeserializeOwned>(value: Value) -> Result<T> {
1097        T::deserialize(ValueDeserializer::new(value, true))
1098    }
1099
1100    fn nested_arrays(containers: usize) -> Value {
1101        let mut value = Value::Array(Vec::new());
1102        for _ in 1..containers {
1103            value = Value::Array(vec![value]);
1104        }
1105        value
1106    }
1107
1108    #[test]
1109    fn derived_struct_round_trips_with_attributes() {
1110        #[derive(Serialize, Deserialize, PartialEq, Debug, Default)]
1111        struct Inner {
1112            count: u32,
1113        }
1114
1115        #[derive(Serialize, Deserialize, PartialEq, Debug)]
1116        struct Pet {
1117            #[serde(rename = "Name")]
1118            name: String,
1119            #[serde(skip)]
1120            mood: u8,
1121            legs: Option<u32>,
1122            #[serde(default)]
1123            tag: String,
1124            nested: Inner,
1125        }
1126
1127        let pet = Pet {
1128            name: "Fido".to_owned(),
1129            mood: 0,
1130            legs: Some(4),
1131            tag: String::new(),
1132            nested: Inner { count: 2 },
1133        };
1134        let value = to_value(&pet).unwrap();
1135        assert_eq!(
1136            value,
1137            dict([
1138                ("Name", Value::from("Fido")),
1139                ("legs", Value::from(4u32)),
1140                ("nested", dict([("count", Value::from(2u32))])),
1141                ("tag", Value::from("")),
1142            ])
1143        );
1144        assert_eq!(from_value::<Pet>(value).unwrap(), pet);
1145
1146        // Option and default fields tolerate absence; mood is skipped entirely.
1147        let sparse = dict([
1148            ("Name", Value::from("Rex")),
1149            ("nested", dict([("count", Value::from(0u32))])),
1150        ]);
1151        assert_eq!(
1152            from_value::<Pet>(sparse).unwrap(),
1153            Pet {
1154                name: "Rex".to_owned(),
1155                mood: 0,
1156                legs: None,
1157                tag: String::new(),
1158                nested: Inner { count: 0 },
1159            }
1160        );
1161    }
1162
1163    #[test]
1164    fn missing_keys_error_without_option_or_default() {
1165        #[derive(Deserialize, Debug)]
1166        struct Strict {
1167            #[expect(dead_code, reason = "field exists only to be required")]
1168            required: i64,
1169        }
1170        assert!(from_value::<Strict>(dict([])).is_err());
1171        assert!(from_value::<Strict>(dict([("required", Value::from(1u8))])).is_ok());
1172    }
1173
1174    #[test]
1175    fn extra_keys_are_ignored_even_when_they_hold_dates() {
1176        #[derive(Deserialize, PartialEq, Debug)]
1177        struct Small {
1178            x: i64,
1179        }
1180        let value = dict([
1181            ("ignored", Value::Date(rfc("2013-11-27T00:34:00Z"))),
1182            ("uid_too", Value::Uid(Uid::from(3))),
1183            ("x", Value::from(1u8)),
1184        ]);
1185        assert_eq!(from_value::<Small>(value).unwrap(), Small { x: 1 });
1186
1187        let ignored = de::IgnoredAny::deserialize(ValueDeserializer::new(
1188            Value::Date(rfc("2013-11-27T00:34:00Z")),
1189            false,
1190        ));
1191        assert!(ignored.is_ok());
1192    }
1193
1194    #[test]
1195    fn flatten_round_trips_and_collisions_keep_the_last_writer() {
1196        #[derive(Serialize, Deserialize, PartialEq, Debug)]
1197        struct Outer {
1198            a: u8,
1199            #[serde(flatten)]
1200            rest: BTreeMap<String, u8>,
1201        }
1202
1203        let outer = Outer {
1204            a: 1,
1205            rest: BTreeMap::from([("b".to_owned(), 2u8)]),
1206        };
1207        let value = to_value(&outer).unwrap();
1208        assert_eq!(
1209            value,
1210            dict([("a", Value::from(1u8)), ("b", Value::from(2u8))])
1211        );
1212        assert_eq!(from_value::<Outer>(value).unwrap(), outer);
1213
1214        // Collision: the flattened map's "a" overwrites the field on encode,
1215        // and the field captures it back on decode.
1216        let colliding = Outer {
1217            a: 1,
1218            rest: BTreeMap::from([("a".to_owned(), 9u8)]),
1219        };
1220        let wire = to_value(&colliding).unwrap();
1221        assert_eq!(wire, dict([("a", Value::from(9u8))]));
1222        assert_eq!(
1223            from_value::<Outer>(wire).unwrap(),
1224            Outer {
1225                a: 9,
1226                rest: BTreeMap::new(),
1227            }
1228        );
1229    }
1230
1231    #[test]
1232    fn illegal_strict_decodes_error() {
1233        // Strict decode rejects every cross-kind coercion.
1234        assert!(from_value::<i64>(Value::from("abc")).is_err());
1235        assert!(from_value::<i64>(Value::Data(vec![0, 16, 4])).is_err());
1236        assert!(from_value::<i64>(Value::from(34.1)).is_err());
1237        assert!(from_value::<i64>(Value::from(true)).is_err());
1238        assert!(from_value::<i64>(Value::Date(rfc("2010-01-01T00:00:00Z"))).is_err());
1239        assert!(from_value::<bool>(Value::from(0u8)).is_err());
1240        assert!(from_value::<bool>(Value::from(vec![Value::from(0u8)])).is_err());
1241        assert!(from_value::<bool>(dict([("a", Value::from(0u8))])).is_err());
1242        assert!(
1243            from_value::<[i32; 1]>(Value::from(vec![
1244                Value::from(true),
1245                Value::from(true),
1246                Value::from(true),
1247            ]))
1248            .is_err()
1249        );
1250        assert!(from_value::<[u8; 3]>(Value::Data(b"Hello".to_vec())).is_err());
1251    }
1252
1253    #[test]
1254    fn integers_never_coerce_to_floats_but_reals_downcast() {
1255        assert!(matches!(
1256            from_value::<f64>(Value::from(5u8)),
1257            Err(Error::TypeMismatch {
1258                expected: "f64",
1259                found: "integer",
1260            })
1261        ));
1262        assert!(from_value::<f32>(Value::from(-5i64)).is_err());
1263
1264        let downcast = from_value::<f32>(Value::from(34.1)).unwrap();
1265        assert!((f64::from(downcast) - 34.1).abs() < 1e-4);
1266        let narrow = from_value::<f32>(Value::Real(Real::from(1.5f32))).unwrap();
1267        assert!((narrow - 1.5).abs() < f32::EPSILON);
1268    }
1269
1270    #[test]
1271    fn data_decodes_into_byte_shapes_but_never_strings() {
1272        assert_eq!(
1273            from_value::<Vec<u8>>(Value::Data(b"Hello".to_vec())).unwrap(),
1274            b"Hello".to_vec()
1275        );
1276        assert_eq!(
1277            from_value::<[u8; 5]>(Value::Data(b"Hello".to_vec())).unwrap(),
1278            *b"Hello"
1279        );
1280        assert!(from_value::<[u8; 8]>(Value::Data(b"Hello".to_vec())).is_err());
1281        assert!(from_value::<String>(Value::Data(b"Hello".to_vec())).is_err());
1282        assert!(lax::<String>(Value::Data(b"Hello".to_vec())).is_err());
1283
1284        // Arrays of integers decode element-wise into byte targets.
1285        let array = Value::from(vec![Value::from(1u8), Value::from(2u8)]);
1286        assert_eq!(from_value::<Vec<u8>>(array.clone()).unwrap(), vec![1, 2]);
1287        assert_eq!(from_value::<[u8; 2]>(array).unwrap(), [1, 2]);
1288        let too_big = Value::from(vec![Value::from(256u16)]);
1289        assert!(from_value::<Vec<u8>>(too_big).is_err());
1290
1291        // Strings never become bytes, in either mode.
1292        assert!(from_value::<Vec<u8>>(Value::from("jkl")).is_err());
1293        assert!(lax::<Vec<u8>>(Value::from("jkl")).is_err());
1294    }
1295
1296    #[test]
1297    fn date_sources_decode_only_into_dates_and_values() {
1298        let date = rfc("2013-11-27T00:34:00.5Z");
1299        let value = Value::Date(date);
1300        assert_eq!(from_value::<Date>(value.clone()).unwrap(), date);
1301        assert_eq!(from_value::<Value>(value.clone()).unwrap(), value);
1302
1303        assert!(from_value::<String>(value.clone()).is_err());
1304        assert!(from_value::<u64>(value.clone()).is_err());
1305        assert!(from_value::<f64>(value.clone()).is_err());
1306        assert!(from_value::<BTreeMap<String, Value>>(value.clone()).is_err());
1307        assert!(from_value::<Vec<Value>>(value).is_err());
1308
1309        // A plist string never decodes into Date in strict mode.
1310        assert!(from_value::<Date>(Value::from("2013-11-27T00:34:00Z")).is_err());
1311
1312        let ancient = Date::from_apple_epoch(-1e300);
1313        assert_eq!(
1314            from_value::<Value>(Value::Date(ancient)).unwrap(),
1315            Value::Date(ancient)
1316        );
1317    }
1318
1319    #[test]
1320    fn uid_sources_downgrade_into_integers_but_not_strings_or_floats() {
1321        let value = Value::Uid(Uid::from(1024));
1322        assert_eq!(from_value::<Uid>(value.clone()).unwrap(), Uid::from(1024));
1323        assert_eq!(from_value::<u64>(value.clone()).unwrap(), 1024);
1324        assert_eq!(from_value::<i64>(value.clone()).unwrap(), 1024);
1325        assert_eq!(from_value::<Value>(value.clone()).unwrap(), value);
1326        assert!(from_value::<String>(value.clone()).is_err());
1327        assert!(from_value::<f64>(value).is_err());
1328
1329        // Narrow integer targets are range-checked, not wrapped.
1330        assert!(from_value::<u8>(Value::Uid(Uid::from(1024))).is_err());
1331        assert!(from_value::<i64>(Value::Uid(Uid::from(u64::MAX))).is_err());
1332    }
1333
1334    #[test]
1335    fn integers_and_lax_strings_decode_into_uid_targets() {
1336        assert_eq!(
1337            from_value::<Uid>(Value::from(1024u64)).unwrap(),
1338            Uid::from(1024)
1339        );
1340        assert_eq!(
1341            from_value::<Uid>(Value::from(1024i64)).unwrap(),
1342            Uid::from(1024)
1343        );
1344        assert!(from_value::<Uid>(Value::from(-1i64)).is_err());
1345        assert!(from_value::<Uid>(Value::from("12")).is_err());
1346        assert_eq!(lax::<Uid>(Value::from("12")).unwrap(), Uid::from(12));
1347        assert!(lax::<Uid>(Value::from("+5")).is_err());
1348        assert!(from_value::<Uid>(Value::from(1.5)).is_err());
1349    }
1350
1351    #[test]
1352    fn integer_narrowing_is_range_checked() {
1353        assert!(from_value::<i64>(Value::from(u64::MAX)).is_err());
1354        assert!(from_value::<i8>(Value::from(300u16)).is_err());
1355        assert!(from_value::<u64>(Value::from(-1i8)).is_err());
1356        assert_eq!(from_value::<i64>(Value::from(5u64)).unwrap(), 5);
1357        assert_eq!(from_value::<u64>(Value::from(5i64)).unwrap(), 5);
1358        assert_eq!(from_value::<i8>(Value::from(-128i64)).unwrap(), i8::MIN);
1359    }
1360
1361    #[test]
1362    fn int128_targets_fit_or_error() {
1363        assert_eq!(
1364            from_value::<i128>(Value::from(u64::MAX)).unwrap(),
1365            i128::from(u64::MAX)
1366        );
1367        assert_eq!(from_value::<u128>(Value::from(7u8)).unwrap(), 7);
1368        assert!(from_value::<u128>(Value::from(-1i64)).is_err());
1369        assert_eq!(from_value::<i128>(Value::from(-1i64)).unwrap(), -1);
1370    }
1371
1372    #[test]
1373    fn value_round_trip_is_lossless_for_every_variant() {
1374        let tree = dict([
1375            (
1376                "array",
1377                Value::from(vec![
1378                    Value::from(-1i64),
1379                    Value::from(u64::MAX),
1380                    dict([("inner", Value::from(false))]),
1381                ]),
1382            ),
1383            ("bool", Value::from(true)),
1384            ("data", Value::Data(vec![1, 2, 3])),
1385            ("date", Value::Date(rfc("2013-11-27T00:34:00.123456789Z"))),
1386            ("narrow", Value::Real(Real::from(32.5f32))),
1387            ("string", Value::from("hello")),
1388            ("uid", Value::Uid(Uid::from(u64::MAX))),
1389            ("wide", Value::from(1.5)),
1390        ]);
1391        let round_tripped = from_value::<Value>(tree.clone()).unwrap();
1392        assert_eq!(round_tripped, tree);
1393
1394        // The narrow flag survives the generic round trip: a narrow real
1395        // stays a 32-bit-width real.
1396        match round_tripped.as_dictionary().and_then(|d| d.get("narrow")) {
1397            Some(Value::Real(real)) => assert!(!real.wide()),
1398            other => panic!("expected a real, got {other:?}"),
1399        }
1400        match round_tripped.as_dictionary().and_then(|d| d.get("wide")) {
1401            Some(Value::Real(real)) => assert!(real.wide()),
1402            other => panic!("expected a real, got {other:?}"),
1403        }
1404    }
1405
1406    #[test]
1407    fn depth_guard_caps_container_nesting_at_128() {
1408        assert!(from_value::<Value>(nested_arrays(128)).is_ok());
1409        assert!(matches!(
1410            from_value::<Value>(nested_arrays(129)),
1411            Err(Error::MaxDepthExceeded)
1412        ));
1413        // A leaf inside the deepest allowed container still decodes.
1414        let mut leafy = Value::from(vec![Value::from(1u8)]);
1415        for _ in 1..128 {
1416            leafy = Value::from(vec![leafy]);
1417        }
1418        assert!(from_value::<Value>(leafy).is_ok());
1419        // Hostile depth fails fast instead of overflowing the stack.
1420        assert!(matches!(
1421            from_value::<Value>(nested_arrays(2000)),
1422            Err(Error::MaxDepthExceeded)
1423        ));
1424    }
1425
1426    #[test]
1427    fn lax_decodes_the_lax_fixture() {
1428        // Lax decode fixture: every scalar arrives as a string from the
1429        // OpenStep parser.
1430        #[derive(Deserialize, PartialEq, Debug)]
1431        #[serde(rename_all = "UPPERCASE")]
1432        struct LaxTestData {
1433            i64: i64,
1434            u64: u64,
1435            f64: f64,
1436            b: bool,
1437            d: Date,
1438        }
1439
1440        let value = dict([
1441            ("B", Value::from("1")),
1442            ("D", Value::from("2013-11-27 00:34:00 +0000")),
1443            ("F64", Value::from("3.0")),
1444            ("I64", Value::from("1")),
1445            ("U64", Value::from("2")),
1446        ]);
1447        assert_eq!(
1448            lax::<LaxTestData>(value).unwrap(),
1449            LaxTestData {
1450                i64: 1,
1451                u64: 2,
1452                f64: 3.0,
1453                b: true,
1454                d: rfc("2013-11-27T00:34:00Z"),
1455            }
1456        );
1457    }
1458
1459    #[test]
1460    fn illegal_lax_decodes_error() {
1461        // Lax decode still rejects unparseable scalar strings.
1462        assert!(lax::<i64>(Value::from("abc")).is_err());
1463        assert!(lax::<u64>(Value::from("abc")).is_err());
1464        assert!(lax::<f64>(Value::from("def")).is_err());
1465        assert!(lax::<bool>(Value::from("ghi")).is_err());
1466        assert!(lax::<Vec<u8>>(Value::from("jkl")).is_err());
1467    }
1468
1469    #[test]
1470    fn lax_bool_accepts_exactly_the_twelve_parse_bool_tokens() {
1471        for token in ["1", "t", "T", "TRUE", "true", "True"] {
1472            assert!(lax::<bool>(Value::from(token)).unwrap(), "{token}");
1473        }
1474        for token in ["0", "f", "F", "FALSE", "false", "False"] {
1475            assert!(!lax::<bool>(Value::from(token)).unwrap(), "{token}");
1476        }
1477        for token in ["yes", "2", "TrUe", ""] {
1478            assert!(lax::<bool>(Value::from(token)).is_err(), "{token}");
1479        }
1480    }
1481
1482    #[test]
1483    fn lax_integers_follow_sign_and_base_rules() {
1484        assert_eq!(lax::<i64>(Value::from("+5")).unwrap(), 5);
1485        assert_eq!(lax::<i64>(Value::from("-5")).unwrap(), -5);
1486        assert!(lax::<u64>(Value::from("+5")).is_err());
1487        assert!(lax::<u64>(Value::from("-5")).is_err());
1488        assert_eq!(lax::<u64>(Value::from("5")).unwrap(), 5);
1489        // Base 10 only: no hex sniffing in lax mode.
1490        assert!(lax::<i64>(Value::from("0x10")).is_err());
1491        assert!(lax::<u64>(Value::from("0x10")).is_err());
1492        assert!(lax::<i64>(Value::from("5_0")).is_err());
1493        // Parsed at 64 bits, then range-checked into the narrow target.
1494        assert!(lax::<i8>(Value::from("300")).is_err());
1495    }
1496
1497    #[test]
1498    fn lax_floats_follow_c_style_parse() {
1499        assert!((lax::<f64>(Value::from("3.0")).unwrap() - 3.0).abs() < f64::EPSILON);
1500        assert!((lax::<f64>(Value::from("1e3")).unwrap() - 1000.0).abs() < f64::EPSILON);
1501        assert!(lax::<f64>(Value::from("-Inf")).unwrap().is_infinite());
1502        assert!(lax::<f64>(Value::from("nan")).unwrap().is_nan());
1503        assert!(lax::<f64>(Value::from("1e999")).is_err());
1504        // Via the shared helper: C-style hex floats and digit-group
1505        // underscores parse.
1506        assert!((lax::<f64>(Value::from("0x1p-2")).unwrap() - 0.25).abs() < f64::EPSILON);
1507        assert!((lax::<f64>(Value::from("1_000.5")).unwrap() - 1000.5).abs() < f64::EPSILON);
1508    }
1509
1510    #[test]
1511    fn lax_dates_use_the_text_layout_only() {
1512        assert_eq!(
1513            lax::<Date>(Value::from("2013-11-27 00:34:00 +0000")).unwrap(),
1514            rfc("2013-11-27T00:34:00Z")
1515        );
1516        // Offsets convert to UTC.
1517        assert_eq!(
1518            lax::<Date>(Value::from("2013-11-27 00:34:00 -0500")).unwrap(),
1519            rfc("2013-11-27T05:34:00Z")
1520        );
1521        assert!(matches!(
1522            lax::<Date>(Value::from("2013-11-27T00:34:00Z")),
1523            Err(Error::ParseScalar(_))
1524        ));
1525        assert!(lax::<Date>(Value::from("not a date")).is_err());
1526    }
1527
1528    #[test]
1529    fn lax_never_applies_inside_deserialize_any() {
1530        assert_eq!(lax::<Value>(Value::from("1")).unwrap(), Value::from("1"));
1531        let map = lax::<BTreeMap<String, Value>>(dict([("B", Value::from("1"))])).unwrap();
1532        assert_eq!(map.get("B"), Some(&Value::from("1")));
1533    }
1534
1535    #[test]
1536    fn public_from_value_is_always_strict() {
1537        assert!(from_value::<bool>(Value::from("1")).is_err());
1538        assert!(from_value::<i64>(Value::from("1")).is_err());
1539        assert!(from_value::<Date>(Value::from("2013-11-27 00:34:00 +0000")).is_err());
1540    }
1541
1542    #[test]
1543    fn enums_round_trip_their_external_tagging() {
1544        #[derive(Serialize, Deserialize, PartialEq, Debug)]
1545        enum Repr {
1546            Unit,
1547            New(u8),
1548            Tuple(u8, u8),
1549            Struct { f: bool },
1550        }
1551
1552        for variant in [
1553            Repr::Unit,
1554            Repr::New(1),
1555            Repr::Tuple(1, 2),
1556            Repr::Struct { f: true },
1557        ] {
1558            let value = to_value(&variant).unwrap();
1559            assert_eq!(from_value::<Repr>(value).unwrap(), variant);
1560        }
1561
1562        assert_eq!(from_value::<Repr>(Value::from("Unit")).unwrap(), Repr::Unit);
1563        assert_eq!(
1564            from_value::<Repr>(dict([("New", Value::from(1u8))])).unwrap(),
1565            Repr::New(1)
1566        );
1567
1568        // Shape violations.
1569        assert!(matches!(
1570            from_value::<Repr>(dict([
1571                ("New", Value::from(1u8)),
1572                ("Unit", Value::from(2u8)),
1573            ])),
1574            Err(Error::Message(_))
1575        ));
1576        assert!(from_value::<Repr>(dict([])).is_err());
1577        assert!(from_value::<Repr>(Value::from("New")).is_err());
1578        assert!(from_value::<Repr>(dict([("Unit", Value::from(1u8))])).is_err());
1579        assert!(from_value::<Repr>(Value::from("Bogus")).is_err());
1580        assert!(from_value::<Repr>(Value::from(1u8)).is_err());
1581    }
1582
1583    #[test]
1584    fn map_key_targets_must_be_string_shaped() {
1585        #[derive(Deserialize, PartialEq, Eq, PartialOrd, Ord, Debug)]
1586        struct SortaString(String);
1587
1588        let value = dict([("1", Value::from("first")), ("2", Value::from("second"))]);
1589        assert!(from_value::<BTreeMap<u32, String>>(value.clone()).is_err());
1590        // Keys never lax-coerce: map keys are converted, not parsed.
1591        assert!(lax::<BTreeMap<u32, String>>(value.clone()).is_err());
1592
1593        let aliased = from_value::<BTreeMap<SortaString, String>>(value).unwrap();
1594        assert_eq!(
1595            aliased.get(&SortaString("1".to_owned())),
1596            Some(&"first".to_owned())
1597        );
1598    }
1599
1600    #[test]
1601    fn fixed_arity_targets_reject_leftover_elements() {
1602        let three = Value::from(vec![Value::from(1u8), Value::from(2u8), Value::from(3u8)]);
1603        assert!(from_value::<(u8, u8)>(three.clone()).is_err());
1604        assert_eq!(from_value::<(u8, u8, u8)>(three).unwrap(), (1, 2, 3));
1605        assert!(from_value::<(u8, u8)>(Value::from(vec![Value::from(1u8)])).is_err());
1606    }
1607
1608    #[test]
1609    fn chars_demand_one_character_strings() {
1610        assert_eq!(from_value::<char>(Value::from("a")).unwrap(), 'a');
1611        assert_eq!(from_value::<char>(to_value(&'£').unwrap()).unwrap(), '£');
1612        assert!(from_value::<char>(Value::from("ab")).is_err());
1613        assert!(from_value::<char>(Value::from("")).is_err());
1614        assert!(from_value::<char>(Value::from(65u8)).is_err());
1615    }
1616
1617    #[test]
1618    fn borrowing_targets_fail_with_an_owned_tree() {
1619        let result = <&str>::deserialize(ValueDeserializer::new(Value::from("x"), false));
1620        assert!(result.is_err());
1621    }
1622
1623    #[test]
1624    fn options_wrap_present_values() {
1625        assert_eq!(
1626            from_value::<Option<i64>>(Value::from(5i64)).unwrap(),
1627            Some(5)
1628        );
1629        assert_eq!(
1630            from_value::<Option<Vec<u8>>>(Value::Data(vec![1])).unwrap(),
1631            Some(vec![1])
1632        );
1633    }
1634
1635    #[test]
1636    fn unit_targets_always_mismatch() {
1637        #[derive(Deserialize, Debug)]
1638        struct UnitStruct;
1639        // A braced empty struct accepts any dictionary.
1640        #[derive(Deserialize, Debug)]
1641        struct Empty {}
1642
1643        assert!(from_value::<()>(dict([])).is_err());
1644        assert!(from_value::<UnitStruct>(dict([])).is_err());
1645        assert!(from_value::<Empty>(dict([("x", Value::from(1u8))])).is_ok());
1646        assert!(from_value::<Empty>(Value::from(1u8)).is_err());
1647    }
1648
1649    #[test]
1650    fn special_types_round_trip_inside_derived_structs() {
1651        #[derive(Serialize, Deserialize, PartialEq, Debug)]
1652        struct Archive {
1653            stamp: Date,
1654            reference: Uid,
1655        }
1656
1657        let archive = Archive {
1658            stamp: rfc("2013-11-27T00:34:00.25Z"),
1659            reference: Uid::from(42),
1660        };
1661        let value = to_value(&archive).unwrap();
1662        assert_eq!(
1663            value,
1664            dict([
1665                ("reference", Value::Uid(Uid::from(42))),
1666                ("stamp", Value::Date(rfc("2013-11-27T00:34:00.25Z"))),
1667            ])
1668        );
1669        assert_eq!(from_value::<Archive>(value).unwrap(), archive);
1670    }
1671
1672    #[test]
1673    fn integer_and_real_deserialize_from_their_values() {
1674        assert_eq!(
1675            from_value::<Integer>(Value::from(-1i64)).unwrap(),
1676            Integer::Signed(-1)
1677        );
1678        assert_eq!(
1679            from_value::<Integer>(Value::from(u64::MAX)).unwrap(),
1680            Integer::Unsigned(u64::MAX)
1681        );
1682        assert!(from_value::<Integer>(Value::from(1.5)).is_err());
1683
1684        let narrow = from_value::<Real>(Value::Real(Real::from(1.5f32))).unwrap();
1685        assert!(!narrow.wide());
1686        let wide = from_value::<Real>(Value::from(1.5)).unwrap();
1687        assert!(wide.wide());
1688        assert!(from_value::<Real>(Value::from(1u8)).is_err());
1689    }
1690}