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