Skip to content

Commit bcc23aa

Browse files
bors[bot]jonasbb
andauthored
Merge #566
566: Generalize the trait bounds of `Seq` r=jonasbb a=jonasbb Generalize the trait bounds of `Seq` to allow for more flexible. Instead of forcing the inner type to be a tuple, take anything convertible to/from a tuple. This can be expressed using the Closes #565 Co-authored-by: Jonas Bushart <[email protected]>
2 parents 429f027 + 0c5e7b1 commit bcc23aa

File tree

5 files changed

+182
-33
lines changed

5 files changed

+182
-33
lines changed

serde_with/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
4444
},
4545
```
4646

47+
### Changed
48+
49+
* Relax the trait bounds of `Seq` to allow for more custom types. (#565)
50+
This extends the support beyond tuples.
51+
4752
### Fixed
4853

4954
* `EnumMap` passes the `human_readable` status of the `Serializer` to more places.

serde_with/src/de/impls.rs

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -545,25 +545,23 @@ tuple_impl!(16 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7
545545

546546
#[cfg(feature = "alloc")]
547547
macro_rules! map_as_tuple_seq_intern {
548-
($tyorig:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >, $ty:ident <(KAs, VAs)>) => {
549-
impl<'de, K, KAs, V, VAs> DeserializeAs<'de, $tyorig<K, V>> for $ty<(KAs, VAs)>
548+
($tyorig:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >, $ty:ident <TAs>) => {
549+
impl<'de, K, V, TAs> DeserializeAs<'de, $tyorig<K, V>> for $ty<TAs>
550550
where
551-
KAs: DeserializeAs<'de, K>,
552-
VAs: DeserializeAs<'de, V>,
551+
TAs: DeserializeAs<'de, (K, V)>,
553552
$(K: $kbound1 $(+ $kbound2)*,)*
554553
{
555554
fn deserialize_as<D>(deserializer: D) -> Result<$tyorig<K, V>, D::Error>
556555
where
557556
D: Deserializer<'de>,
558557
{
559-
struct SeqVisitor<K, KAs, V, VAs> {
560-
marker: PhantomData<(K, KAs, V, VAs)>,
558+
struct SeqVisitor<K, V, TAs> {
559+
marker: PhantomData<(K, V, TAs)>,
561560
}
562561

563-
impl<'de, K, KAs, V, VAs> Visitor<'de> for SeqVisitor<K, KAs, V, VAs>
562+
impl<'de, K, V, TAs> Visitor<'de> for SeqVisitor<K, V, TAs>
564563
where
565-
KAs: DeserializeAs<'de, K>,
566-
VAs: DeserializeAs<'de, V>,
564+
TAs: DeserializeAs<'de, (K, V)>,
567565
$(K: $kbound1 $(+ $kbound2)*,)*
568566
{
569567
type Value = $tyorig<K, V>;
@@ -579,17 +577,13 @@ macro_rules! map_as_tuple_seq_intern {
579577
{
580578
let iter = utils::SeqIter::new(access);
581579
iter.map(|res| {
582-
res.map(
583-
|(k, v): (DeserializeAsWrap<K, KAs>, DeserializeAsWrap<V, VAs>)| {
584-
(k.into_inner(), v.into_inner())
585-
},
586-
)
580+
res.map(<DeserializeAsWrap<(K, V), TAs>>::into_inner)
587581
})
588582
.collect()
589583
}
590584
}
591585

592-
let visitor = SeqVisitor::<K, KAs, V, VAs> {
586+
let visitor = SeqVisitor::<K, V, TAs> {
593587
marker: PhantomData,
594588
};
595589
deserializer.deserialize_seq(visitor)
@@ -600,9 +594,9 @@ macro_rules! map_as_tuple_seq_intern {
600594
#[cfg(feature = "alloc")]
601595
macro_rules! map_as_tuple_seq {
602596
($tyorig:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >) => {
603-
map_as_tuple_seq_intern!($tyorig < K $(: $kbound1 $(+ $kbound2)*)* , V $(, $typaram : $bound1 $(+ $bound2)*)* > , Seq<(KAs, VAs)>);
597+
map_as_tuple_seq_intern!($tyorig < K $(: $kbound1 $(+ $kbound2)*)* , V $(, $typaram : $bound1 $(+ $bound2)*)* > , Seq<TAs>);
604598
#[cfg(feature = "alloc")]
605-
map_as_tuple_seq_intern!($tyorig < K $(: $kbound1 $(+ $kbound2)*)* , V $(, $typaram : $bound1 $(+ $bound2)*)* >, Vec<(KAs, VAs)>);
599+
map_as_tuple_seq_intern!($tyorig < K $(: $kbound1 $(+ $kbound2)*)* , V $(, $typaram : $bound1 $(+ $bound2)*)* >, Vec<TAs>);
606600
}
607601
}
608602
foreach_map!(map_as_tuple_seq);

serde_with/src/lib.rs

Lines changed: 85 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2098,9 +2098,6 @@ pub struct StringWithSeparator<Sep, T>(PhantomData<(Sep, T)>);
20982098
/// However, sometimes this is not possible due to type constraints, e.g., if the type implements neither [`Hash`] nor [`Ord`].
20992099
/// Another use case is deserializing a map with duplicate keys.
21002100
///
2101-
/// The implementation is generic using the [`FromIterator`] and [`IntoIterator`] traits.
2102-
/// Therefore, all of [`Vec`], [`VecDeque`](std::collections::VecDeque), and [`LinkedList`](std::collections::LinkedList) and anything which implements those are supported.
2103-
///
21042101
/// # Examples
21052102
///
21062103
/// `Wrapper` does not implement [`Hash`] nor [`Ord`], thus prohibiting the use [`HashMap`] or [`BTreeMap`].
@@ -2149,13 +2146,14 @@ pub struct StringWithSeparator<Sep, T>(PhantomData<(Sep, T)>);
21492146
/// ```
21502147
pub struct Map<K, V>(PhantomData<(K, V)>);
21512148

