-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Deserialize a sequence from a map by ignoring keys #745
Comments
Sorta similar to #541, except instead of only keeping homogeneous keys this keeps the heterogeneous values |
I think this implementation looks fine as is. As long as you are aware of the limitations. Since you don't specify a type for the key (but have It would be possible to make the key type another parameter, defaulting to There are a couple of extensions I can think to make it nicer to use. #[serde_with::serde_as]
#[derive(Debug, serde::Deserialize)]
struct Foo {
#[serde_as(as = "IgnoreKeys")]
foo: (String, i32, String),
} You could provide that by extending the macro to create a second impl for Implementationmacro_rules! tuple_impl {
($len:literal $($n:tt $t:ident $tas:ident)+) => {
impl<'de, $($t, $tas,)+> DeserializeAs<'de, ($($t,)+)> for IgnoreKeys<($($tas,)+)>
where
$($tas: DeserializeAs<'de, $t>,)+
{
fn deserialize_as<D>(deserializer: D) -> Result<($($t,)+), D::Error>
where
D: Deserializer<'de>,
{
struct MapVisitor<$($t,)+>(PhantomData<($($t,)+)>);
impl<'de, $($t, $tas,)+> Visitor<'de>
for MapVisitor<$(DeserializeAsWrap<$t, $tas>,)+>
where
$($tas: DeserializeAs<'de, $t>,)+
{
type Value = ($($t,)+);
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(concat!("a map of size ", $len))
}
#[allow(non_snake_case)]
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
$(
let $t: (IgnoredAny, DeserializeAsWrap<$t, $tas>) = match map.next_entry()? {
Some(value) => value,
None => return Err(DeError::invalid_length($n, &self)),
};
)+
Ok(($($t.1.into_inner(),)+))
}
}
deserializer.deserialize_map(
MapVisitor::<$(DeserializeAsWrap<$t, $tas>,)+>(PhantomData),
)
}
}
impl<'de, $($t,)+> DeserializeAs<'de, ($($t,)+)> for IgnoreKeys<serde_with::Same>
where
$($t: serde::Deserialize<'de>,)+
{
fn deserialize_as<D>(deserializer: D) -> Result<($($t,)+), D::Error>
where
D: Deserializer<'de>,
{
struct MapVisitor<$($t,)+>(PhantomData<($($t,)+)>);
impl<'de, $($t,)+> Visitor<'de>
for MapVisitor<$($t,)+>
where
$($t: serde::Deserialize<'de>,)+
{
type Value = ($($t,)+);
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(concat!("a map of size ", $len))
}
#[allow(non_snake_case)]
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
$(
let $t: (IgnoredAny, $t) = match map.next_entry()? {
Some(value) => value,
None => return Err(DeError::invalid_length($n, &self)),
};
)+
Ok(($($t.1,)+))
}
}
deserializer.deserialize_map(
MapVisitor::<$($t,)+>(PhantomData),
)
}
}
};
}
tuple_impl!(1 0 T0 As0);
tuple_impl!(2 0 T0 As0 1 T1 As1);
tuple_impl!(3 0 T0 As0 1 T1 As1 2 T2 As2);
tuple_impl!(4 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3);
tuple_impl!(5 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4);
tuple_impl!(6 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5);
tuple_impl!(7 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6);
tuple_impl!(8 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7);
tuple_impl!(9 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8);
tuple_impl!(10 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9);
tuple_impl!(11 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9 10 T10 As10);
tuple_impl!(12 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9 10 T10 As10 11 T11 As11);
tuple_impl!(13 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9 10 T10 As10 11 T11 As11 12 T12 As12);
tuple_impl!(14 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9 10 T10 As10 11 T11 As11 12 T12 As12 13 T13 As13);
tuple_impl!(15 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9 10 T10 As10 11 T11 As11 12 T12 As12 13 T13 As13 14 T14 As14);
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 T7 As7 8 T8 As8 9 T9 As9 10 T10 As10 11 T11 As11 12 T12 As12 13 T13 As13 14 T14 As14 15 T15 As15); Instead of only supporting heterogeneous collections, homogeneous collections would be a nice extension, similar to the #541 issue you found. #[serde_with::serde_as]
#[derive(Debug, serde::Deserialize)]
struct Foo {
#[serde_as(as = "IgnoreKeys<_>")]
foo: Vec<String>,
} This would need a single fully separate implementation to the macro. Implementationimpl<'de, T, TAs> DeserializeAs<'de, Vec<T>> for IgnoreKeys<TAs>
where
TAs: DeserializeAs<'de, T>,
{
fn deserialize_as<D>(deserializer: D) -> Result<Vec<T>, D::Error>
where
D: Deserializer<'de>,
{
struct MapVisitor<T>(PhantomData<T>);
impl<'de, T, TAs> Visitor<'de> for MapVisitor<DeserializeAsWrap<T, TAs>>
where
TAs: DeserializeAs<'de, T>,
{
type Value = Vec<T>;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a map")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let mut res = Vec::new();
while let Some((_, value)) = map.next_entry::<IgnoredAny, DeserializeAsWrap<T, TAs>>()? {
res.push(value.into_inner());
}
Ok(res)
}
}
deserializer.deserialize_map(MapVisitor::<DeserializeAsWrap<T, TAs>>(PhantomData))
}
} |
I have a case where I'd like to deserialize a heterogeneous tuple from a map by ignoring the keys of the map. I implemented
DeserializeAs
forIgnoreKeys
based on the regular tuple implementation. Naturally you can only deserialize and cannot re-serialize as the key names are all lost.IgnoreKeys
Is there a better way to do this? And if not, should I make a PR to add this to the crate?
The text was updated successfully, but these errors were encountered: