1use alloc::string::String;
2
3use cgp::core::field::traits::StaticString;
4use cgp::extra::field::impls::{FinalizeOptional, HasOptionalBuilder, SetOptional};
5use cgp::prelude::*;
6use serde::de::{Error, IgnoredAny, MapAccess, Visitor};
7
8use crate::components::{CanDeserializeValue, ValueDeserializer, ValueDeserializerComponent};
9use crate::types::DeserializeWithContext;
10
11pub struct DeserializeRecordFields;
12
13#[cgp_impl(DeserializeRecordFields)]
14impl<'de, Record, Builder> ValueDeserializer<'de, Record>
15where
16 Record: HasOptionalBuilder<Builder = Builder> + HasFields,
17 Record::Fields: HandleMapEntry<'de, Self, Builder>,
18 Builder: FinalizeOptional<Target = Record>,
19{
20 fn deserialize<D>(&self, deserializer: D) -> Result<Record, D::Error>
21 where
22 D: serde::Deserializer<'de>,
23 {
24 deserializer.deserialize_map(MapVisitor {
25 context: self,
26 phantom: PhantomData,
27 })
28 }
29}
30
31struct MapVisitor<'a, Context, Record> {
32 context: &'a Context,
33 phantom: PhantomData<Record>,
34}
35
36impl<'de, 'a, Context, Record, Builder> Visitor<'de> for MapVisitor<'a, Context, Record>
37where
38 Record: HasOptionalBuilder<Builder = Builder> + HasFields,
39 Record::Fields: HandleMapEntry<'de, Context, Builder>,
40 Builder: FinalizeOptional<Target = Record>,
41{
42 type Value = Record;
43
44 fn expecting(&self, formatter: &mut alloc::fmt::Formatter) -> alloc::fmt::Result {
45 write!(formatter, "map")
46 }
47
48 fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
49 where
50 M: MapAccess<'de>,
51 {
52 let mut builder = Record::optional_builder();
53
54 while let Some(key) = map.next_key::<String>()? {
55 builder = Record::Fields::handle_map_entry(&mut map, &key, self.context, builder)?;
56 }
57
58 let value = builder
59 .finalize_optional()
60 .map_err(|field| M::Error::custom(format_args!("missing field: {field}")))?;
61
62 Ok(value)
63 }
64}
65
66trait HandleMapEntry<'de, Context, Builder> {
67 fn handle_map_entry<M: MapAccess<'de>>(
68 map: &mut M,
69 key: &str,
70 context: &Context,
71 builder: Builder,
72 ) -> Result<Builder, M::Error>;
73}
74
75impl<'de, Context, Builder, Tag, Value, Tail> HandleMapEntry<'de, Context, Builder>
76 for Cons<Field<Tag, Value>, Tail>
77where
78 Tag: StaticString,
79 Tail: HandleMapEntry<'de, Context, Builder>,
80 Context: CanDeserializeValue<'de, Value>,
81 Builder: SetOptional<Tag, Value = Value>,
82{
83 fn handle_map_entry<M: MapAccess<'de>>(
84 map: &mut M,
85 key: &str,
86 context: &Context,
87 builder: Builder,
88 ) -> Result<Builder, M::Error> {
89 if key == Tag::VALUE {
90 let value = map.next_value_seed(DeserializeWithContext {
91 context,
92 phantom: PhantomData::<Value>,
93 })?;
94
95 let (replaced, builder) = builder.set_optional(PhantomData, value);
96
97 if replaced.is_some() {
98 Err(M::Error::custom(format_args!(
99 "duplicate field: {}",
100 Tag::VALUE,
101 )))
102 } else {
103 Ok(builder)
104 }
105 } else {
106 Tail::handle_map_entry(map, key, context, builder)
107 }
108 }
109}
110
111impl<'de, Context, Builder> HandleMapEntry<'de, Context, Builder> for Nil {
112 fn handle_map_entry<M: MapAccess<'de>>(
113 map: &mut M,
114 _key: &str,
115 _context: &Context,
116 builder: Builder,
117 ) -> Result<Builder, M::Error> {
118 map.next_value::<IgnoredAny>()?;
119
120 Ok(builder)
121 }
122}