2152-
/// De/Serialize a Map into a list of tuples
2149+
/// De/Serialize a Map into a list of tuples or custom type
21532150
///
21542151
/// Some formats, like JSON, have limitations on the types of keys for maps.
21552152
/// In case of JSON, keys are restricted to strings.
21562153
/// Rust features more powerful keys, for example tuples, which can not be serialized to JSON.
21572154
///
21582155
/// This helper serializes the Map into a list of tuples, which do not have the same type restrictions.
2156+
/// Other types can be used to, if they implement `SerializeAs<(K, V)>`.
21592157
///
21602158
/// # Examples
21612159
///
@@ -2194,6 +2192,89 @@ pub struct Map<K, V>(PhantomData<(K, V)>);
21942192
/// assert_eq!(data, serde_json::from_value(value).unwrap());
21952193
/// # }
21962194
/// ```
2195+
///
2196+
/// ## Use a custom representation
2197+
///
2198+
/// ```rust
2199+
/// # #[cfg(feature = "macros")] {
2200+
/// # use serde::{Deserialize, Serialize};
2201+
/// # use serde_json::json;
2202+
/// # use serde_with::{serde_as, Seq};
2203+
/// # use std::{collections::BTreeMap, net::IpAddr};
2204+
/// #
2205+
/// use serde_with::{de::DeserializeAsWrap, ser::SerializeAsWrap, DeserializeAs, SerializeAs};
2206+
///
2207+
/// #[derive(Serialize, Deserialize)]
2208+
/// struct Custom<K, V> {
2209+
/// custom_key: K,
2210+
/// v: V,
2211+
/// }
2212+
///
2213+
/// impl<K, KAs, V, VAs> SerializeAs<(K, V)> for Custom<KAs, VAs>
2214+
/// where
2215+
/// KAs: SerializeAs<K>,
2216+
/// VAs: SerializeAs<V>,
2217+
/// {
2218+
/// fn serialize_as<S>((k, v): &(K, V), serializer: S) -> Result<S::Ok, S::Error>
2219+
/// where
2220+
/// S: serde::Serializer,
2221+
/// {
2222+
/// (Custom {
2223+
/// custom_key: SerializeAsWrap::<K, KAs>::new(k),
2224+
/// v: SerializeAsWrap::<V, VAs>::new(v),
2225+
/// })
2226+
/// .serialize(serializer)
2227+
/// }
2228+
/// }
2229+
///
2230+
/// impl<'de, K, KAs, V, VAs> DeserializeAs<'de, (K, V)> for Custom<KAs, VAs>
2231+
/// where
2232+
/// KAs: DeserializeAs<'de, K>,
2233+
/// VAs: DeserializeAs<'de, V>,
2234+
/// {
2235+
/// fn deserialize_as<D>(deserializer: D) -> Result<(K, V), D::Error>
2236+
/// where
2237+
/// D: serde::Deserializer<'de>,
2238+
/// {
2239+
/// let c = <Custom<DeserializeAsWrap<K, KAs>, DeserializeAsWrap<V, VAs>>>::deserialize(
2240+
/// deserializer,
2241+
/// )?;
2242+
/// Ok((c.custom_key.into_inner(), c.v.into_inner()))
2243+
/// }
2244+
/// }
2245+
///
2246+
/// #[serde_as]
2247+
/// # #[derive(Debug, PartialEq)]
2248+
/// #[derive(Serialize, Deserialize)]
2249+
/// struct SM(#[serde_as(as = "Seq<Custom<_, _>>")] BTreeMap<u32, IpAddr>);
2250+
///
2251+
/// // This converts the Rust type
2252+
/// let ip = "1.2.3.4".parse().unwrap();
2253+
/// let ip2 = "255.255.255.255".parse().unwrap();
2254+
/// let data = SM(vec![(1, ip), (10, ip), (200, ip2)].into_iter().collect());
2255+
///
2256+
/// // into this JSON
2257+
/// let value = serde_json::json!(
2258+
/// [
2259+
/// {
2260+
/// "custom_key": 1,
2261+
/// "v": "1.2.3.4"
2262+
/// },
2263+
/// {
2264+
/// "custom_key": 10,
2265+
/// "v": "1.2.3.4"
2266+
/// },
2267+
/// {
2268+
/// "custom_key": 200,
2269+
/// "v": "255.255.255.255"
2270+
/// }
2271+
/// ]
2272+
/// );
2273+
///
2274+
/// assert_eq!(value, serde_json::to_value(&data).unwrap());
2275+
/// assert_eq!(data, serde_json::from_value(value).unwrap());
2276+
/// # }
2277+
/// ```
21972278
pub struct Seq<V>(PhantomData<V>);
21982279

