1use 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#[derive(Clone, Debug, PartialEq, Eq)]
53pub enum PathSegment {
54 Field(String),
56 Variant(String),
58 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#[derive(Debug)]
74pub struct ValueError {
75 pub kind: ValueErrorKind,
77 pub source_path: Vec<PathSegment>,
79 pub dest_path: Vec<PathSegment>,
81 pub target_shape: Option<&'static Shape>,
83 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 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 pub fn with_shape(mut self, shape: &'static Shape) -> Self {
111 self.target_shape = Some(shape);
112 self
113 }
114
115 pub fn with_value(mut self, value: Value) -> Self {
117 self.source_value = Some(value);
118 self
119 }
120
121 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 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 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 pub fn into_report(self) -> ValueErrorReport {
164 ValueErrorReport::new(self)
165 }
166}
167
168#[cfg(feature = "diagnostics")]
170struct SourceDiagnostic {
171 source_text: String,
173 source_name: String,
175 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#[cfg(feature = "diagnostics")]
215pub struct ValueErrorReport {
216 error: ValueError,
218 related: Vec<SourceDiagnostic>,
220}
221
222#[cfg(feature = "diagnostics")]
223impl ValueErrorReport {
224 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 if let Some(ref value) = error.source_value {
233 let result = format_value_with_spans(value);
234
235 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 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 if let Some(shape) = error.target_shape {
279 let result = format_shape_with_spans(shape);
280
281 if !result.text.is_empty() {
283 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 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#[derive(Debug)]
368pub enum ValueErrorKind {
369 TypeMismatch {
371 expected: &'static str,
373 got: ValueType,
375 },
376 MissingField {
378 field: &'static str,
380 },
381 UnknownField {
383 field: String,
385 },
386 NumberOutOfRange {
388 message: String,
390 },
391 Reflect(ReflectError),
393 Unsupported {
395 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
429pub type Result<T> = core::result::Result<T, ValueError>;
431
432pub 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
473fn deserialize_value_into<'p>(value: &Value, partial: Partial<'p>) -> Result<Partial<'p>> {
475 let mut partial = partial;
476 let shape = partial.shape();
477
478 if matches!(&shape.def, Def::Option(_)) {
480 return deserialize_option(value, partial);
481 }
482
483 if matches!(&shape.def, Def::Pointer(_)) {
485 return deserialize_pointer(value, partial);
486 }
487
488 #[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 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 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 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 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 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
552fn 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 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 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
613fn 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 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 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
762fn 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 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 let num_fields = struct_def.fields.len();
792 let mut fields_set = alloc::vec![false; num_fields];
793
794 for (key, val) in obj.iter() {
796 let key_str = key.as_str();
797
798 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 #[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 }
829
830 for (idx, field) in struct_def.fields.iter().enumerate() {
832 if fields_set[idx] {
833 continue;
834 }
835
836 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
845fn 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 let mut flatten_keys: BTreeMap<&str, (usize, &str)> = BTreeMap::new();
860
861 for (idx, field) in struct_def.fields.iter().enumerate() {
863 if !field.is_flattened() {
864 continue;
865 }
866
867 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 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 let mut flatten_values: Vec<BTreeMap<String, Value>> =
880 (0..num_fields).map(|_| BTreeMap::new()).collect();
881
882 for (key, val) in obj.iter() {
884 let key_str = key.as_str();
885
886 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 #[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 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 if deny_unknown_fields {
921 return Err(ValueError::new(ValueErrorKind::UnknownField {
922 field: key_str.to_string(),
923 }));
924 }
925 }
927
928 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 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 for (idx, field) in struct_def.fields.iter().enumerate() {
952 if fields_set[idx] {
953 continue;
954 }
955
956 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
965fn 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
999fn 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 (Some(tag_key), None) => deserialize_internally_tagged_enum(value, partial, tag_key),
1013 (Some(tag_key), Some(content_key)) => {
1015 deserialize_adjacently_tagged_enum(value, partial, tag_key, content_key)
1016 }
1017 (None, None) => deserialize_externally_tagged_enum(value, partial),
1019 (None, Some(_)) => Err(ValueError::new(ValueErrorKind::Unsupported {
1021 message: "content key without tag key is invalid".into(),
1022 })),
1023 }
1024}
1025
1026fn deserialize_externally_tagged_enum<'p>(
1028 value: &Value,
1029 mut partial: Partial<'p>,
1030) -> Result<Partial<'p>> {
1031 match value.value_type() {
1032 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 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
1067fn 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 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 match variant.data.kind {
1104 StructKind::Unit => {
1105 Ok(partial)
1107 }
1108 StructKind::Struct => {
1109 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
1127fn 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 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 match variant.data.kind {
1165 StructKind::Unit => {
1166 Ok(partial)
1168 }
1169 _ => {
1170 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 } 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
1312fn 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
1333fn 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
1371fn 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
1392fn 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 partial = partial.begin_key()?;
1407 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 partial = partial.begin_value()?;
1420 partial = deserialize_value_into(val, partial)?;
1421 partial = partial.end()?;
1422 }
1423
1424 Ok(partial)
1425}
1426
1427fn 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()?; } else {
1433 partial = partial.begin_some()?;
1434 partial = deserialize_value_into(value, partial)?;
1435 partial = partial.end()?;
1436 }
1437 Ok(partial)
1438}
1439
1440fn 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 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 if is_cow {
1474 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 if let Some(s) = value.as_string() {
1484 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 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 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 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 let v = Value::TRUE;
1537 let b: bool = from_value(v).unwrap();
1538 assert!(b);
1539
1540 let v = Value::from(42i64);
1542 let n: i32 = from_value(v).unwrap();
1543 assert_eq!(n, 42);
1544
1545 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 let v = Value::from(42i64);
1555 let opt: Option<i32> = from_value(v).unwrap();
1556 assert_eq!(opt, Some(42));
1557
1558 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 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}