Skip to main content

facet_value/
deserialize.rs

1//! Deserialize from a `Value` into any type implementing `Facet`.
2//!
3//! This module provides the inverse of serialization: given a `Value`, you can
4//! deserialize it into any Rust type that implements `Facet`.
5//!
6//! # Example
7//!
8//! ```ignore
9//! use facet::Facet;
10//! use facet_value::{Value, from_value};
11//!
12//! #[derive(Debug, Facet, PartialEq)]
13//! struct Person {
14//!     name: String,
15//!     age: u32,
16//! }
17//!
18//! // Create a Value (could come from JSON, MessagePack, etc.)
19//! let value = facet_value::value!({
20//!     "name": "Alice",
21//!     "age": 30
22//! });
23//!
24//! // Deserialize into a typed struct
25//! let person: Person = from_value(value).unwrap();
26//! assert_eq!(person.name, "Alice");
27//! assert_eq!(person.age, 30);
28//! ```
29
30use alloc::format;
31use alloc::string::{String, ToString};
32use alloc::vec::Vec;
33
34use facet_core::{
35    Def, Facet, NumericType, PrimitiveType, Shape, StructKind, TextualType, Type, UserType, Variant,
36};
37use facet_reflect::{Partial, ReflectError};
38
39use crate::{VNumber, Value, ValueType};
40
41/// A segment in a deserialization path
42#[derive(Clone, Debug, PartialEq, Eq)]
43pub enum PathSegment {
44    /// A field name in a struct or map
45    Field(String),
46    /// A variant name in an enum
47    Variant(String),
48    /// An index in an array or list
49    Index(usize),
50}
51
52impl core::fmt::Display for PathSegment {
53    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
54        match self {
55            PathSegment::Field(name) => write!(f, ".{name}"),
56            PathSegment::Variant(name) => write!(f, "::{name}"),
57            PathSegment::Index(i) => write!(f, "[{i}]"),
58        }
59    }
60}
61
62/// Error type for Value deserialization.
63#[derive(Debug)]
64pub struct ValueError {
65    /// The specific kind of error
66    pub kind: ValueErrorKind,
67    /// Path through the source Value where the error occurred
68    pub source_path: Vec<PathSegment>,
69    /// Path through the target Shape where the error occurred
70    pub dest_path: Vec<PathSegment>,
71    /// The target Shape we were deserializing into (for diagnostics)
72    pub target_shape: Option<&'static Shape>,
73    /// The source Value we were deserializing from (for diagnostics)
74    pub source_value: Option<Value>,
75}
76
77impl core::fmt::Display for ValueError {
78    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
79        if self.source_path.is_empty() {
80            write!(f, "{}", self.kind)
81        } else {
82            write!(f, "at {}: {}", self.source_path_string(), self.kind)
83        }
84    }
85}
86
87impl ValueError {
88    /// Create a new ValueError with empty paths
89    pub const fn new(kind: ValueErrorKind) -> Self {
90        Self {
91            kind,
92            source_path: Vec::new(),
93            dest_path: Vec::new(),
94            target_shape: None,
95            source_value: None,
96        }
97    }
98
99    /// Set the target shape for diagnostics
100    pub const fn with_shape(mut self, shape: &'static Shape) -> Self {
101        self.target_shape = Some(shape);
102        self
103    }
104
105    /// Set the source value for diagnostics
106    pub fn with_value(mut self, value: Value) -> Self {
107        self.source_value = Some(value);
108        self
109    }
110
111    /// Add a path segment to both paths (prepends since we unwind from error site)
112    pub fn with_path(mut self, segment: PathSegment) -> Self {
113        self.source_path.insert(0, segment.clone());
114        self.dest_path.insert(0, segment);
115        self
116    }
117
118    /// Format the source path as a string
119    pub fn source_path_string(&self) -> String {
120        if self.source_path.is_empty() {
121            "<root>".into()
122        } else {
123            use core::fmt::Write;
124            let mut s = String::new();
125            for seg in &self.source_path {
126                let _ = write!(s, "{seg}");
127            }
128            s
129        }
130    }
131
132    /// Format the dest path as a string
133    pub fn dest_path_string(&self) -> String {
134        if self.dest_path.is_empty() {
135            "<root>".into()
136        } else {
137            use core::fmt::Write;
138            let mut s = String::new();
139            for seg in &self.dest_path {
140                let _ = write!(s, "{seg}");
141            }
142            s
143        }
144    }
145}
146
147#[cfg(feature = "std")]
148impl core::error::Error for ValueError {}
149
150/// Specific error kinds for Value deserialization.
151#[derive(Debug)]
152pub enum ValueErrorKind {
153    /// Type mismatch between Value and target type
154    TypeMismatch {
155        /// What the target type expected
156        expected: &'static str,
157        /// What the Value actually contained
158        got: ValueType,
159    },
160    /// A required field is missing from the object
161    MissingField {
162        /// The name of the missing field
163        field: &'static str,
164    },
165    /// An unknown field was encountered (when deny_unknown_fields is set)
166    UnknownField {
167        /// The unknown field name
168        field: String,
169    },
170    /// Number conversion failed (out of range)
171    NumberOutOfRange {
172        /// Description of the error
173        message: String,
174    },
175    /// Reflection error from facet-reflect
176    Reflect(ReflectError),
177    /// Unsupported type or feature
178    Unsupported {
179        /// Description of what's unsupported
180        message: String,
181    },
182}
183
184impl core::fmt::Display for ValueErrorKind {
185    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
186        match self {
187            ValueErrorKind::TypeMismatch { expected, got } => {
188                write!(f, "type mismatch: expected {expected}, got {got:?}")
189            }
190            ValueErrorKind::MissingField { field } => {
191                write!(f, "missing required field `{field}`")
192            }
193            ValueErrorKind::UnknownField { field } => {
194                write!(f, "unknown field `{field}`")
195            }
196            ValueErrorKind::NumberOutOfRange { message } => {
197                write!(f, "number out of range: {message}")
198            }
199            ValueErrorKind::Reflect(e) => write!(f, "reflection error: {e}"),
200            ValueErrorKind::Unsupported { message } => {
201                write!(f, "unsupported: {message}")
202            }
203        }
204    }
205}
206
207impl From<ReflectError> for ValueError {
208    fn from(err: ReflectError) -> Self {
209        ValueError::new(ValueErrorKind::Reflect(err))
210    }
211}
212
213/// Result type for Value deserialization.
214pub type Result<T> = core::result::Result<T, ValueError>;
215
216/// Deserialize a `Value` into any type implementing `Facet`.
217///
218/// This is the main entry point for converting a dynamic `Value` into a
219/// typed Rust value.
220///
221/// # Example
222///
223/// ```ignore
224/// use facet::Facet;
225/// use facet_value::{Value, from_value};
226///
227/// #[derive(Debug, Facet, PartialEq)]
228/// struct Point {
229///     x: i32,
230///     y: i32,
231/// }
232///
233/// let value = facet_value::value!({"x": 10, "y": 20});
234/// let point: Point = from_value(value).unwrap();
235/// assert_eq!(point, Point { x: 10, y: 20 });
236/// ```
237pub fn from_value<'facet, T: Facet<'facet>>(value: Value) -> Result<T> {
238    let partial = Partial::alloc::<T>().map_err(|e| {
239        ValueError::from(e)
240            .with_shape(T::SHAPE)
241            .with_value(value.clone())
242    })?;
243    let partial = deserialize_value_into(&value, partial)
244        .map_err(|e| e.with_shape(T::SHAPE).with_value(value.clone()))?;
245    let heap_value = partial.build().map_err(|e| {
246        ValueError::from(e)
247            .with_shape(T::SHAPE)
248            .with_value(value.clone())
249    })?;
250    heap_value.materialize().map_err(|e| {
251        ValueError::from(e)
252            .with_shape(T::SHAPE)
253            .with_value(value.clone())
254    })
255}
256
257/// Internal deserializer that reads from a Value and writes to a Partial.
258fn deserialize_value_into<'p>(value: &Value, partial: Partial<'p>) -> Result<Partial<'p>> {
259    let mut partial = partial;
260    let shape = partial.shape();
261
262    // Check for Option first (it's also an enum but needs special handling)
263    if matches!(&shape.def, Def::Option(_)) {
264        return deserialize_option(value, partial);
265    }
266
267    // Check for smart pointers
268    if matches!(&shape.def, Def::Pointer(_)) {
269        return deserialize_pointer(value, partial);
270    }
271
272    // Check for container-level proxy
273    #[cfg(feature = "alloc")]
274    if shape.proxy.is_some() {
275        let (partial_returned, has_proxy) = partial.begin_custom_deserialization_from_shape()?;
276        partial = partial_returned;
277        if has_proxy {
278            partial = deserialize_value_into(value, partial)?;
279            partial = partial.end()?;
280            return Ok(partial);
281        }
282    }
283
284    // Priority 1: Check for builder_shape (immutable collections like Bytes -> BytesMut)
285    if shape.builder_shape.is_some() {
286        partial = partial.begin_inner()?;
287        partial = deserialize_value_into(value, partial)?;
288        partial = partial.end()?;
289        return Ok(partial);
290    }
291
292    // Priority 2: Check for .inner (transparent wrappers like NonZero)
293    // Collections (List/Map/Set/Array) have .inner for variance but shouldn't use this path
294    if shape.inner.is_some()
295        && !matches!(
296            &shape.def,
297            Def::List(_) | Def::Map(_) | Def::Set(_) | Def::Array(_)
298        )
299    {
300        partial = partial.begin_inner()?;
301        partial = deserialize_value_into(value, partial)?;
302        partial = partial.end()?;
303        return Ok(partial);
304    }
305
306    // Priority 3: Check the Type for structs and enums
307    match &shape.ty {
308        Type::User(UserType::Struct(struct_def)) => {
309            if struct_def.kind == StructKind::Tuple {
310                return deserialize_tuple(value, partial);
311            }
312            return deserialize_struct(value, partial);
313        }
314        Type::User(UserType::Enum(_)) => return deserialize_enum(value, partial),
315        _ => {}
316    }
317
318    // Priority 4: Check Def for containers and special types
319    match &shape.def {
320        Def::Scalar => deserialize_scalar(value, partial),
321        Def::List(_) => deserialize_list(value, partial),
322        Def::Map(_) => deserialize_map(value, partial),
323        Def::Array(_) => deserialize_array(value, partial),
324        Def::Set(_) => deserialize_set(value, partial),
325        Def::DynamicValue(_) => {
326            // Target is a DynamicValue (like Value itself) - just clone
327            partial = partial.set(value.clone())?;
328            Ok(partial)
329        }
330        _ => Err(ValueError::new(ValueErrorKind::Unsupported {
331            message: format!("unsupported shape def: {:?}", shape.def),
332        })),
333    }
334}
335
336/// Deserialize a scalar value (primitives, strings).
337fn deserialize_scalar<'p>(value: &Value, partial: Partial<'p>) -> Result<Partial<'p>> {
338    let mut partial = partial;
339    let shape = partial.shape();
340
341    match value.value_type() {
342        ValueType::Null => {
343            partial = partial.set_default()?;
344            Ok(partial)
345        }
346        ValueType::Bool => {
347            let b = value.as_bool().unwrap();
348            partial = partial.set(b)?;
349            Ok(partial)
350        }
351        ValueType::Number => {
352            let num = value.as_number().unwrap();
353            // If target expects a string, stringify the number
354            // This is needed for formats like XML where type inference may produce
355            // numbers even when strings are expected
356            if shape.type_identifier == "String" {
357                let s = if let Some(i) = num.to_i64() {
358                    format!("{i}")
359                } else if let Some(u) = num.to_u64() {
360                    format!("{u}")
361                } else if let Some(f) = num.to_f64() {
362                    format!("{f}")
363                } else {
364                    return Err(ValueError::new(ValueErrorKind::TypeMismatch {
365                        expected: "String",
366                        got: ValueType::Number,
367                    }));
368                };
369                partial = partial.set(s)?;
370                Ok(partial)
371            } else {
372                set_number(num, partial, shape)
373            }
374        }
375        ValueType::String => {
376            let s = value.as_string().unwrap();
377            // Try parse_from_str first if the type supports it
378            if shape.vtable.has_parse() {
379                partial = partial.parse_from_str(s.as_str())?;
380            } else {
381                partial = partial.set(s.as_str().to_string())?;
382            }
383            Ok(partial)
384        }
385        ValueType::Bytes => {
386            let bytes = value.as_bytes().unwrap();
387            partial = partial.set(bytes.as_slice().to_vec())?;
388            Ok(partial)
389        }
390        other => Err(ValueError::new(ValueErrorKind::TypeMismatch {
391            expected: shape.type_identifier,
392            got: other,
393        })),
394    }
395}
396
397/// Set a numeric value with appropriate type conversion.
398fn set_number<'p>(num: &VNumber, partial: Partial<'p>, shape: &Shape) -> Result<Partial<'p>> {
399    use facet_core::{NumericType, PrimitiveType, ShapeLayout};
400
401    let mut partial = partial;
402    let size = match shape.layout {
403        ShapeLayout::Sized(layout) => layout.size(),
404        _ => {
405            return Err(ValueError::new(ValueErrorKind::Unsupported {
406                message: "unsized numeric type".into(),
407            }));
408        }
409    };
410
411    match &shape.ty {
412        Type::Primitive(PrimitiveType::Numeric(NumericType::Integer { signed: true })) => {
413            let val = num.to_i64().ok_or_else(|| {
414                ValueError::new(ValueErrorKind::NumberOutOfRange {
415                    message: "value cannot be represented as i64".into(),
416                })
417            })?;
418            // Check type_identifier to distinguish i64 from isize (both 8 bytes on 64-bit)
419            if shape.type_identifier == "isize" {
420                let v = isize::try_from(val).map_err(|_| {
421                    ValueError::new(ValueErrorKind::NumberOutOfRange {
422                        message: format!("{val} out of range for isize"),
423                    })
424                })?;
425                partial = partial.set(v)?;
426            } else {
427                match size {
428                    1 => {
429                        let v = i8::try_from(val).map_err(|_| {
430                            ValueError::new(ValueErrorKind::NumberOutOfRange {
431                                message: format!("{val} out of range for i8"),
432                            })
433                        })?;
434                        partial = partial.set(v)?;
435                    }
436                    2 => {
437                        let v = i16::try_from(val).map_err(|_| {
438                            ValueError::new(ValueErrorKind::NumberOutOfRange {
439                                message: format!("{val} out of range for i16"),
440                            })
441                        })?;
442                        partial = partial.set(v)?;
443                    }
444                    4 => {
445                        let v = i32::try_from(val).map_err(|_| {
446                            ValueError::new(ValueErrorKind::NumberOutOfRange {
447                                message: format!("{val} out of range for i32"),
448                            })
449                        })?;
450                        partial = partial.set(v)?;
451                    }
452                    8 => {
453                        partial = partial.set(val)?;
454                    }
455                    16 => {
456                        partial = partial.set(val as i128)?;
457                    }
458                    _ => {
459                        return Err(ValueError::new(ValueErrorKind::Unsupported {
460                            message: format!("unexpected integer size: {size}"),
461                        }));
462                    }
463                }
464            }
465        }
466        Type::Primitive(PrimitiveType::Numeric(NumericType::Integer { signed: false })) => {
467            let val = num.to_u64().ok_or_else(|| {
468                ValueError::new(ValueErrorKind::NumberOutOfRange {
469                    message: "value cannot be represented as u64".into(),
470                })
471            })?;
472            // Check type_identifier to distinguish u64 from usize (both 8 bytes on 64-bit)
473            if shape.type_identifier == "usize" {
474                let v = usize::try_from(val).map_err(|_| {
475                    ValueError::new(ValueErrorKind::NumberOutOfRange {
476                        message: format!("{val} out of range for usize"),
477                    })
478                })?;
479                partial = partial.set(v)?;
480            } else {
481                match size {
482                    1 => {
483                        let v = u8::try_from(val).map_err(|_| {
484                            ValueError::new(ValueErrorKind::NumberOutOfRange {
485                                message: format!("{val} out of range for u8"),
486                            })
487                        })?;
488                        partial = partial.set(v)?;
489                    }
490                    2 => {
491                        let v = u16::try_from(val).map_err(|_| {
492                            ValueError::new(ValueErrorKind::NumberOutOfRange {
493                                message: format!("{val} out of range for u16"),
494                            })
495                        })?;
496                        partial = partial.set(v)?;
497                    }
498                    4 => {
499                        let v = u32::try_from(val).map_err(|_| {
500                            ValueError::new(ValueErrorKind::NumberOutOfRange {
501                                message: format!("{val} out of range for u32"),
502                            })
503                        })?;
504                        partial = partial.set(v)?;
505                    }
506                    8 => {
507                        partial = partial.set(val)?;
508                    }
509                    16 => {
510                        partial = partial.set(val as u128)?;
511                    }
512                    _ => {
513                        return Err(ValueError::new(ValueErrorKind::Unsupported {
514                            message: format!("unexpected integer size: {size}"),
515                        }));
516                    }
517                }
518            }
519        }
520        Type::Primitive(PrimitiveType::Numeric(NumericType::Float)) => {
521            let val = num.to_f64_lossy();
522            match size {
523                4 => {
524                    partial = partial.set(val as f32)?;
525                }
526                8 => {
527                    partial = partial.set(val)?;
528                }
529                _ => {
530                    return Err(ValueError::new(ValueErrorKind::Unsupported {
531                        message: format!("unexpected float size: {size}"),
532                    }));
533                }
534            }
535        }
536        _ => {
537            return Err(ValueError::new(ValueErrorKind::TypeMismatch {
538                expected: shape.type_identifier,
539                got: ValueType::Number,
540            }));
541        }
542    }
543    Ok(partial)
544}
545
546/// Deserialize a struct from a Value::Object.
547fn deserialize_struct<'p>(value: &Value, partial: Partial<'p>) -> Result<Partial<'p>> {
548    let mut partial = partial;
549    let obj = value.as_object().ok_or_else(|| {
550        ValueError::new(ValueErrorKind::TypeMismatch {
551            expected: "object",
552            got: value.value_type(),
553        })
554    })?;
555
556    let struct_def = match &partial.shape().ty {
557        Type::User(UserType::Struct(s)) => s,
558        _ => {
559            return Err(ValueError::new(ValueErrorKind::Unsupported {
560                message: "expected struct type".into(),
561            }));
562        }
563    };
564
565    let deny_unknown_fields = partial.shape().has_deny_unknown_fields_attr();
566
567    // Check if we have any flattened fields
568    let has_flattened = struct_def.fields.iter().any(|f| f.is_flattened());
569
570    if has_flattened {
571        return deserialize_struct_with_flatten(obj, partial, struct_def, deny_unknown_fields);
572    }
573
574    // Track which fields we've set
575    let num_fields = struct_def.fields.len();
576    let mut fields_set = alloc::vec![false; num_fields];
577
578    // Process each key-value pair in the object
579    for (key, val) in obj.iter() {
580        let key_str = key.as_str();
581
582        // Find matching field by name or alias
583        let field_info = struct_def
584            .fields
585            .iter()
586            .enumerate()
587            .find(|(_, f)| f.name == key_str || f.alias == Some(key_str));
588
589        if let Some((idx, field)) = field_info {
590            partial = partial.begin_field(field.name)?;
591            // Check for field-level proxy
592            #[cfg(feature = "alloc")]
593            if field.proxy_convert_in_fn().is_some() {
594                partial = partial.begin_custom_deserialization()?;
595                partial = deserialize_value_into(val, partial)?;
596                partial = partial.end()?;
597            } else {
598                partial = deserialize_value_into(val, partial)?;
599            }
600            #[cfg(not(feature = "alloc"))]
601            {
602                partial = deserialize_value_into(val, partial)?;
603            }
604            partial = partial.end()?;
605            fields_set[idx] = true;
606        } else if deny_unknown_fields {
607            return Err(ValueError::new(ValueErrorKind::UnknownField {
608                field: key_str.to_string(),
609            }));
610        }
611        // else: skip unknown field
612    }
613
614    // Handle missing fields - try to set defaults
615    for (idx, field) in struct_def.fields.iter().enumerate() {
616        if fields_set[idx] {
617            continue;
618        }
619
620        // Try to set default for the field
621        partial = partial
622            .set_nth_field_to_default(idx)
623            .map_err(|_| ValueError::new(ValueErrorKind::MissingField { field: field.name }))?;
624    }
625
626    Ok(partial)
627}
628
629/// Deserialize a struct that has flattened fields.
630fn deserialize_struct_with_flatten<'p>(
631    obj: &crate::VObject,
632    mut partial: Partial<'p>,
633    struct_def: &'static facet_core::StructType,
634    deny_unknown_fields: bool,
635) -> Result<Partial<'p>> {
636    use alloc::collections::BTreeMap;
637
638    let num_fields = struct_def.fields.len();
639    let mut fields_set = alloc::vec![false; num_fields];
640
641    // Collect which keys go to which flattened field
642    // Key -> (flattened_field_idx, inner_field_name)
643    let mut flatten_keys: BTreeMap<&str, (usize, &str)> = BTreeMap::new();
644
645    // First pass: identify which keys belong to flattened fields
646    for (idx, field) in struct_def.fields.iter().enumerate() {
647        if !field.is_flattened() {
648            continue;
649        }
650
651        // Get the inner struct's fields
652        let inner_shape = field.shape.get();
653        if let Type::User(UserType::Struct(inner_struct)) = &inner_shape.ty {
654            for inner_field in inner_struct.fields.iter() {
655                // Use the serialization name (rename if present, else name)
656                let key_name = inner_field.rename.unwrap_or(inner_field.name);
657                flatten_keys.insert(key_name, (idx, inner_field.name));
658            }
659        }
660    }
661
662    // Collect values for each flattened field
663    let mut flatten_values: Vec<BTreeMap<String, Value>> =
664        (0..num_fields).map(|_| BTreeMap::new()).collect();
665
666    // Process each key-value pair in the object
667    for (key, val) in obj.iter() {
668        let key_str = key.as_str();
669
670        // First, check for direct field match (non-flattened fields) by name or alias
671        let direct_field =
672            struct_def.fields.iter().enumerate().find(|(_, f)| {
673                !f.is_flattened() && (f.name == key_str || f.alias == Some(key_str))
674            });
675
676        if let Some((idx, field)) = direct_field {
677            partial = partial.begin_field(field.name)?;
678            // Check for field-level proxy
679            #[cfg(feature = "alloc")]
680            if field.proxy_convert_in_fn().is_some() {
681                partial = partial.begin_custom_deserialization()?;
682                partial = deserialize_value_into(val, partial)?;
683                partial = partial.end()?;
684            } else {
685                partial = deserialize_value_into(val, partial)?;
686            }
687            #[cfg(not(feature = "alloc"))]
688            {
689                partial = deserialize_value_into(val, partial)?;
690            }
691            partial = partial.end()?;
692            fields_set[idx] = true;
693            continue;
694        }
695
696        // Check if this key belongs to a flattened field
697        if let Some(&(flatten_idx, inner_name)) = flatten_keys.get(key_str) {
698            flatten_values[flatten_idx].insert(inner_name.to_string(), val.clone());
699            fields_set[flatten_idx] = true;
700            continue;
701        }
702
703        // Unknown field
704        if deny_unknown_fields {
705            return Err(ValueError::new(ValueErrorKind::UnknownField {
706                field: key_str.to_string(),
707            }));
708        }
709        // else: skip unknown field
710    }
711
712    // Deserialize each flattened field from its collected values
713    for (idx, field) in struct_def.fields.iter().enumerate() {
714        if !field.is_flattened() {
715            continue;
716        }
717
718        if !flatten_values[idx].is_empty() {
719            // Build a synthetic Value::Object for this flattened field
720            let mut synthetic_obj = crate::VObject::new();
721            let values = core::mem::take(&mut flatten_values[idx]);
722            for (k, v) in values {
723                synthetic_obj.insert(k, v);
724            }
725            let synthetic_value = Value::from(synthetic_obj);
726
727            partial = partial.begin_field(field.name)?;
728            partial = deserialize_value_into(&synthetic_value, partial)?;
729            partial = partial.end()?;
730            fields_set[idx] = true;
731        }
732    }
733
734    // Handle missing fields - try to set defaults
735    for (idx, field) in struct_def.fields.iter().enumerate() {
736        if fields_set[idx] {
737            continue;
738        }
739
740        // Try to set default for the field
741        partial = partial
742            .set_nth_field_to_default(idx)
743            .map_err(|_| ValueError::new(ValueErrorKind::MissingField { field: field.name }))?;
744    }
745
746    Ok(partial)
747}
748
749/// Deserialize a tuple from a Value::Array.
750fn deserialize_tuple<'p>(value: &Value, partial: Partial<'p>) -> Result<Partial<'p>> {
751    let mut partial = partial;
752    let arr = value.as_array().ok_or_else(|| {
753        ValueError::new(ValueErrorKind::TypeMismatch {
754            expected: "array",
755            got: value.value_type(),
756        })
757    })?;
758
759    let tuple_len = match &partial.shape().ty {
760        Type::User(UserType::Struct(struct_def)) => struct_def.fields.len(),
761        _ => {
762            return Err(ValueError::new(ValueErrorKind::Unsupported {
763                message: "expected tuple type".into(),
764            }));
765        }
766    };
767
768    if arr.len() != tuple_len {
769        return Err(ValueError::new(ValueErrorKind::Unsupported {
770            message: format!("tuple has {} elements but got {}", tuple_len, arr.len()),
771        }));
772    }
773
774    for (i, item) in arr.iter().enumerate() {
775        partial = partial.begin_nth_field(i)?;
776        partial = deserialize_value_into(item, partial)?;
777        partial = partial.end()?;
778    }
779
780    Ok(partial)
781}
782
783/// Deserialize an enum from a Value.
784fn deserialize_enum<'p>(value: &Value, partial: Partial<'p>) -> Result<Partial<'p>> {
785    let shape = partial.shape();
786
787    // Check for numeric enums first (like #[repr(u8)] enums)
788    if shape.is_numeric() {
789        return deserialize_numeric_enum(value, partial);
790    }
791
792    if shape.is_untagged() {
793        return deserialize_untagged_enum(value, partial);
794    }
795
796    let tag_key = shape.get_tag_attr();
797    let content_key = shape.get_content_attr();
798
799    match (tag_key, content_key) {
800        // Internally tagged: {"type": "Circle", "radius": 5.0}
801        (Some(tag_key), None) => deserialize_internally_tagged_enum(value, partial, tag_key),
802        // Adjacently tagged: {"t": "Message", "c": "hello"}
803        (Some(tag_key), Some(content_key)) => {
804            deserialize_adjacently_tagged_enum(value, partial, tag_key, content_key)
805        }
806        // Externally tagged (default): {"VariantName": {...}}
807        (None, None) => deserialize_externally_tagged_enum(value, partial),
808        // Invalid: content without tag
809        (None, Some(_)) => Err(ValueError::new(ValueErrorKind::Unsupported {
810            message: "content key without tag key is invalid".into(),
811        })),
812    }
813}
814
815/// Deserialize a numeric enum from a Value::Number or Value::String.
816///
817/// Numeric enums use their discriminant value for serialization (e.g., `#[repr(u8)]` enums).
818/// Accepts:
819/// - Number values (i64/u64)
820/// - String values that can be parsed as i64
821fn deserialize_numeric_enum<'p>(value: &Value, mut partial: Partial<'p>) -> Result<Partial<'p>> {
822    let discriminant = match value.value_type() {
823        ValueType::Number => {
824            let num = value.as_number().unwrap();
825            if let Some(i) = num.to_i64() {
826                i
827            } else {
828                return Err(ValueError::new(ValueErrorKind::TypeMismatch {
829                    expected: "Could not parse discriminant into i64", // TODO
830                    got: ValueType::Number,
831                }));
832            }
833        }
834        ValueType::String => {
835            // Parse string as i64 discriminant
836            let s = value.as_string().unwrap().as_str();
837            s.parse().map_err(|_| {
838                ValueError::new(ValueErrorKind::TypeMismatch {
839                    expected: "Failed to parse string into i64",
840                    got: ValueType::String,
841                })
842            })?
843        }
844        other => {
845            return Err(ValueError::new(ValueErrorKind::TypeMismatch {
846                expected: "Expected number or string for numeric enum",
847                got: other,
848            }));
849        }
850    };
851
852    partial = partial.select_variant(discriminant)?;
853    Ok(partial)
854}
855
856/// Deserialize an externally tagged enum: {"VariantName": data} or "VariantName"
857fn deserialize_externally_tagged_enum<'p>(
858    value: &Value,
859    mut partial: Partial<'p>,
860) -> Result<Partial<'p>> {
861    match value.value_type() {
862        // String = unit variant
863        ValueType::String => {
864            let variant_name = value.as_string().unwrap().as_str();
865            partial = partial.select_variant_named(variant_name)?;
866            Ok(partial)
867        }
868        // Object = externally tagged variant with data
869        ValueType::Object => {
870            let obj = value.as_object().unwrap();
871            if obj.len() != 1 {
872                return Err(ValueError::new(ValueErrorKind::Unsupported {
873                    message: format!("enum object must have exactly 1 key, got {}", obj.len()),
874                }));
875            }
876
877            let (key, val) = obj.iter().next().unwrap();
878            let variant_name = key.as_str();
879
880            partial = partial.select_variant_named(variant_name)?;
881
882            let variant = partial.selected_variant().ok_or_else(|| {
883                ValueError::new(ValueErrorKind::Unsupported {
884                    message: "failed to get selected variant".into(),
885                })
886            })?;
887
888            populate_variant_from_value(val, partial, &variant)
889        }
890        other => Err(ValueError::new(ValueErrorKind::TypeMismatch {
891            expected: "string or object for enum",
892            got: other,
893        })),
894    }
895}
896
897/// Deserialize an internally tagged enum: {"type": "Circle", "radius": 5.0}
898fn deserialize_internally_tagged_enum<'p>(
899    value: &Value,
900    mut partial: Partial<'p>,
901    tag_key: &str,
902) -> Result<Partial<'p>> {
903    let obj = value.as_object().ok_or_else(|| {
904        ValueError::new(ValueErrorKind::TypeMismatch {
905            expected: "object for internally tagged enum",
906            got: value.value_type(),
907        })
908    })?;
909
910    // Find the tag value
911    let tag_value = obj.get(tag_key).ok_or_else(|| {
912        ValueError::new(ValueErrorKind::Unsupported {
913            message: format!("internally tagged enum missing tag key '{tag_key}'"),
914        })
915    })?;
916
917    let variant_name = tag_value.as_string().ok_or_else(|| {
918        ValueError::new(ValueErrorKind::TypeMismatch {
919            expected: "string for enum tag",
920            got: tag_value.value_type(),
921        })
922    })?;
923
924    partial = partial.select_variant_named(variant_name.as_str())?;
925
926    let variant = partial.selected_variant().ok_or_else(|| {
927        ValueError::new(ValueErrorKind::Unsupported {
928            message: "failed to get selected variant".into(),
929        })
930    })?;
931
932    // For struct variants, deserialize the remaining fields (excluding the tag)
933    match variant.data.kind {
934        StructKind::Unit => {
935            // Unit variant - just the tag, no other fields expected
936            Ok(partial)
937        }
938        StructKind::Struct => {
939            // Struct variant - deserialize fields from the same object (excluding tag)
940            for field in variant.data.fields.iter() {
941                if let Some(field_value) = obj.get(field.name) {
942                    partial = partial.begin_field(field.name)?;
943                    partial = deserialize_value_into(field_value, partial)?;
944                    partial = partial.end()?;
945                }
946            }
947            Ok(partial)
948        }
949        StructKind::TupleStruct | StructKind::Tuple => {
950            Err(ValueError::new(ValueErrorKind::Unsupported {
951                message: "internally tagged tuple variants are not supported".into(),
952            }))
953        }
954    }
955}
956
957/// Deserialize an adjacently tagged enum: {"t": "Message", "c": "hello"}
958fn deserialize_adjacently_tagged_enum<'p>(
959    value: &Value,
960    mut partial: Partial<'p>,
961    tag_key: &str,
962    content_key: &str,
963) -> Result<Partial<'p>> {
964    let obj = value.as_object().ok_or_else(|| {
965        ValueError::new(ValueErrorKind::TypeMismatch {
966            expected: "object for adjacently tagged enum",
967            got: value.value_type(),
968        })
969    })?;
970
971    // Find the tag value
972    let tag_value = obj.get(tag_key).ok_or_else(|| {
973        ValueError::new(ValueErrorKind::Unsupported {
974            message: format!("adjacently tagged enum missing tag key '{tag_key}'"),
975        })
976    })?;
977
978    let variant_name = tag_value.as_string().ok_or_else(|| {
979        ValueError::new(ValueErrorKind::TypeMismatch {
980            expected: "string for enum tag",
981            got: tag_value.value_type(),
982        })
983    })?;
984
985    partial = partial.select_variant_named(variant_name.as_str())?;
986
987    let variant = partial.selected_variant().ok_or_else(|| {
988        ValueError::new(ValueErrorKind::Unsupported {
989            message: "failed to get selected variant".into(),
990        })
991    })?;
992
993    // For non-unit variants, get the content
994    match variant.data.kind {
995        StructKind::Unit => {
996            // Unit variant - no content field needed
997            Ok(partial)
998        }
999        _ => {
1000            // Get the content value
1001            let content_value = obj.get(content_key).ok_or_else(|| {
1002                ValueError::new(ValueErrorKind::Unsupported {
1003                    message: format!("adjacently tagged enum missing content key '{content_key}'"),
1004                })
1005            })?;
1006
1007            populate_variant_from_value(content_value, partial, &variant)
1008        }
1009    }
1010}
1011
1012fn deserialize_untagged_enum<'p>(value: &Value, partial: Partial<'p>) -> Result<Partial<'p>> {
1013    let mut partial = partial;
1014    let shape = partial.shape();
1015    let enum_type = match &shape.ty {
1016        Type::User(UserType::Enum(enum_def)) => enum_def,
1017        _ => {
1018            return Err(ValueError::new(ValueErrorKind::Unsupported {
1019                message: "expected enum type".into(),
1020            }));
1021        }
1022    };
1023
1024    for variant in enum_type.variants.iter() {
1025        if value_matches_variant(value, variant) {
1026            partial = partial.select_variant_named(variant.effective_name())?;
1027            return populate_variant_from_value(value, partial, variant);
1028        }
1029    }
1030
1031    Err(ValueError::new(ValueErrorKind::TypeMismatch {
1032        expected: shape.type_identifier,
1033        got: value.value_type(),
1034    }))
1035}
1036
1037fn populate_variant_from_value<'p>(
1038    value: &Value,
1039    mut partial: Partial<'p>,
1040    variant: &Variant,
1041) -> Result<Partial<'p>> {
1042    match variant.data.kind {
1043        StructKind::Unit => {
1044            if !matches!(value.value_type(), ValueType::Null) {
1045                return Err(ValueError::new(ValueErrorKind::TypeMismatch {
1046                    expected: "null for unit variant",
1047                    got: value.value_type(),
1048                }));
1049            }
1050        }
1051        StructKind::TupleStruct | StructKind::Tuple => {
1052            let num_fields = variant.data.fields.len();
1053            if num_fields == 0 {
1054                // nothing to populate
1055            } else if num_fields == 1 {
1056                partial = partial.begin_nth_field(0)?;
1057                partial = deserialize_value_into(value, partial)?;
1058                partial = partial.end()?;
1059            } else {
1060                let arr = value.as_array().ok_or_else(|| {
1061                    ValueError::new(ValueErrorKind::TypeMismatch {
1062                        expected: "array for tuple variant",
1063                        got: value.value_type(),
1064                    })
1065                })?;
1066
1067                if arr.len() != num_fields {
1068                    return Err(ValueError::new(ValueErrorKind::Unsupported {
1069                        message: format!(
1070                            "tuple variant has {} fields but got {}",
1071                            num_fields,
1072                            arr.len()
1073                        ),
1074                    }));
1075                }
1076
1077                for (i, item) in arr.iter().enumerate() {
1078                    partial = partial.begin_nth_field(i)?;
1079                    partial = deserialize_value_into(item, partial)?;
1080                    partial = partial.end()?;
1081                }
1082            }
1083        }
1084        StructKind::Struct => {
1085            let inner_obj = value.as_object().ok_or_else(|| {
1086                ValueError::new(ValueErrorKind::TypeMismatch {
1087                    expected: "object for struct variant",
1088                    got: value.value_type(),
1089                })
1090            })?;
1091
1092            for (field_key, field_val) in inner_obj.iter() {
1093                partial = partial.begin_field(field_key.as_str())?;
1094                partial = deserialize_value_into(field_val, partial)?;
1095                partial = partial.end()?;
1096            }
1097        }
1098    }
1099
1100    Ok(partial)
1101}
1102
1103fn value_matches_variant(value: &Value, variant: &Variant) -> bool {
1104    match variant.data.kind {
1105        StructKind::Unit => matches!(value.value_type(), ValueType::Null),
1106        StructKind::TupleStruct | StructKind::Tuple => {
1107            let fields = variant.data.fields;
1108            if fields.is_empty() {
1109                matches!(value.value_type(), ValueType::Null)
1110            } else if fields.len() == 1 {
1111                value_matches_shape(value, fields[0].shape.get())
1112            } else {
1113                value
1114                    .as_array()
1115                    .map(|arr| arr.len() == fields.len())
1116                    .unwrap_or(false)
1117            }
1118        }
1119        StructKind::Struct => matches!(value.value_type(), ValueType::Object),
1120    }
1121}
1122
1123fn value_matches_shape(value: &Value, shape: &'static Shape) -> bool {
1124    match &shape.ty {
1125        Type::Primitive(PrimitiveType::Boolean) => {
1126            matches!(value.value_type(), ValueType::Bool)
1127        }
1128        Type::Primitive(PrimitiveType::Numeric(num)) => match num {
1129            NumericType::Integer { signed } => {
1130                if *signed {
1131                    value.as_number().and_then(|n| n.to_i64()).is_some()
1132                } else {
1133                    value.as_number().and_then(|n| n.to_u64()).is_some()
1134                }
1135            }
1136            NumericType::Float => value.as_number().and_then(|n| n.to_f64()).is_some(),
1137        },
1138        _ => true,
1139    }
1140}
1141
1142/// Deserialize a list/Vec from a Value::Array.
1143fn deserialize_list<'p>(value: &Value, partial: Partial<'p>) -> Result<Partial<'p>> {
1144    let mut partial = partial;
1145    let arr = value.as_array().ok_or_else(|| {
1146        ValueError::new(ValueErrorKind::TypeMismatch {
1147            expected: "array",
1148            got: value.value_type(),
1149        })
1150    })?;
1151
1152    partial = partial.init_list()?;
1153
1154    for item in arr.iter() {
1155        partial = partial.begin_list_item()?;
1156        partial = deserialize_value_into(item, partial)?;
1157        partial = partial.end()?;
1158    }
1159
1160    Ok(partial)
1161}
1162
1163/// Deserialize a fixed-size array from a Value::Array.
1164fn deserialize_array<'p>(value: &Value, partial: Partial<'p>) -> Result<Partial<'p>> {
1165    let mut partial = partial;
1166    let arr = value.as_array().ok_or_else(|| {
1167        ValueError::new(ValueErrorKind::TypeMismatch {
1168            expected: "array",
1169            got: value.value_type(),
1170        })
1171    })?;
1172
1173    let array_len = match &partial.shape().def {
1174        Def::Array(arr_def) => arr_def.n,
1175        _ => {
1176            return Err(ValueError::new(ValueErrorKind::Unsupported {
1177                message: "expected array type".into(),
1178            }));
1179        }
1180    };
1181
1182    if arr.len() != array_len {
1183        return Err(ValueError::new(ValueErrorKind::Unsupported {
1184            message: format!(
1185                "fixed array has {} elements but got {}",
1186                array_len,
1187                arr.len()
1188            ),
1189        }));
1190    }
1191
1192    for (i, item) in arr.iter().enumerate() {
1193        partial = partial.begin_nth_field(i)?;
1194        partial = deserialize_value_into(item, partial)?;
1195        partial = partial.end()?;
1196    }
1197
1198    Ok(partial)
1199}
1200
1201/// Deserialize a set from a Value::Array.
1202fn deserialize_set<'p>(value: &Value, partial: Partial<'p>) -> Result<Partial<'p>> {
1203    let mut partial = partial;
1204    let arr = value.as_array().ok_or_else(|| {
1205        ValueError::new(ValueErrorKind::TypeMismatch {
1206            expected: "array",
1207            got: value.value_type(),
1208        })
1209    })?;
1210
1211    partial = partial.init_set()?;
1212
1213    for item in arr.iter() {
1214        partial = partial.begin_set_item()?;
1215        partial = deserialize_value_into(item, partial)?;
1216        partial = partial.end()?;
1217    }
1218
1219    Ok(partial)
1220}
1221
1222/// Deserialize a map from a Value::Object.
1223fn deserialize_map<'p>(value: &Value, partial: Partial<'p>) -> Result<Partial<'p>> {
1224    let mut partial = partial;
1225    let obj = value.as_object().ok_or_else(|| {
1226        ValueError::new(ValueErrorKind::TypeMismatch {
1227            expected: "object",
1228            got: value.value_type(),
1229        })
1230    })?;
1231
1232    partial = partial.init_map()?;
1233
1234    for (key, val) in obj.iter() {
1235        // Set the key
1236        partial = partial.begin_key()?;
1237        // For map keys, we need to handle the key type
1238        // Most commonly it's String, but could be other types with inner
1239        if partial.shape().inner.is_some() {
1240            partial = partial.begin_inner()?;
1241            partial = partial.set(key.as_str().to_string())?;
1242            partial = partial.end()?;
1243        } else {
1244            partial = partial.set(key.as_str().to_string())?;
1245        }
1246        partial = partial.end()?;
1247
1248        // Set the value
1249        partial = partial.begin_value()?;
1250        partial = deserialize_value_into(val, partial)?;
1251        partial = partial.end()?;
1252    }
1253
1254    Ok(partial)
1255}
1256
1257/// Deserialize an Option from a Value.
1258fn deserialize_option<'p>(value: &Value, partial: Partial<'p>) -> Result<Partial<'p>> {
1259    let mut partial = partial;
1260    if value.is_null() {
1261        partial = partial.set_default()?; // None
1262    } else {
1263        partial = partial.begin_some()?;
1264        partial = deserialize_value_into(value, partial)?;
1265        partial = partial.end()?;
1266    }
1267    Ok(partial)
1268}
1269
1270/// Deserialize a smart pointer (Box, Arc, Rc) or Cow from a Value.
1271fn deserialize_pointer<'p>(value: &Value, partial: Partial<'p>) -> Result<Partial<'p>> {
1272    use facet_core::{KnownPointer, SequenceType};
1273
1274    let mut partial = partial;
1275    let (is_slice_pointer, is_reference, is_cow) =
1276        if let Def::Pointer(ptr_def) = partial.shape().def {
1277            let is_slice = if let Some(pointee) = ptr_def.pointee() {
1278                matches!(pointee.ty, Type::Sequence(SequenceType::Slice(_)))
1279            } else {
1280                false
1281            };
1282            let is_ref = matches!(
1283                ptr_def.known,
1284                Some(KnownPointer::SharedReference | KnownPointer::ExclusiveReference)
1285            );
1286            let is_cow = matches!(ptr_def.known, Some(KnownPointer::Cow));
1287            (is_slice, is_ref, is_cow)
1288        } else {
1289            (false, false, false)
1290        };
1291
1292    // References can't be deserialized (need existing data to borrow from)
1293    if is_reference {
1294        return Err(ValueError::new(ValueErrorKind::Unsupported {
1295            message: format!(
1296                "cannot deserialize into reference type '{}'",
1297                partial.shape().type_identifier
1298            ),
1299        }));
1300    }
1301
1302    // Cow needs special handling
1303    if is_cow {
1304        // Check if this is Cow<str> - we can set it directly from a string value
1305        if let Def::Pointer(ptr_def) = partial.shape().def
1306            && let Some(pointee) = ptr_def.pointee()
1307            && matches!(
1308                pointee.ty,
1309                Type::Primitive(PrimitiveType::Textual(TextualType::Str))
1310            )
1311        {
1312            // This is Cow<str> - deserialize from string
1313            if let Some(s) = value.as_string() {
1314                // Set the owned string value - Cow<str> will store it as Owned
1315                partial = partial.set(alloc::borrow::Cow::<'static, str>::Owned(
1316                    s.as_str().to_string(),
1317                ))?;
1318                return Ok(partial);
1319            } else {
1320                return Err(ValueError::new(ValueErrorKind::TypeMismatch {
1321                    expected: "string for Cow<str>",
1322                    got: value.value_type(),
1323                }));
1324            }
1325        }
1326        // For other Cow types, use begin_inner
1327        partial = partial.begin_inner()?;
1328        partial = deserialize_value_into(value, partial)?;
1329        partial = partial.end()?;
1330        return Ok(partial);
1331    }
1332
1333    partial = partial.begin_smart_ptr()?;
1334
1335    if is_slice_pointer {
1336        // This is a slice pointer like Arc<[T]> - deserialize as array
1337        let arr = value.as_array().ok_or_else(|| {
1338            ValueError::new(ValueErrorKind::TypeMismatch {
1339                expected: "array",
1340                got: value.value_type(),
1341            })
1342        })?;
1343
1344        for item in arr.iter() {
1345            partial = partial.begin_list_item()?;
1346            partial = deserialize_value_into(item, partial)?;
1347            partial = partial.end()?;
1348        }
1349    } else {
1350        // Regular smart pointer - deserialize the inner type
1351        partial = deserialize_value_into(value, partial)?;
1352    }
1353
1354    partial = partial.end()?;
1355    Ok(partial)
1356}
1357
1358#[cfg(test)]
1359mod tests {
1360    use super::*;
1361    use crate::{VArray, VObject, VString};
1362
1363    #[test]
1364    fn test_deserialize_primitives() {
1365        // bool
1366        let v = Value::TRUE;
1367        let b: bool = from_value(v).unwrap();
1368        assert!(b);
1369
1370        // i32
1371        let v = Value::from(42i64);
1372        let n: i32 = from_value(v).unwrap();
1373        assert_eq!(n, 42);
1374
1375        // String
1376        let v: Value = VString::new("hello").into();
1377        let s: String = from_value(v).unwrap();
1378        assert_eq!(s, "hello");
1379    }
1380
1381    #[test]
1382    fn test_deserialize_option() {
1383        // Some
1384        let v = Value::from(42i64);
1385        let opt: Option<i32> = from_value(v).unwrap();
1386        assert_eq!(opt, Some(42));
1387
1388        // None
1389        let v = Value::NULL;
1390        let opt: Option<i32> = from_value(v).unwrap();
1391        assert_eq!(opt, None);
1392    }
1393
1394    #[test]
1395    fn test_deserialize_vec() {
1396        let mut arr = VArray::new();
1397        arr.push(Value::from(1i64));
1398        arr.push(Value::from(2i64));
1399        arr.push(Value::from(3i64));
1400
1401        let v: Value = arr.into();
1402        let vec: alloc::vec::Vec<i32> = from_value(v).unwrap();
1403        assert_eq!(vec, alloc::vec![1, 2, 3]);
1404    }
1405
1406    #[test]
1407    fn test_deserialize_nested() {
1408        // Vec<Option<i32>>
1409        let mut arr = VArray::new();
1410        arr.push(Value::from(1i64));
1411        arr.push(Value::NULL);
1412        arr.push(Value::from(3i64));
1413
1414        let v: Value = arr.into();
1415        let vec: alloc::vec::Vec<Option<i32>> = from_value(v).unwrap();
1416        assert_eq!(vec, alloc::vec![Some(1), None, Some(3)]);
1417    }
1418
1419    #[test]
1420    fn test_deserialize_map() {
1421        use alloc::collections::BTreeMap;
1422
1423        let mut obj = VObject::new();
1424        obj.insert("a", Value::from(1i64));
1425        obj.insert("b", Value::from(2i64));
1426
1427        let v: Value = obj.into();
1428        let map: BTreeMap<String, i32> = from_value(v).unwrap();
1429        assert_eq!(map.get("a"), Some(&1));
1430        assert_eq!(map.get("b"), Some(&2));
1431    }
1432}