smart_config/de/
repeated.rs

1//! `Repeated` deserializer for arrays / objects.
2
3use std::{
4    collections::{BTreeMap, BTreeSet, HashMap, HashSet},
5    fmt,
6    hash::{BuildHasher, Hash},
7    marker::PhantomData,
8    sync::Arc,
9};
10
11use serde::de::{DeserializeOwned, Error as DeError};
12
13use crate::{
14    de::{DeserializeContext, DeserializeParam, WellKnown, WellKnownOption},
15    error::{ErrorWithOrigin, LowLevelError},
16    metadata::{BasicTypes, ParamMetadata, TypeDescription},
17    utils::const_eq,
18    value::{Map, StrValue, Value, ValueOrigin, WithOrigin},
19};
20
21/// Deserializer from JSON arrays.
22///
23/// Supports deserializing to [`Vec`], arrays, [`HashSet`], [`BTreeSet`].
24#[derive(Debug)]
25pub struct Repeated<De>(pub De);
26
27impl<De> Repeated<De> {
28    fn deserialize_array<T, C>(
29        &self,
30        mut ctx: DeserializeContext<'_>,
31        param: &'static ParamMetadata,
32        expected_len: Option<usize>,
33    ) -> Result<C, ErrorWithOrigin>
34    where
35        De: DeserializeParam<T>,
36        C: FromIterator<T>,
37    {
38        let deserializer = ctx.current_value_deserializer(param.name)?;
39        let Value::Array(items) = deserializer.value() else {
40            return Err(deserializer.invalid_type("array"));
41        };
42
43        if let Some(expected_len) = expected_len {
44            if items.len() != expected_len {
45                let err = DeError::invalid_length(items.len(), &expected_len.to_string().as_str());
46                return Err(deserializer.enrich_err(err));
47            }
48        }
49
50        let mut has_errors = false;
51        let items = items.iter().enumerate().filter_map(|(i, item)| {
52            let coerced = item.coerce_value_type(De::EXPECTING);
53            let mut child_ctx = ctx.child(&i.to_string(), ctx.location_in_config);
54            let mut child_ctx = child_ctx.patched(coerced.as_ref().unwrap_or(item));
55            match self.0.deserialize_param(child_ctx.borrow(), param) {
56                Ok(val) if !has_errors => Some(val),
57                Ok(_) => None, // Drop the value since it won't be needed anyway
58                Err(err) => {
59                    has_errors = true;
60                    child_ctx.push_error(err);
61                    None
62                }
63            }
64        });
65        let items: C = items.collect();
66
67        if has_errors {
68            let origin = deserializer.origin().clone();
69            Err(ErrorWithOrigin::new(LowLevelError::InvalidArray, origin))
70        } else {
71            Ok(items)
72        }
73    }
74}
75
76macro_rules! impl_serialization_for_repeated {
77    ($param:ty) => {
78        fn deserialize_param(
79            &self,
80            ctx: DeserializeContext<'_>,
81            param: &'static ParamMetadata,
82        ) -> Result<$param, ErrorWithOrigin> {
83            self.deserialize_array(ctx, param, None)
84        }
85
86        fn serialize_param(&self, param: &$param) -> serde_json::Value {
87            let array = param
88                .iter()
89                .map(|item| self.0.serialize_param(item))
90                .collect();
91            serde_json::Value::Array(array)
92        }
93    };
94}
95
96impl<T: 'static, De> DeserializeParam<Vec<T>> for Repeated<De>
97where
98    De: DeserializeParam<T>,
99{
100    const EXPECTING: BasicTypes = BasicTypes::ARRAY;
101
102    fn describe(&self, description: &mut TypeDescription) {
103        description.set_items(&self.0);
104    }
105
106    impl_serialization_for_repeated!(Vec<T>);
107}
108
109impl<T, S, De> DeserializeParam<HashSet<T, S>> for Repeated<De>
110where
111    T: 'static + Eq + Hash,
112    S: 'static + Default + BuildHasher,
113    De: DeserializeParam<T>,
114{
115    const EXPECTING: BasicTypes = BasicTypes::ARRAY;
116
117    fn describe(&self, description: &mut TypeDescription) {
118        description.set_details("set").set_items(&self.0);
119    }
120
121    impl_serialization_for_repeated!(HashSet<T, S>);
122}
123
124impl<T, De> DeserializeParam<BTreeSet<T>> for Repeated<De>
125where
126    T: 'static + Eq + Ord,
127    De: DeserializeParam<T>,
128{
129    const EXPECTING: BasicTypes = BasicTypes::ARRAY;
130
131    fn describe(&self, description: &mut TypeDescription) {
132        description.set_details("set").set_items(&self.0);
133    }
134
135    impl_serialization_for_repeated!(BTreeSet<T>);
136}
137
138impl<T: 'static, De, const N: usize> DeserializeParam<[T; N]> for Repeated<De>
139where
140    De: DeserializeParam<T>,
141{
142    const EXPECTING: BasicTypes = BasicTypes::ARRAY;
143
144    fn describe(&self, description: &mut TypeDescription) {
145        description
146            .set_details(format!("{N}-element array"))
147            .set_items(&self.0);
148    }
149
150    fn deserialize_param(
151        &self,
152        ctx: DeserializeContext<'_>,
153        param: &'static ParamMetadata,
154    ) -> Result<[T; N], ErrorWithOrigin> {
155        let items: Vec<_> = self.deserialize_array(ctx, param, Some(N))?;
156        // `unwrap()` is safe due to the length check in `deserialize_inner()`
157        Ok(items.try_into().ok().unwrap())
158    }
159
160    fn serialize_param(&self, param: &[T; N]) -> serde_json::Value {
161        let array = param
162            .iter()
163            .map(|item| self.0.serialize_param(item))
164            .collect();
165        serde_json::Value::Array(array)
166    }
167}
168
169impl<T: WellKnown> WellKnown for Vec<T> {
170    type Deserializer = Repeated<T::Deserializer>;
171    const DE: Self::Deserializer = Repeated(T::DE);
172}
173
174impl<T: WellKnown> WellKnownOption for Vec<T> {}
175
176impl<T: WellKnown, const N: usize> WellKnown for [T; N] {
177    type Deserializer = Repeated<T::Deserializer>;
178    const DE: Self::Deserializer = Repeated(T::DE);
179}
180
181impl<T: WellKnown, const N: usize> WellKnownOption for [T; N] {}
182
183// Heterogeneous tuples don't look like a good idea to mark as well-known because they wouldn't look well-structured
184// (it'd be better to define either multiple params or a struct param).
185
186impl<T, S> WellKnown for HashSet<T, S>
187where
188    T: Eq + Hash + WellKnown,
189    S: 'static + Default + BuildHasher,
190{
191    type Deserializer = Repeated<T::Deserializer>;
192    const DE: Self::Deserializer = Repeated(T::DE);
193}
194
195impl<T, S> WellKnownOption for HashSet<T, S>
196where
197    T: Eq + Hash + WellKnown,
198    S: 'static + Default + BuildHasher,
199{
200}
201
202impl<T> WellKnown for BTreeSet<T>
203where
204    T: Eq + Ord + WellKnown,
205{
206    type Deserializer = Repeated<T::Deserializer>;
207    const DE: Self::Deserializer = Repeated(T::DE);
208}
209
210impl<T> WellKnownOption for BTreeSet<T> where T: Eq + Ord + WellKnown {}
211
212/// Deserializer from JSON objects.
213///
214/// Supports deserializing to [`HashMap`] and [`BTreeMap`].
215pub struct Entries<K, V, DeK = <K as WellKnown>::Deserializer, DeV = <V as WellKnown>::Deserializer>
216{
217    keys: DeK,
218    values: DeV,
219    _kv: PhantomData<fn(K, V)>,
220}
221
222impl<K, V, DeK: fmt::Debug, DeV: fmt::Debug> fmt::Debug for Entries<K, V, DeK, DeV> {
223    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
224        formatter
225            .debug_struct("Entries")
226            .field("keys", &self.keys)
227            .field("values", &self.values)
228            .finish()
229    }
230}
231
232impl<K: WellKnown, V: WellKnown> Entries<K, V, K::Deserializer, V::Deserializer> {
233    /// `Entries` instance using the [`WellKnown`] deserializers for keys and values.
234    pub const WELL_KNOWN: Self = Self::new(K::DE, V::DE);
235}
236
237impl<K, V, DeK, DeV> Entries<K, V, DeK, DeV>
238where
239    DeK: DeserializeParam<K>,
240    DeV: DeserializeParam<V>,
241{
242    /// Creates a new deserializer instance with provided key and value deserializers.
243    pub const fn new(keys: DeK, values: DeV) -> Self {
244        Self {
245            keys,
246            values,
247            _kv: PhantomData,
248        }
249    }
250
251    /// Converts this to a [`NamedEntries`] instance.
252    ///
253    /// # Panics
254    ///
255    ///  Will panic if either `keys_name` or `values_name` is empty OR they coincide
256    pub const fn named(
257        self,
258        keys_name: &'static str,
259        values_name: &'static str,
260    ) -> NamedEntries<K, V, DeK, DeV> {
261        assert!(!keys_name.is_empty());
262        assert!(!values_name.is_empty());
263        assert!(
264            !const_eq(keys_name.as_bytes(), values_name.as_bytes()),
265            "Keys and values fields must not coincide"
266        );
267
268        NamedEntries {
269            inner: self,
270            keys_name,
271            values_name,
272        }
273    }
274
275    fn deserialize_map<C: FromIterator<(K, V)>>(
276        &self,
277        mut ctx: DeserializeContext<'_>,
278        param: &'static ParamMetadata,
279        map: &Map,
280        map_origin: &Arc<ValueOrigin>,
281    ) -> Result<C, ErrorWithOrigin> {
282        let mut has_errors = false;
283        let items = map.iter().filter_map(|(key, value)| {
284            let key_as_value = WithOrigin::new(
285                key.clone().into(),
286                Arc::new(ValueOrigin::Synthetic {
287                    source: map_origin.clone(),
288                    transform: "string key".into(),
289                }),
290            );
291            let parsed_key =
292                parse_key_or_value::<K, _>(&mut ctx, param, key, &self.keys, &key_as_value);
293            let parsed_value =
294                parse_key_or_value::<V, _>(&mut ctx, param, key, &self.values, value);
295
296            has_errors |= parsed_key.is_none() || parsed_value.is_none();
297            Some((parsed_key?, parsed_value?)).filter(|_| !has_errors)
298        });
299        let items: C = items.collect();
300
301        if has_errors {
302            let origin = map_origin.clone();
303            Err(ErrorWithOrigin::new(LowLevelError::InvalidObject, origin))
304        } else {
305            Ok(items)
306        }
307    }
308}
309
310fn parse_key_or_value<T, De: DeserializeParam<T>>(
311    ctx: &mut DeserializeContext<'_>,
312    param: &'static ParamMetadata,
313    key_path: &str,
314    de: &De,
315    val: &WithOrigin,
316) -> Option<T> {
317    let coerced = val.coerce_value_type(De::EXPECTING);
318    let mut child_ctx = ctx.child(key_path, ctx.location_in_config);
319    let mut child_ctx = child_ctx.patched(coerced.as_ref().unwrap_or(val));
320    match de.deserialize_param(child_ctx.borrow(), param) {
321        Ok(val) => Some(val),
322        Err(err) => {
323            child_ctx.push_error(err);
324            None
325        }
326    }
327}
328
329/// Converts a key–value entry into the common format (pair of references to the key and value).
330pub trait ToEntry<'a, K, V>: Copy {
331    /// Performs the conversion.
332    fn to_entry(self) -> (&'a K, &'a V);
333}
334
335impl<'a, K, V> ToEntry<'a, K, V> for &'a (K, V) {
336    fn to_entry(self) -> (&'a K, &'a V) {
337        (&self.0, &self.1)
338    }
339}
340
341impl<'a, K, V> ToEntry<'a, K, V> for (&'a K, &'a V) {
342    fn to_entry(self) -> (&'a K, &'a V) {
343        self
344    }
345}
346
347/// Collection that can iterate over its entries.
348///
349/// Implemented for maps in the standard library, `Vec<(K, V)>`, `Box<[(K, V)]>` etc.
350// Needed as a separate trait with a blank impl since otherwise (if the `&C: IntoIterator<..>` requirement
351// is specified directly on the `DeserializeParam` impls) the compiler explodes, suggesting to specify type params
352// in the proc-macro code.
353pub trait ToEntries<K: 'static, V: 'static> {
354    /// Iterates over entries in the collection.
355    fn to_entries(&self) -> impl Iterator<Item = (&K, &V)>;
356}
357
358// Covers maps
359impl<K: 'static, V: 'static, C> ToEntries<K, V> for C
360where
361    for<'a> &'a C: IntoIterator<Item: ToEntry<'a, K, V>>,
362{
363    fn to_entries(&self) -> impl Iterator<Item = (&K, &V)> {
364        self.into_iter().map(ToEntry::to_entry)
365    }
366}
367
368impl<K, V, C, DeK, DeV> DeserializeParam<C> for Entries<K, V, DeK, DeV>
369where
370    K: 'static,
371    V: 'static,
372    DeK: DeserializeParam<K>,
373    DeV: DeserializeParam<V>,
374    C: FromIterator<(K, V)> + ToEntries<K, V>,
375{
376    const EXPECTING: BasicTypes = {
377        assert!(
378            DeK::EXPECTING.contains(BasicTypes::STRING)
379                || DeK::EXPECTING.contains(BasicTypes::INTEGER),
380            "map keys must be deserializable from strings or ints"
381        );
382        BasicTypes::OBJECT
383    };
384
385    fn describe(&self, description: &mut TypeDescription) {
386        description
387            .set_details("map")
388            .set_entries(&self.keys, &self.values);
389    }
390
391    fn deserialize_param(
392        &self,
393        ctx: DeserializeContext<'_>,
394        param: &'static ParamMetadata,
395    ) -> Result<C, ErrorWithOrigin> {
396        let deserializer = ctx.current_value_deserializer(param.name)?;
397        let Value::Object(map) = deserializer.value() else {
398            return Err(deserializer.invalid_type("object"));
399        };
400        self.deserialize_map(ctx, param, map, deserializer.origin())
401    }
402
403    fn serialize_param(&self, param: &C) -> serde_json::Value {
404        let object = param
405            .to_entries()
406            .map(|(key, value)| {
407                let key = match self.keys.serialize_param(key) {
408                    serde_json::Value::String(s) => s,
409                    serde_json::Value::Number(num) => num.to_string(),
410                    _ => panic!("unsupported key value"),
411                };
412                let value = self.values.serialize_param(value);
413                (key, value)
414            })
415            .collect();
416        serde_json::Value::Object(object)
417    }
418}
419
420impl<K, V, S> WellKnown for HashMap<K, V, S>
421where
422    K: 'static + Eq + Hash + WellKnown,
423    V: 'static + WellKnown,
424    S: 'static + Default + BuildHasher,
425{
426    type Deserializer = Entries<K, V, K::Deserializer, V::Deserializer>;
427    const DE: Self::Deserializer = Entries::new(K::DE, V::DE);
428}
429
430impl<K, V, S> WellKnownOption for HashMap<K, V, S>
431where
432    K: 'static + Eq + Hash + WellKnown,
433    V: 'static + WellKnown,
434    S: 'static + Default + BuildHasher,
435{
436}
437
438impl<K, V> WellKnown for BTreeMap<K, V>
439where
440    K: 'static + Eq + Ord + WellKnown,
441    V: 'static + WellKnown,
442{
443    type Deserializer = Entries<K, V, K::Deserializer, V::Deserializer>;
444    const DE: Self::Deserializer = Entries::new(K::DE, V::DE);
445}
446
447impl<K, V> WellKnownOption for BTreeMap<K, V>
448where
449    K: 'static + Eq + Ord + WellKnown,
450    V: 'static + WellKnown,
451{
452}
453
454/// Deserializer that supports either an array of values, or a string in which values are delimited
455/// by the specified separator.
456///
457/// # Examples
458///
459/// ```
460/// use std::{collections::HashSet, path::PathBuf};
461/// use smart_config::{de, testing, DescribeConfig, DeserializeConfig};
462///
463/// #[derive(DescribeConfig, DeserializeConfig)]
464/// struct TestConfig {
465///     #[config(default, with = de::Delimited(","))]
466///     strings: Vec<String>,
467///     // More complex types are supported as well
468///     #[config(with = de::Delimited(":"))]
469///     paths: Vec<PathBuf>,
470///     // ...and more complex collections (here together with string -> number coercion)
471///     #[config(with = de::Delimited(";"))]
472///     ints: HashSet<u64>,
473/// }
474///
475/// let sample = smart_config::config!(
476///     "strings": ["test", "string"], // standard array value is still supported
477///     "paths": "/usr/bin:/usr/local/bin",
478///     "ints": "12;34;12",
479/// );
480/// let config: TestConfig = testing::test(sample)?;
481/// assert_eq!(config.strings.len(), 2);
482/// assert_eq!(config.strings[0], "test");
483/// assert_eq!(config.paths.len(), 2);
484/// assert_eq!(config.paths[1].as_os_str(), "/usr/local/bin");
485/// assert_eq!(config.ints, HashSet::from([12, 34]));
486/// # anyhow::Ok(())
487/// ```
488///
489/// The wrapping logic is smart enough to catch in compile time an attempt to apply `Delimited` to a type
490/// that cannot be deserialized from an array:
491///
492/// ```compile_fail
493/// use smart_config::{de, DescribeConfig, DeserializeConfig};
494///
495/// #[derive(DescribeConfig, DeserializeConfig)]
496/// struct Fail {
497///     // will fail with "evaluation of `<Delimited as DeserializeParam<u64>>::EXPECTING` failed"
498///     #[config(default, with = de::Delimited(","))]
499///     test: u64,
500/// }
501/// ```
502#[derive(Debug)]
503pub struct Delimited(pub &'static str);
504
505impl<T: DeserializeOwned + WellKnown> DeserializeParam<T> for Delimited {
506    const EXPECTING: BasicTypes = {
507        let base = <T::Deserializer as DeserializeParam<T>>::EXPECTING;
508        assert!(
509            base.contains(BasicTypes::ARRAY),
510            "can only apply `Delimited` to types that support deserialization from array"
511        );
512        base.or(BasicTypes::STRING)
513    };
514
515    fn describe(&self, description: &mut TypeDescription) {
516        T::DE.describe(description);
517        let details = if let Some(details) = description.details() {
518            format!("{details}; using {:?} delimiter", self.0)
519        } else {
520            format!("using {:?} delimiter", self.0)
521        };
522        description.set_details(details);
523    }
524
525    fn deserialize_param(
526        &self,
527        mut ctx: DeserializeContext<'_>,
528        param: &'static ParamMetadata,
529    ) -> Result<T, ErrorWithOrigin> {
530        let Some(WithOrigin {
531            inner: Value::String(s),
532            origin,
533        }) = ctx.current_value()
534        else {
535            return T::DE.deserialize_param(ctx, param);
536        };
537
538        let array_origin = Arc::new(ValueOrigin::Synthetic {
539            source: origin.clone(),
540            transform: format!("{:?}-delimited string", self.0),
541        });
542        let array_items = s.expose().split(self.0).enumerate().map(|(i, part)| {
543            let item_origin = ValueOrigin::Path {
544                source: array_origin.clone(),
545                path: i.to_string(),
546            };
547            let part = if s.is_secret() {
548                StrValue::Secret(part.into())
549            } else {
550                StrValue::Plain(part.into())
551            };
552            WithOrigin::new(Value::String(part), Arc::new(item_origin))
553        });
554        let array = WithOrigin::new(Value::Array(array_items.collect()), array_origin);
555        T::DE.deserialize_param(ctx.patched(&array), param)
556    }
557
558    fn serialize_param(&self, param: &T) -> serde_json::Value {
559        T::DE.serialize_param(param)
560    }
561}
562
563/// Deserializer that supports either a map or an array of `{ key: _, value: _ }` tuples (with customizable
564/// key / value names). Created using [`Entries::named()`].
565///
566/// Unlike [`Entries`], [`NamedEntries`] doesn't require keys to be deserializable from strings (although
567/// if they don't, map inputs will not work).
568///
569/// # Examples
570///
571/// ```
572/// use std::{collections::HashMap, time::Duration};
573/// # use smart_config::{de::Entries, testing, DescribeConfig, DeserializeConfig};
574///
575/// #[derive(DescribeConfig, DeserializeConfig)]
576/// struct TestConfig {
577///     #[config(with = Entries::WELL_KNOWN.named("num", "value"))]
578///     entries: HashMap<u64, String>,
579///     /// Can also be used with "linear" containers with tuple items.
580///     #[config(with = Entries::WELL_KNOWN.named("method", "timeout"))]
581///     tuples: Vec<(String, Duration)>,
582/// }
583///
584/// // Parsing from maps:
585/// let map_input = smart_config::config!(
586///     "entries": serde_json::json!({ "2": "two", "3": "three" }),
587///     "tuples": serde_json::json!({ "getLogs": "2s" }),
588/// );
589/// let config: TestConfig = testing::test(map_input)?;
590/// assert_eq!(
591///     config.entries,
592///     HashMap::from([(2, "two".to_owned()), (3, "three".to_owned())])
593/// );
594/// assert_eq!(
595///     config.tuples,
596///    [("getLogs".to_owned(), Duration::from_secs(2))]
597/// );
598///
599/// // The equivalent input as named tuples:
600/// let tuples_input = smart_config::config!(
601///     "entries": serde_json::json!([
602///         { "num": 2, "value": "two" },
603///         { "num": 3, "value": "three" },
604///     ]),
605///     "tuples": serde_json::json!([
606///         { "method": "getLogs", "timeout": "2s" },
607///     ]),
608/// );
609/// let config: TestConfig = testing::test(tuples_input)?;
610/// # assert_eq!(
611/// #     config.entries,
612/// #     HashMap::from([(2, "two".to_owned()), (3, "three".to_owned())])
613/// # );
614/// # assert_eq!(
615/// #     config.tuples,
616/// #    [("getLogs".to_owned(), Duration::from_secs(2))]
617/// # );
618/// # anyhow::Ok(())
619/// ```
620pub struct NamedEntries<
621    K,
622    V,
623    DeK = <K as WellKnown>::Deserializer,
624    DeV = <V as WellKnown>::Deserializer,
625> {
626    inner: Entries<K, V, DeK, DeV>,
627    keys_name: &'static str,
628    values_name: &'static str,
629}
630
631impl<K, V, DeK: fmt::Debug, DeV: fmt::Debug> fmt::Debug for NamedEntries<K, V, DeK, DeV> {
632    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
633        formatter
634            .debug_struct("NamedEntries")
635            .field("inner", &self.inner)
636            .field("keys_name", &self.keys_name)
637            .field("values_name", &self.values_name)
638            .finish()
639    }
640}
641
642impl<K, V, DeK, DeV> NamedEntries<K, V, DeK, DeV>
643where
644    DeK: DeserializeParam<K>,
645    DeV: DeserializeParam<V>,
646{
647    fn deserialize_entries<C: FromIterator<(K, V)>>(
648        &self,
649        mut ctx: DeserializeContext<'_>,
650        param: &'static ParamMetadata,
651        array: &[WithOrigin],
652        array_origin: &Arc<ValueOrigin>,
653    ) -> Result<C, ErrorWithOrigin> {
654        let mut has_errors = false;
655        let items = array.iter().enumerate().filter_map(|(i, entry)| {
656            let idx_str = i.to_string();
657            let (key, value) = match self.parse_entry(entry) {
658                Ok(entry) => entry,
659                Err(err) => {
660                    ctx.child(&idx_str, ctx.location_in_config).push_error(err);
661                    has_errors = true;
662                    return None;
663                }
664            };
665
666            let parsed_key =
667                parse_key_or_value::<K, _>(&mut ctx, param, &idx_str, &self.inner.keys, key);
668            let null_value;
669            let value = if let Some(value) = value {
670                value
671            } else {
672                let null_origin = ValueOrigin::Synthetic {
673                    source: entry.origin.clone(),
674                    transform: "missing entry value".to_owned(),
675                };
676                null_value = WithOrigin::new(Value::Null, Arc::new(null_origin));
677                &null_value
678            };
679            let parsed_value =
680                parse_key_or_value::<V, _>(&mut ctx, param, &idx_str, &self.inner.values, value);
681            has_errors |= parsed_key.is_none() || parsed_value.is_none();
682            Some((parsed_key?, parsed_value?)).filter(|_| !has_errors)
683        });
684        let items: C = items.collect();
685
686        if has_errors {
687            let origin = array_origin.clone();
688            Err(ErrorWithOrigin::new(LowLevelError::InvalidArray, origin))
689        } else {
690            Ok(items)
691        }
692    }
693
694    fn parse_entry<'a>(
695        &self,
696        entry: &'a WithOrigin,
697    ) -> Result<(&'a WithOrigin, Option<&'a WithOrigin>), ErrorWithOrigin> {
698        let Value::Object(obj) = &entry.inner else {
699            let expected = format!(
700                "{{ {:?}: _, {:?}: _ }} tuple",
701                self.keys_name, self.values_name
702            );
703            return Err(entry.invalid_type(&expected));
704        };
705
706        let key = obj.get(self.keys_name).ok_or_else(|| {
707            let err = DeError::missing_field(self.keys_name);
708            ErrorWithOrigin::json(err, entry.origin.clone())
709        })?;
710        let value = obj.get(self.values_name);
711
712        if obj.len() > 2 {
713            let expected = format!(
714                "{{ {:?}: _, {:?}: _ }} tuple",
715                self.keys_name, self.values_name
716            );
717            return Err(entry.invalid_type(&expected));
718        }
719        Ok((key, value))
720    }
721}
722
723impl<K, V, DeK, DeV, C> DeserializeParam<C> for NamedEntries<K, V, DeK, DeV>
724where
725    K: 'static,
726    V: 'static,
727    DeK: DeserializeParam<K>,
728    DeV: DeserializeParam<V>,
729    C: FromIterator<(K, V)> + ToEntries<K, V>,
730{
731    const EXPECTING: BasicTypes = BasicTypes::OBJECT.or(BasicTypes::ARRAY);
732
733    fn describe(&self, description: &mut TypeDescription) {
734        let details = format!(
735            "map or array of {{ {:?}: _, {:?}: _ }} tuples",
736            self.keys_name, self.values_name
737        );
738        description
739            .set_details(details)
740            .set_entries(&self.inner.keys, &self.inner.values);
741    }
742
743    fn deserialize_param(
744        &self,
745        ctx: DeserializeContext<'_>,
746        param: &'static ParamMetadata,
747    ) -> Result<C, ErrorWithOrigin> {
748        let deserializer = ctx.current_value_deserializer(param.name)?;
749        match deserializer.value() {
750            Value::Object(map) => {
751                self.inner
752                    .deserialize_map(ctx, param, map, deserializer.origin())
753            }
754            Value::Array(array) => {
755                self.deserialize_entries(ctx, param, array, deserializer.origin())
756            }
757            _ => Err(deserializer.invalid_type("object or array")),
758        }
759    }
760
761    fn serialize_param(&self, param: &C) -> serde_json::Value {
762        let entries = param.to_entries().map(|(key, value)| {
763            let key = self.inner.keys.serialize_param(key);
764            let value = self.inner.values.serialize_param(value);
765            serde_json::json!({
766                self.keys_name: key,
767                self.values_name: value,
768            })
769        });
770        serde_json::Value::Array(entries.collect())
771    }
772}