1#![allow(clippy::result_large_err)]
2use alloc::format;
32use alloc::string::{String, ToString};
33use alloc::vec::Vec;
34
35use facet_core::{
36 Def, Facet, Field, NumericType, PrimitiveType, Shape, StructKind, TextualType, Type, UserType,
37 Variant,
38};
39use facet_reflect::{AllocError, Partial, ReflectError, ShapeMismatchError, TypePlan};
40
41use crate::{VNumber, Value, ValueType};
42
43#[derive(Clone, Debug, PartialEq, Eq)]
45pub enum PathSegment {
46 Field(String),
48 Variant(String),
50 Index(usize),
52}
53
54impl core::fmt::Display for PathSegment {
55 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
56 match self {
57 PathSegment::Field(name) => write!(f, ".{name}"),
58 PathSegment::Variant(name) => write!(f, "::{name}"),
59 PathSegment::Index(i) => write!(f, "[{i}]"),
60 }
61 }
62}
63
64#[derive(Debug)]
66pub struct ValueError {
67 pub kind: ValueErrorKind,
69 pub source_path: Vec<PathSegment>,
71 pub dest_path: Vec<PathSegment>,
73 pub target_shape: Option<&'static Shape>,
75 pub source_value: Option<Value>,
77}
78
79impl core::fmt::Display for ValueError {
80 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
81 if self.source_path.is_empty() {
82 write!(f, "{}", self.kind)
83 } else {
84 write!(f, "at {}: {}", self.source_path_string(), self.kind)
85 }
86 }
87}
88
89impl ValueError {
90 pub const fn new(kind: ValueErrorKind) -> Self {
92 Self {
93 kind,
94 source_path: Vec::new(),
95 dest_path: Vec::new(),
96 target_shape: None,
97 source_value: None,
98 }
99 }
100
101 pub const fn with_shape(mut self, shape: &'static Shape) -> Self {
103 self.target_shape = Some(shape);
104 self
105 }
106
107 pub fn with_value(mut self, value: Value) -> Self {
109 self.source_value = Some(value);
110 self
111 }
112
113 pub fn with_path(mut self, segment: PathSegment) -> Self {
115 self.source_path.insert(0, segment.clone());
116 self.dest_path.insert(0, segment);
117 self
118 }
119
120 pub fn source_path_string(&self) -> String {
122 if self.source_path.is_empty() {
123 "<root>".into()
124 } else {
125 use core::fmt::Write;
126 let mut s = String::new();
127 for seg in &self.source_path {
128 let _ = write!(s, "{seg}");
129 }
130 s
131 }
132 }
133
134 pub fn dest_path_string(&self) -> String {
136 if self.dest_path.is_empty() {
137 "<root>".into()
138 } else {
139 use core::fmt::Write;
140 let mut s = String::new();
141 for seg in &self.dest_path {
142 let _ = write!(s, "{seg}");
143 }
144 s
145 }
146 }
147}
148
149#[cfg(feature = "std")]
150impl core::error::Error for ValueError {}
151
152#[derive(Debug)]
154pub enum ValueErrorKind {
155 TypeMismatch {
157 expected: &'static str,
159 got: ValueType,
161 },
162 MissingField {
164 field: &'static str,
166 },
167 UnknownField {
169 field: String,
171 },
172 NumberOutOfRange {
174 message: String,
176 },
177 Reflect(ReflectError),
179 Unsupported {
181 message: String,
183 },
184}
185
186impl core::fmt::Display for ValueErrorKind {
187 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
188 match self {
189 ValueErrorKind::TypeMismatch { expected, got } => {
190 write!(f, "type mismatch: expected {expected}, got {got:?}")
191 }
192 ValueErrorKind::MissingField { field } => {
193 write!(f, "missing required field `{field}`")
194 }
195 ValueErrorKind::UnknownField { field } => {
196 write!(f, "unknown field `{field}`")
197 }
198 ValueErrorKind::NumberOutOfRange { message } => {
199 write!(f, "number out of range: {message}")
200 }
201 ValueErrorKind::Reflect(e) => write!(f, "reflection error: {e}"),
202 ValueErrorKind::Unsupported { message } => {
203 write!(f, "unsupported: {message}")
204 }
205 }
206 }
207}
208
209impl From<ReflectError> for ValueError {
210 fn from(err: ReflectError) -> Self {
211 ValueError::new(ValueErrorKind::Reflect(err))
212 }
213}
214
215impl From<ShapeMismatchError> for ValueError {
216 fn from(err: ShapeMismatchError) -> Self {
217 ValueError::new(ValueErrorKind::Unsupported {
218 message: format!(
219 "shape mismatch: expected {}, got {}",
220 err.expected, err.actual
221 ),
222 })
223 }
224}
225
226impl From<AllocError> for ValueError {
227 fn from(err: AllocError) -> Self {
228 ValueError::new(ValueErrorKind::Unsupported {
229 message: format!("allocation failed for {}: {}", err.shape, err.operation),
230 })
231 }
232}
233
234pub type Result<T> = core::result::Result<T, ValueError>;
236
237pub fn from_value<T: Facet<'static>>(value: Value) -> Result<T> {
259 let plan = TypePlan::<T>::build().map_err(|e| {
260 ValueError::from(e)
261 .with_shape(T::SHAPE)
262 .with_value(value.clone())
263 })?;
264 let partial = plan.partial_owned().map_err(|e| {
265 ValueError::from(e)
266 .with_shape(T::SHAPE)
267 .with_value(value.clone())
268 })?;
269 let partial = deserialize_value_into(&value, partial)
270 .map_err(|e| e.with_shape(T::SHAPE).with_value(value.clone()))?;
271 let heap_value = partial.build().map_err(|e| {
272 ValueError::from(e)
273 .with_shape(T::SHAPE)
274 .with_value(value.clone())
275 })?;
276 heap_value.materialize().map_err(|e| {
277 ValueError::from(e)
278 .with_shape(T::SHAPE)
279 .with_value(value.clone())
280 })
281}
282
283fn deserialize_value_into<'facet>(
285 value: &Value,
286 partial: Partial<'facet, false>,
287) -> Result<Partial<'facet, false>> {
288 let mut partial = partial;
289 let shape = partial.shape();
290
291 if matches!(&shape.def, Def::Option(_)) {
293 return deserialize_option(value, partial);
294 }
295
296 if matches!(&shape.def, Def::Pointer(_)) {
298 return deserialize_pointer(value, partial);
299 }
300
301 #[cfg(feature = "alloc")]
303 if shape.proxy.is_some() {
304 let (partial_returned, has_proxy) = partial.begin_custom_deserialization_from_shape()?;
305 partial = partial_returned;
306 if has_proxy {
307 partial = deserialize_value_into(value, partial)?;
308 partial = partial.end()?;
309 return Ok(partial);
310 }
311 }
312
313 if shape.builder_shape.is_some() {
315 partial = partial.begin_inner()?;
316 partial = deserialize_value_into(value, partial)?;
317 partial = partial.end()?;
318 return Ok(partial);
319 }
320
321 if shape.inner.is_some()
324 && !matches!(
325 &shape.def,
326 Def::List(_) | Def::Map(_) | Def::Set(_) | Def::Array(_)
327 )
328 {
329 partial = partial.begin_inner()?;
330 partial = deserialize_value_into(value, partial)?;
331 partial = partial.end()?;
332 return Ok(partial);
333 }
334
335 match &shape.ty {
337 Type::User(UserType::Struct(struct_def)) => {
338 if struct_def.kind == StructKind::Tuple {
339 return deserialize_tuple(value, partial);
340 }
341 return deserialize_struct(value, partial);
342 }
343 Type::User(UserType::Enum(_)) => return deserialize_enum(value, partial),
344 _ => {}
345 }
346
347 match &shape.def {
349 Def::Scalar => deserialize_scalar(value, partial),
350 Def::List(_) => deserialize_list(value, partial),
351 Def::Map(_) => deserialize_map(value, partial),
352 Def::Array(_) => deserialize_array(value, partial),
353 Def::Set(_) => deserialize_set(value, partial),
354 Def::DynamicValue(_) => {
355 partial = partial.set(value.clone())?;
357 Ok(partial)
358 }
359 _ => Err(ValueError::new(ValueErrorKind::Unsupported {
360 message: format!("unsupported shape def: {:?}", shape.def),
361 })),
362 }
363}
364
365fn deserialize_scalar<'facet>(
367 value: &Value,
368 partial: Partial<'facet, false>,
369) -> Result<Partial<'facet, false>> {
370 let mut partial = partial;
371 let shape = partial.shape();
372
373 match value.value_type() {
374 ValueType::Null => {
375 partial = partial.set_default()?;
376 Ok(partial)
377 }
378 ValueType::Bool => {
379 let b = value.as_bool().unwrap();
380 partial = partial.set(b)?;
381 Ok(partial)
382 }
383 ValueType::Number => {
384 let num = value.as_number().unwrap();
385 if *shape == *String::SHAPE {
389 let s = if let Some(i) = num.to_i64() {
390 format!("{i}")
391 } else if let Some(u) = num.to_u64() {
392 format!("{u}")
393 } else if let Some(f) = num.to_f64() {
394 format!("{f}")
395 } else {
396 return Err(ValueError::new(ValueErrorKind::TypeMismatch {
397 expected: "String",
398 got: ValueType::Number,
399 }));
400 };
401 partial = partial.set(s)?;
402 Ok(partial)
403 } else {
404 set_number(num, partial, shape)
405 }
406 }
407 ValueType::String => {
408 let s = value.as_string().unwrap();
409 if shape.vtable.has_parse() {
411 partial = partial.parse_from_str(s.as_str())?;
412 } else {
413 partial = partial.set(s.as_str().to_string())?;
414 }
415 Ok(partial)
416 }
417 ValueType::Bytes => {
418 let bytes = value.as_bytes().unwrap();
419 partial = partial.set(bytes.as_slice().to_vec())?;
420 Ok(partial)
421 }
422 other => Err(ValueError::new(ValueErrorKind::TypeMismatch {
423 expected: shape.type_identifier,
424 got: other,
425 })),
426 }
427}
428
429fn set_number<'facet>(
431 num: &VNumber,
432 partial: Partial<'facet, false>,
433 shape: &Shape,
434) -> Result<Partial<'facet, false>> {
435 use facet_core::{NumericType, PrimitiveType, ShapeLayout};
436
437 let mut partial = partial;
438 let size = match shape.layout {
439 ShapeLayout::Sized(layout) => layout.size(),
440 _ => {
441 return Err(ValueError::new(ValueErrorKind::Unsupported {
442 message: "unsized numeric type".into(),
443 }));
444 }
445 };
446
447 match &shape.ty {
448 Type::Primitive(PrimitiveType::Numeric(NumericType::Integer { signed: true })) => {
449 let val = num.to_i64().ok_or_else(|| {
450 ValueError::new(ValueErrorKind::NumberOutOfRange {
451 message: "value cannot be represented as i64".into(),
452 })
453 })?;
454 if *shape == *isize::SHAPE {
456 let v = isize::try_from(val).map_err(|_| {
457 ValueError::new(ValueErrorKind::NumberOutOfRange {
458 message: format!("{val} out of range for isize"),
459 })
460 })?;
461 partial = partial.set(v)?;
462 } else {
463 match size {
464 1 => {
465 let v = i8::try_from(val).map_err(|_| {
466 ValueError::new(ValueErrorKind::NumberOutOfRange {
467 message: format!("{val} out of range for i8"),
468 })
469 })?;
470 partial = partial.set(v)?;
471 }
472 2 => {
473 let v = i16::try_from(val).map_err(|_| {
474 ValueError::new(ValueErrorKind::NumberOutOfRange {
475 message: format!("{val} out of range for i16"),
476 })
477 })?;
478 partial = partial.set(v)?;
479 }
480 4 => {
481 let v = i32::try_from(val).map_err(|_| {
482 ValueError::new(ValueErrorKind::NumberOutOfRange {
483 message: format!("{val} out of range for i32"),
484 })
485 })?;
486 partial = partial.set(v)?;
487 }
488 8 => {
489 partial = partial.set(val)?;
490 }
491 16 => {
492 partial = partial.set(val as i128)?;
493 }
494 _ => {
495 return Err(ValueError::new(ValueErrorKind::Unsupported {
496 message: format!("unexpected integer size: {size}"),
497 }));
498 }
499 }
500 }
501 }
502 Type::Primitive(PrimitiveType::Numeric(NumericType::Integer { signed: false })) => {
503 let val = num.to_u64().ok_or_else(|| {
504 ValueError::new(ValueErrorKind::NumberOutOfRange {
505 message: "value cannot be represented as u64".into(),
506 })
507 })?;
508 if *shape == *usize::SHAPE {
510 let v = usize::try_from(val).map_err(|_| {
511 ValueError::new(ValueErrorKind::NumberOutOfRange {
512 message: format!("{val} out of range for usize"),
513 })
514 })?;
515 partial = partial.set(v)?;
516 } else {
517 match size {
518 1 => {
519 let v = u8::try_from(val).map_err(|_| {
520 ValueError::new(ValueErrorKind::NumberOutOfRange {
521 message: format!("{val} out of range for u8"),
522 })
523 })?;
524 partial = partial.set(v)?;
525 }
526 2 => {
527 let v = u16::try_from(val).map_err(|_| {
528 ValueError::new(ValueErrorKind::NumberOutOfRange {
529 message: format!("{val} out of range for u16"),
530 })
531 })?;
532 partial = partial.set(v)?;
533 }
534 4 => {
535 let v = u32::try_from(val).map_err(|_| {
536 ValueError::new(ValueErrorKind::NumberOutOfRange {
537 message: format!("{val} out of range for u32"),
538 })
539 })?;
540 partial = partial.set(v)?;
541 }
542 8 => {
543 partial = partial.set(val)?;
544 }
545 16 => {
546 partial = partial.set(val as u128)?;
547 }
548 _ => {
549 return Err(ValueError::new(ValueErrorKind::Unsupported {
550 message: format!("unexpected integer size: {size}"),
551 }));
552 }
553 }
554 }
555 }
556 Type::Primitive(PrimitiveType::Numeric(NumericType::Float)) => {
557 let val = num.to_f64_lossy();
558 match size {
559 4 => {
560 partial = partial.set(val as f32)?;
561 }
562 8 => {
563 partial = partial.set(val)?;
564 }
565 _ => {
566 return Err(ValueError::new(ValueErrorKind::Unsupported {
567 message: format!("unexpected float size: {size}"),
568 }));
569 }
570 }
571 }
572 _ => {
573 return Err(ValueError::new(ValueErrorKind::TypeMismatch {
574 expected: shape.type_identifier,
575 got: ValueType::Number,
576 }));
577 }
578 }
579 Ok(partial)
580}
581
582fn deserialize_struct<'facet>(
584 value: &Value,
585 partial: Partial<'facet, false>,
586) -> Result<Partial<'facet, false>> {
587 let mut partial = partial;
588 let obj = value.as_object().ok_or_else(|| {
589 ValueError::new(ValueErrorKind::TypeMismatch {
590 expected: "object",
591 got: value.value_type(),
592 })
593 })?;
594
595 let struct_def = match &partial.shape().ty {
596 Type::User(UserType::Struct(s)) => s,
597 _ => {
598 return Err(ValueError::new(ValueErrorKind::Unsupported {
599 message: "expected struct type".into(),
600 }));
601 }
602 };
603
604 let deny_unknown_fields = partial.struct_plan().unwrap().deny_unknown_fields;
605
606 let has_flattened = struct_def.fields.iter().any(|f| f.is_flattened());
608
609 if has_flattened {
610 return deserialize_struct_with_flatten(obj, partial, struct_def, deny_unknown_fields);
611 }
612
613 let num_fields = struct_def.fields.len();
615 let mut fields_set = alloc::vec![false; num_fields];
616
617 for (key, val) in obj.iter() {
619 let key_str = key.as_str();
620
621 let field_info = struct_def
623 .fields
624 .iter()
625 .enumerate()
626 .find(|(_, f)| f.effective_name() == key_str || f.alias == Some(key_str));
627
628 if let Some((idx, field)) = field_info {
629 partial = partial.begin_field(field.name)?;
630 #[cfg(feature = "alloc")]
632 if field.proxy_convert_in_fn().is_some() {
633 partial = partial.begin_custom_deserialization()?;
634 partial = deserialize_value_into(val, partial)?;
635 partial = partial.end()?;
636 } else {
637 partial = deserialize_value_into(val, partial)?;
638 }
639 #[cfg(not(feature = "alloc"))]
640 {
641 partial = deserialize_value_into(val, partial)?;
642 }
643 partial = partial.end()?;
644 fields_set[idx] = true;
645 } else if deny_unknown_fields {
646 return Err(ValueError::new(ValueErrorKind::UnknownField {
647 field: key_str.to_string(),
648 }));
649 }
650 }
652
653 for (idx, field) in struct_def.fields.iter().enumerate() {
655 if fields_set[idx] {
656 continue;
657 }
658
659 partial = partial
661 .set_nth_field_to_default(idx)
662 .map_err(|_| ValueError::new(ValueErrorKind::MissingField { field: field.name }))?;
663 }
664
665 Ok(partial)
666}
667
668fn deserialize_struct_with_flatten<'facet>(
670 obj: &crate::VObject,
671 mut partial: Partial<'facet, false>,
672 struct_def: &'static facet_core::StructType,
673 deny_unknown_fields: bool,
674) -> Result<Partial<'facet, false>> {
675 use alloc::collections::BTreeMap;
676
677 let num_fields = struct_def.fields.len();
678 let mut fields_set = alloc::vec![false; num_fields];
679
680 let mut flatten_keys: BTreeMap<&str, (usize, &str)> = BTreeMap::new();
683
684 for (idx, field) in struct_def.fields.iter().enumerate() {
686 if !field.is_flattened() {
687 continue;
688 }
689
690 let inner_shape = field.shape.get();
692 if let Type::User(UserType::Struct(inner_struct)) = &inner_shape.ty {
693 for inner_field in inner_struct.fields.iter() {
694 let key_name = inner_field.rename.unwrap_or(inner_field.name);
696 flatten_keys.insert(key_name, (idx, inner_field.name));
697 }
698 }
699 }
700
701 let mut flatten_values: Vec<BTreeMap<String, Value>> =
703 (0..num_fields).map(|_| BTreeMap::new()).collect();
704
705 for (key, val) in obj.iter() {
707 let key_str = key.as_str();
708
709 let direct_field = struct_def.fields.iter().enumerate().find(|(_, f)| {
711 !f.is_flattened() && (f.effective_name() == key_str || f.alias == Some(key_str))
712 });
713
714 if let Some((idx, field)) = direct_field {
715 partial = partial.begin_field(field.name)?;
716 #[cfg(feature = "alloc")]
718 if field.proxy_convert_in_fn().is_some() {
719 partial = partial.begin_custom_deserialization()?;
720 partial = deserialize_value_into(val, partial)?;
721 partial = partial.end()?;
722 } else {
723 partial = deserialize_value_into(val, partial)?;
724 }
725 #[cfg(not(feature = "alloc"))]
726 {
727 partial = deserialize_value_into(val, partial)?;
728 }
729 partial = partial.end()?;
730 fields_set[idx] = true;
731 continue;
732 }
733
734 if let Some(&(flatten_idx, inner_name)) = flatten_keys.get(key_str) {
736 flatten_values[flatten_idx].insert(inner_name.to_string(), val.clone());
737 fields_set[flatten_idx] = true;
738 continue;
739 }
740
741 if deny_unknown_fields {
743 return Err(ValueError::new(ValueErrorKind::UnknownField {
744 field: key_str.to_string(),
745 }));
746 }
747 }
749
750 for (idx, field) in struct_def.fields.iter().enumerate() {
752 if !field.is_flattened() {
753 continue;
754 }
755
756 if !flatten_values[idx].is_empty() {
757 let mut synthetic_obj = crate::VObject::new();
759 let values = core::mem::take(&mut flatten_values[idx]);
760 for (k, v) in values {
761 synthetic_obj.insert(k, v);
762 }
763 let synthetic_value = Value::from(synthetic_obj);
764
765 partial = partial.begin_field(field.name)?;
766 partial = deserialize_value_into(&synthetic_value, partial)?;
767 partial = partial.end()?;
768 fields_set[idx] = true;
769 }
770 }
771
772 for (idx, field) in struct_def.fields.iter().enumerate() {
774 if fields_set[idx] {
775 continue;
776 }
777
778 partial = partial
780 .set_nth_field_to_default(idx)
781 .map_err(|_| ValueError::new(ValueErrorKind::MissingField { field: field.name }))?;
782 }
783
784 Ok(partial)
785}
786
787fn deserialize_tuple<'facet>(
789 value: &Value,
790 partial: Partial<'facet, false>,
791) -> Result<Partial<'facet, false>> {
792 let mut partial = partial;
793 let arr = value.as_array().ok_or_else(|| {
794 ValueError::new(ValueErrorKind::TypeMismatch {
795 expected: "array",
796 got: value.value_type(),
797 })
798 })?;
799
800 let tuple_len = match &partial.shape().ty {
801 Type::User(UserType::Struct(struct_def)) => struct_def.fields.len(),
802 _ => {
803 return Err(ValueError::new(ValueErrorKind::Unsupported {
804 message: "expected tuple type".into(),
805 }));
806 }
807 };
808
809 if arr.len() != tuple_len {
810 return Err(ValueError::new(ValueErrorKind::Unsupported {
811 message: format!("tuple has {} elements but got {}", tuple_len, arr.len()),
812 }));
813 }
814
815 for (i, item) in arr.iter().enumerate() {
816 partial = partial.begin_nth_field(i)?;
817 partial = deserialize_value_into(item, partial)?;
818 partial = partial.end()?;
819 }
820
821 Ok(partial)
822}
823
824fn deserialize_enum<'facet>(
826 value: &Value,
827 partial: Partial<'facet, false>,
828) -> Result<Partial<'facet, false>> {
829 let shape = partial.shape();
830
831 let tag_key = shape.get_tag_attr();
832 let content_key = shape.get_content_attr();
833
834 if shape.is_numeric() && tag_key.is_none() {
836 return deserialize_numeric_enum(value, partial);
837 }
838
839 if shape.is_untagged() {
840 return deserialize_untagged_enum(value, partial);
841 }
842
843 match (tag_key, content_key) {
844 (Some(tag_key), None) => deserialize_internally_tagged_enum(value, partial, tag_key),
846 (Some(tag_key), Some(content_key)) => {
848 deserialize_adjacently_tagged_enum(value, partial, tag_key, content_key)
849 }
850 (None, None) => deserialize_externally_tagged_enum(value, partial),
852 (None, Some(_)) => Err(ValueError::new(ValueErrorKind::Unsupported {
854 message: "content key without tag key is invalid".into(),
855 })),
856 }
857}
858
859fn deserialize_numeric_enum<'facet>(
866 value: &Value,
867 mut partial: Partial<'facet, false>,
868) -> Result<Partial<'facet, false>> {
869 let discriminant = match value.value_type() {
870 ValueType::Number => {
871 let num = value.as_number().unwrap();
872 if let Some(i) = num.to_i64() {
873 i
874 } else {
875 return Err(ValueError::new(ValueErrorKind::TypeMismatch {
876 expected: "Could not parse discriminant into i64", got: ValueType::Number,
878 }));
879 }
880 }
881 ValueType::String => {
882 let s = value.as_string().unwrap().as_str();
884 s.parse().map_err(|_| {
885 ValueError::new(ValueErrorKind::TypeMismatch {
886 expected: "Failed to parse string into i64",
887 got: ValueType::String,
888 })
889 })?
890 }
891 other => {
892 return Err(ValueError::new(ValueErrorKind::TypeMismatch {
893 expected: "Expected number or string for numeric enum",
894 got: other,
895 }));
896 }
897 };
898
899 partial = partial.select_variant(discriminant)?;
900 Ok(partial)
901}
902
903fn deserialize_externally_tagged_enum<'facet>(
905 value: &Value,
906 mut partial: Partial<'facet, false>,
907) -> Result<Partial<'facet, false>> {
908 match value.value_type() {
909 ValueType::String => {
911 let variant_name = value.as_string().unwrap().as_str();
912 partial = partial.select_variant_named(variant_name)?;
913 Ok(partial)
914 }
915 ValueType::Object => {
917 let obj = value.as_object().unwrap();
918 if obj.len() != 1 {
919 return Err(ValueError::new(ValueErrorKind::Unsupported {
920 message: format!("enum object must have exactly 1 key, got {}", obj.len()),
921 }));
922 }
923
924 let (key, val) = obj.iter().next().unwrap();
925 let variant_name = key.as_str();
926
927 partial = partial.select_variant_named(variant_name)?;
928
929 let variant = partial.selected_variant().ok_or_else(|| {
930 ValueError::new(ValueErrorKind::Unsupported {
931 message: "failed to get selected variant".into(),
932 })
933 })?;
934
935 populate_variant_from_value(val, partial, &variant)
936 }
937 other => Err(ValueError::new(ValueErrorKind::TypeMismatch {
938 expected: "string or object for enum",
939 got: other,
940 })),
941 }
942}
943
944fn deserialize_internally_tagged_enum<'facet>(
946 value: &Value,
947 mut partial: Partial<'facet, false>,
948 tag_key: &str,
949) -> Result<Partial<'facet, false>> {
950 let obj = value.as_object().ok_or_else(|| {
951 ValueError::new(ValueErrorKind::TypeMismatch {
952 expected: "object for internally tagged enum",
953 got: value.value_type(),
954 })
955 })?;
956
957 let tag_value = obj.get(tag_key).ok_or_else(|| {
959 ValueError::new(ValueErrorKind::Unsupported {
960 message: format!("internally tagged enum missing tag key '{tag_key}'"),
961 })
962 })?;
963
964 if partial.shape().is_numeric() {
965 let discriminant = tag_value
966 .as_number()
967 .and_then(VNumber::to_i64)
968 .ok_or_else(|| {
969 ValueError::new(ValueErrorKind::TypeMismatch {
970 expected: "integer for enum discriminant",
971 got: tag_value.value_type(),
972 })
973 })?;
974 partial = partial.select_variant(discriminant)?;
975 } else {
976 let variant_name = tag_value.as_string().ok_or_else(|| {
977 ValueError::new(ValueErrorKind::TypeMismatch {
978 expected: "string for enum tag",
979 got: tag_value.value_type(),
980 })
981 })?;
982 partial = partial.select_variant_named(variant_name.as_str())?;
983 }
984
985 let variant = partial.selected_variant().ok_or_else(|| {
986 ValueError::new(ValueErrorKind::Unsupported {
987 message: "failed to get selected variant".into(),
988 })
989 })?;
990
991 match variant.data.kind {
993 StructKind::Unit => {
994 Ok(partial)
996 }
997 StructKind::Struct => {
998 for field in variant.data.fields.iter() {
1000 if let Some(field_value) = obj
1001 .get(field.effective_name())
1002 .or_else(|| field.alias.and_then(|alias| obj.get(alias)))
1003 {
1004 partial = partial.begin_field(field.name)?;
1005 partial = deserialize_enum_field_value(field_value, field, partial)?;
1006 partial = partial.end()?;
1007 }
1008 }
1009 Ok(partial)
1010 }
1011 StructKind::TupleStruct | StructKind::Tuple => {
1012 Err(ValueError::new(ValueErrorKind::Unsupported {
1013 message: "internally tagged tuple variants are not supported".into(),
1014 }))
1015 }
1016 }
1017}
1018
1019fn deserialize_adjacently_tagged_enum<'facet>(
1021 value: &Value,
1022 mut partial: Partial<'facet, false>,
1023 tag_key: &str,
1024 content_key: &str,
1025) -> Result<Partial<'facet, false>> {
1026 let obj = value.as_object().ok_or_else(|| {
1027 ValueError::new(ValueErrorKind::TypeMismatch {
1028 expected: "object for adjacently tagged enum",
1029 got: value.value_type(),
1030 })
1031 })?;
1032
1033 let tag_value = obj.get(tag_key).ok_or_else(|| {
1035 ValueError::new(ValueErrorKind::Unsupported {
1036 message: format!("adjacently tagged enum missing tag key '{tag_key}'"),
1037 })
1038 })?;
1039
1040 if partial.shape().is_numeric() {
1041 let discriminant = tag_value
1042 .as_number()
1043 .and_then(VNumber::to_i64)
1044 .ok_or_else(|| {
1045 ValueError::new(ValueErrorKind::TypeMismatch {
1046 expected: "integer for enum discriminant",
1047 got: tag_value.value_type(),
1048 })
1049 })?;
1050 partial = partial.select_variant(discriminant)?;
1051 } else {
1052 let variant_name = tag_value.as_string().ok_or_else(|| {
1053 ValueError::new(ValueErrorKind::TypeMismatch {
1054 expected: "string for enum tag",
1055 got: tag_value.value_type(),
1056 })
1057 })?;
1058 partial = partial.select_variant_named(variant_name.as_str())?;
1059 }
1060
1061 let variant = partial.selected_variant().ok_or_else(|| {
1062 ValueError::new(ValueErrorKind::Unsupported {
1063 message: "failed to get selected variant".into(),
1064 })
1065 })?;
1066
1067 match variant.data.kind {
1069 StructKind::Unit => {
1070 Ok(partial)
1072 }
1073 _ => {
1074 let content_value = obj.get(content_key).ok_or_else(|| {
1076 ValueError::new(ValueErrorKind::Unsupported {
1077 message: format!("adjacently tagged enum missing content key '{content_key}'"),
1078 })
1079 })?;
1080
1081 populate_variant_from_value(content_value, partial, &variant)
1082 }
1083 }
1084}
1085
1086fn deserialize_untagged_enum<'facet>(
1087 value: &Value,
1088 partial: Partial<'facet, false>,
1089) -> Result<Partial<'facet, false>> {
1090 let mut partial = partial;
1091 let shape = partial.shape();
1092 let enum_type = match &shape.ty {
1093 Type::User(UserType::Enum(enum_def)) => enum_def,
1094 _ => {
1095 return Err(ValueError::new(ValueErrorKind::Unsupported {
1096 message: "expected enum type".into(),
1097 }));
1098 }
1099 };
1100
1101 for variant in enum_type.variants.iter() {
1102 if value_matches_variant(value, variant) {
1103 partial = partial.select_variant_named(variant.effective_name())?;
1104 return populate_variant_from_value(value, partial, variant);
1105 }
1106 }
1107
1108 Err(ValueError::new(ValueErrorKind::TypeMismatch {
1109 expected: shape.type_identifier,
1110 got: value.value_type(),
1111 }))
1112}
1113
1114fn populate_variant_from_value<'facet>(
1115 value: &Value,
1116 mut partial: Partial<'facet, false>,
1117 variant: &Variant,
1118) -> Result<Partial<'facet, false>> {
1119 match variant.data.kind {
1120 StructKind::Unit => {
1121 if !matches!(value.value_type(), ValueType::Null) {
1122 return Err(ValueError::new(ValueErrorKind::TypeMismatch {
1123 expected: "null for unit variant",
1124 got: value.value_type(),
1125 }));
1126 }
1127 }
1128 StructKind::TupleStruct | StructKind::Tuple => {
1129 let num_fields = variant.data.fields.len();
1130 if num_fields == 0 {
1131 } else if num_fields == 1 {
1133 let field = variant.data.fields[0];
1134 partial = partial.begin_nth_field(0)?;
1135 partial = deserialize_enum_field_value(value, &field, partial)?;
1136 partial = partial.end()?;
1137 } else {
1138 let arr = value.as_array().ok_or_else(|| {
1139 ValueError::new(ValueErrorKind::TypeMismatch {
1140 expected: "array for tuple variant",
1141 got: value.value_type(),
1142 })
1143 })?;
1144
1145 if arr.len() != num_fields {
1146 return Err(ValueError::new(ValueErrorKind::Unsupported {
1147 message: format!(
1148 "tuple variant has {} fields but got {}",
1149 num_fields,
1150 arr.len()
1151 ),
1152 }));
1153 }
1154
1155 for (i, (field, item)) in variant.data.fields.iter().zip(arr.iter()).enumerate() {
1156 partial = partial.begin_nth_field(i)?;
1157 partial = deserialize_enum_field_value(item, field, partial)?;
1158 partial = partial.end()?;
1159 }
1160 }
1161 }
1162 StructKind::Struct => {
1163 let inner_obj = value.as_object().ok_or_else(|| {
1164 ValueError::new(ValueErrorKind::TypeMismatch {
1165 expected: "object for struct variant",
1166 got: value.value_type(),
1167 })
1168 })?;
1169
1170 for (field_key, field_val) in inner_obj.iter() {
1171 let key = field_key.as_str();
1172 let field = variant
1173 .data
1174 .fields
1175 .iter()
1176 .find(|f| f.effective_name() == key || f.alias == Some(key))
1177 .ok_or_else(|| {
1178 ValueError::new(ValueErrorKind::UnknownField {
1179 field: key.to_string(),
1180 })
1181 })?;
1182
1183 partial = partial.begin_field(field.name)?;
1184 partial = deserialize_enum_field_value(field_val, field, partial)?;
1185 partial = partial.end()?;
1186 }
1187 }
1188 }
1189
1190 Ok(partial)
1191}
1192
1193fn deserialize_enum_field_value<'facet>(
1194 value: &Value,
1195 field: &Field,
1196 mut partial: Partial<'facet, false>,
1197) -> Result<Partial<'facet, false>> {
1198 #[cfg(feature = "alloc")]
1199 if field.proxy_convert_in_fn().is_some() {
1200 partial = partial.begin_custom_deserialization()?;
1201 partial = deserialize_value_into(value, partial)?;
1202 partial = partial.end()?;
1203 } else {
1204 partial = deserialize_value_into(value, partial)?;
1205 }
1206
1207 #[cfg(not(feature = "alloc"))]
1208 {
1209 partial = deserialize_value_into(value, partial)?;
1210 }
1211
1212 Ok(partial)
1213}
1214
1215fn value_matches_variant(value: &Value, variant: &Variant) -> bool {
1216 match variant.data.kind {
1217 StructKind::Unit => matches!(value.value_type(), ValueType::Null),
1218 StructKind::TupleStruct | StructKind::Tuple => {
1219 let fields = variant.data.fields;
1220 if fields.is_empty() {
1221 matches!(value.value_type(), ValueType::Null)
1222 } else if fields.len() == 1 {
1223 value_matches_shape(value, fields[0].shape.get())
1224 } else {
1225 value
1226 .as_array()
1227 .map(|arr| arr.len() == fields.len())
1228 .unwrap_or(false)
1229 }
1230 }
1231 StructKind::Struct => matches!(value.value_type(), ValueType::Object),
1232 }
1233}
1234
1235fn value_matches_shape(value: &Value, shape: &'static Shape) -> bool {
1236 match &shape.ty {
1237 Type::Primitive(PrimitiveType::Boolean) => {
1238 matches!(value.value_type(), ValueType::Bool)
1239 }
1240 Type::Primitive(PrimitiveType::Numeric(num)) => match num {
1241 NumericType::Integer { signed } => {
1242 if *signed {
1243 value.as_number().and_then(|n| n.to_i64()).is_some()
1244 } else {
1245 value.as_number().and_then(|n| n.to_u64()).is_some()
1246 }
1247 }
1248 NumericType::Float => value.as_number().and_then(|n| n.to_f64()).is_some(),
1249 },
1250 _ => true,
1251 }
1252}
1253
1254fn deserialize_list<'facet>(
1256 value: &Value,
1257 partial: Partial<'facet, false>,
1258) -> Result<Partial<'facet, false>> {
1259 let mut partial = partial;
1260 let arr = value.as_array().ok_or_else(|| {
1261 ValueError::new(ValueErrorKind::TypeMismatch {
1262 expected: "array",
1263 got: value.value_type(),
1264 })
1265 })?;
1266
1267 partial = partial.init_list()?;
1268
1269 for item in arr.iter() {
1270 partial = partial.begin_list_item()?;
1271 partial = deserialize_value_into(item, partial)?;
1272 partial = partial.end()?;
1273 }
1274
1275 Ok(partial)
1276}
1277
1278fn deserialize_array<'facet>(
1280 value: &Value,
1281 partial: Partial<'facet, false>,
1282) -> Result<Partial<'facet, false>> {
1283 let mut partial = partial;
1284 let arr = value.as_array().ok_or_else(|| {
1285 ValueError::new(ValueErrorKind::TypeMismatch {
1286 expected: "array",
1287 got: value.value_type(),
1288 })
1289 })?;
1290
1291 let array_len = match &partial.shape().def {
1292 Def::Array(arr_def) => arr_def.n,
1293 _ => {
1294 return Err(ValueError::new(ValueErrorKind::Unsupported {
1295 message: "expected array type".into(),
1296 }));
1297 }
1298 };
1299
1300 if arr.len() != array_len {
1301 return Err(ValueError::new(ValueErrorKind::Unsupported {
1302 message: format!(
1303 "fixed array has {} elements but got {}",
1304 array_len,
1305 arr.len()
1306 ),
1307 }));
1308 }
1309
1310 for (i, item) in arr.iter().enumerate() {
1311 partial = partial.begin_nth_field(i)?;
1312 partial = deserialize_value_into(item, partial)?;
1313 partial = partial.end()?;
1314 }
1315
1316 Ok(partial)
1317}
1318
1319fn deserialize_set<'facet>(
1321 value: &Value,
1322 partial: Partial<'facet, false>,
1323) -> Result<Partial<'facet, false>> {
1324 let mut partial = partial;
1325 let arr = value.as_array().ok_or_else(|| {
1326 ValueError::new(ValueErrorKind::TypeMismatch {
1327 expected: "array",
1328 got: value.value_type(),
1329 })
1330 })?;
1331
1332 partial = partial.init_set()?;
1333
1334 for item in arr.iter() {
1335 partial = partial.begin_set_item()?;
1336 partial = deserialize_value_into(item, partial)?;
1337 partial = partial.end()?;
1338 }
1339
1340 Ok(partial)
1341}
1342
1343fn deserialize_map<'facet>(
1345 value: &Value,
1346 partial: Partial<'facet, false>,
1347) -> Result<Partial<'facet, false>> {
1348 let mut partial = partial;
1349 let obj = value.as_object().ok_or_else(|| {
1350 ValueError::new(ValueErrorKind::TypeMismatch {
1351 expected: "object",
1352 got: value.value_type(),
1353 })
1354 })?;
1355
1356 partial = partial.init_map()?;
1357
1358 for (key, val) in obj.iter() {
1359 partial = partial.begin_key()?;
1361 if partial.shape().inner.is_some() {
1364 partial = partial.begin_inner()?;
1365 partial = partial.set(key.as_str().to_string())?;
1366 partial = partial.end()?;
1367 } else {
1368 partial = partial.set(key.as_str().to_string())?;
1369 }
1370 partial = partial.end()?;
1371
1372 partial = partial.begin_value()?;
1374 partial = deserialize_value_into(val, partial)?;
1375 partial = partial.end()?;
1376 }
1377
1378 Ok(partial)
1379}
1380
1381fn deserialize_option<'facet>(
1383 value: &Value,
1384 partial: Partial<'facet, false>,
1385) -> Result<Partial<'facet, false>> {
1386 let mut partial = partial;
1387 if value.is_null() {
1388 partial = partial.set_default()?; } else {
1390 partial = partial.begin_some()?;
1391 partial = deserialize_value_into(value, partial)?;
1392 partial = partial.end()?;
1393 }
1394 Ok(partial)
1395}
1396
1397fn deserialize_pointer<'facet>(
1399 value: &Value,
1400 partial: Partial<'facet, false>,
1401) -> Result<Partial<'facet, false>> {
1402 use facet_core::{KnownPointer, SequenceType};
1403
1404 let mut partial = partial;
1405 let (is_slice_pointer, is_reference, is_cow) =
1406 if let Def::Pointer(ptr_def) = partial.shape().def {
1407 let is_slice = if let Some(pointee) = ptr_def.pointee() {
1408 matches!(pointee.ty, Type::Sequence(SequenceType::Slice(_)))
1409 } else {
1410 false
1411 };
1412 let is_ref = matches!(
1413 ptr_def.known,
1414 Some(KnownPointer::SharedReference | KnownPointer::ExclusiveReference)
1415 );
1416 let is_cow = matches!(ptr_def.known, Some(KnownPointer::Cow));
1417 (is_slice, is_ref, is_cow)
1418 } else {
1419 (false, false, false)
1420 };
1421
1422 if is_reference {
1424 return Err(ValueError::new(ValueErrorKind::Unsupported {
1425 message: format!(
1426 "cannot deserialize into reference type '{}'",
1427 partial.shape().type_identifier
1428 ),
1429 }));
1430 }
1431
1432 if is_cow {
1434 if let Def::Pointer(ptr_def) = partial.shape().def
1436 && let Some(pointee) = ptr_def.pointee()
1437 && matches!(
1438 pointee.ty,
1439 Type::Primitive(PrimitiveType::Textual(TextualType::Str))
1440 )
1441 {
1442 if let Some(s) = value.as_string() {
1444 partial = partial.set(alloc::borrow::Cow::<'static, str>::Owned(
1446 s.as_str().to_string(),
1447 ))?;
1448 return Ok(partial);
1449 } else {
1450 return Err(ValueError::new(ValueErrorKind::TypeMismatch {
1451 expected: "string for Cow<str>",
1452 got: value.value_type(),
1453 }));
1454 }
1455 }
1456 partial = partial.begin_inner()?;
1458 partial = deserialize_value_into(value, partial)?;
1459 partial = partial.end()?;
1460 return Ok(partial);
1461 }
1462
1463 partial = partial.begin_smart_ptr()?;
1464
1465 if is_slice_pointer {
1466 let arr = value.as_array().ok_or_else(|| {
1468 ValueError::new(ValueErrorKind::TypeMismatch {
1469 expected: "array",
1470 got: value.value_type(),
1471 })
1472 })?;
1473
1474 for item in arr.iter() {
1475 partial = partial.begin_list_item()?;
1476 partial = deserialize_value_into(item, partial)?;
1477 partial = partial.end()?;
1478 }
1479 } else {
1480 partial = deserialize_value_into(value, partial)?;
1482 }
1483
1484 partial = partial.end()?;
1485 Ok(partial)
1486}
1487
1488#[cfg(test)]
1489mod tests {
1490 use super::*;
1491 use crate::{VArray, VObject, VString};
1492
1493 #[test]
1494 fn test_deserialize_primitives() {
1495 let v = Value::TRUE;
1497 let b: bool = from_value(v).unwrap();
1498 assert!(b);
1499
1500 let v = Value::from(42i64);
1502 let n: i32 = from_value(v).unwrap();
1503 assert_eq!(n, 42);
1504
1505 let v: Value = VString::new("hello").into();
1507 let s: String = from_value(v).unwrap();
1508 assert_eq!(s, "hello");
1509 }
1510
1511 #[test]
1512 fn test_deserialize_option() {
1513 let v = Value::from(42i64);
1515 let opt: Option<i32> = from_value(v).unwrap();
1516 assert_eq!(opt, Some(42));
1517
1518 let v = Value::NULL;
1520 let opt: Option<i32> = from_value(v).unwrap();
1521 assert_eq!(opt, None);
1522 }
1523
1524 #[test]
1525 fn test_deserialize_vec() {
1526 let mut arr = VArray::new();
1527 arr.push(Value::from(1i64));
1528 arr.push(Value::from(2i64));
1529 arr.push(Value::from(3i64));
1530
1531 let v: Value = arr.into();
1532 let vec: alloc::vec::Vec<i32> = from_value(v).unwrap();
1533 assert_eq!(vec, alloc::vec![1, 2, 3]);
1534 }
1535
1536 #[test]
1537 fn test_deserialize_nested() {
1538 let mut arr = VArray::new();
1540 arr.push(Value::from(1i64));
1541 arr.push(Value::NULL);
1542 arr.push(Value::from(3i64));
1543
1544 let v: Value = arr.into();
1545 let vec: alloc::vec::Vec<Option<i32>> = from_value(v).unwrap();
1546 assert_eq!(vec, alloc::vec![Some(1), None, Some(3)]);
1547 }
1548
1549 #[test]
1550 fn test_deserialize_map() {
1551 use alloc::collections::BTreeMap;
1552
1553 let mut obj = VObject::new();
1554 obj.insert("a", Value::from(1i64));
1555 obj.insert("b", Value::from(2i64));
1556
1557 let v: Value = obj.into();
1558 let map: BTreeMap<String, i32> = from_value(v).unwrap();
1559 assert_eq!(map.get("a"), Some(&1));
1560 assert_eq!(map.get("b"), Some(&2));
1561 }
1562}