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