21992280
/// Ensure no duplicate keys exist in a map.

serde_with/src/ser/impls.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -348,33 +348,31 @@ tuple_impl!(16 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7
348348

349349
#[cfg(feature = "alloc")]
350350
macro_rules! map_as_tuple_seq_intern {
351-
($tyorig:ident < K, V $(, $typaram:ident : $bound:ident)* >, $ty:ident <(K, V)>) => {
352-
impl<K, KAs, V, VAs $(, $typaram)*> SerializeAs<$tyorig<K, V $(, $typaram)*>> for $ty<(KAs, VAs)>
351+
($tyorig:ident < K, V $(, $typaram:ident : $bound:ident)* >, $ty:ident <TAs>) => {
352+
impl<K, V, TAs $(, $typaram)*> SerializeAs<$tyorig<K, V $(, $typaram)*>> for $ty<TAs>
353353
where
354-
KAs: SerializeAs<K>,
355-
VAs: SerializeAs<V>,
354+
for<'a> TAs: SerializeAs<(&'a K, &'a V)>,
356355
$($typaram: ?Sized + $bound,)*
357356
{
358357
fn serialize_as<S>(source: &$tyorig<K, V $(, $typaram)*>, serializer: S) -> Result<S::Ok, S::Error>
359358
where
360359
S: Serializer,
361360
{
362-
serializer.collect_seq(source.iter().map(|(k, v)| {
363-
(
364-
SerializeAsWrap::<K, KAs>::new(k),
365-
SerializeAsWrap::<V, VAs>::new(v),
366-
)
367-
}))
361+
let mut seq = serializer.serialize_seq(None)?;
362+
for (k, v) in source {
363+
seq.serialize_element(&SerializeAsWrap::<(&K, &V), TAs>::new(&(k, v)))?;
364+
}
365+
seq.end()
368366
}
369367
}
370368
};
371369
}
372370
#[cfg(feature = "alloc")]
373371
macro_rules! map_as_tuple_seq {
374372
($tyorig:ident < K, V $(, $typaram:ident : $bound:ident)* >) => {
375-
map_as_tuple_seq_intern!($tyorig<K, V $(, $typaram: $bound)* >, Seq<(K, V)>);
373+
map_as_tuple_seq_intern!($tyorig<K, V $(, $typaram: $bound)* >, Seq<TAs>);
376374
#[cfg(feature = "alloc")]
377-
map_as_tuple_seq_intern!($tyorig<K, V $(, $typaram: $bound)* >, Vec<(K, V)>);
375+
map_as_tuple_seq_intern!($tyorig<K, V $(, $typaram: $bound)* >, Vec<TAs>);
378376
}
379377
}
380378
foreach_map!(map_as_tuple_seq);

serde_with/tests/serde_as/map_tuple_list.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,3 +319,74 @@ fn test_tuple_array_as_map() {
319319
}"#]],
320320
);
321321
}
322+
323+
#[test]
324+
fn test_map_as_custom_struct() {
325+
let ip = "1.2.3.4".parse().unwrap();
326+
let ip2 = "255.255.255.255".parse().unwrap();
327+
328+
use serde_with::{de::DeserializeAsWrap, ser::SerializeAsWrap, DeserializeAs, SerializeAs};
329+
330+
#[derive(serde::Serialize, serde::Deserialize)]
331+
struct Custom<K, V> {
332+
custom_key: K,
333+
v: V,
334+
}
335+
336+
impl<K, KAs, V, VAs> SerializeAs<(K, V)> for Custom<KAs, VAs>
337+
where
338+
KAs: SerializeAs<K>,
339+
VAs: SerializeAs<V>,
340+
{
341+
fn serialize_as<S>((k, v): &(K, V), serializer: S) -> Result<S::Ok, S::Error>
342+
where
343+
S: serde::Serializer,
344+
{
345+
(Custom {
346+
custom_key: SerializeAsWrap::<K, KAs>::new(k),
347+
v: SerializeAsWrap::<V, VAs>::new(v),
348+
})
349+
.serialize(serializer)
350+
}
351+
}
352+
353+
impl<'de, K, KAs, V, VAs> DeserializeAs<'de, (K, V)> for Custom<KAs, VAs>
354+
where
355+
KAs: DeserializeAs<'de, K>,
356+
VAs: DeserializeAs<'de, V>,
357+
{
358+
fn deserialize_as<D>(deserializer: D) -> Result<(K, V), D::Error>
359+
where
360+
D: serde::Deserializer<'de>,
361+
{
362+
let c = <Custom<DeserializeAsWrap<K, KAs>, DeserializeAsWrap<V, VAs>>>::deserialize(
363+
deserializer,
364+
)?;
365+
Ok((c.custom_key.into_inner(), c.v.into_inner()))
366+
}
367+
}
368+
369+
#[serde_as]
370+
#[derive(Debug, Serialize, Deserialize, PartialEq)]
371+
struct SM(#[serde_as(as = "Seq<Custom<_, _>>")] BTreeMap<u32, IpAddr>);
372+
373+
let map: BTreeMap<_, _> = vec![(1, ip), (10, ip), (200, ip2)].into_iter().collect();
374+
is_equal(
375+
SM(map),
376+
expect![[r#"
377+
[
378+
{
379+
"custom_key": 1,
380+
"v": "1.2.3.4"
381+
},
382+
{
383+
"custom_key": 10,
384+
"v": "1.2.3.4"
385+
},
386+
{
387+
"custom_key": 200,
388+
"v": "255.255.255.255"
389+
}
390+
]"#]],
391+
);
392+
}

0 commit comments

Comments
 (0)