Skip to content
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

Question: multiple ways to deserialize / date example #507

Open
xpe opened this issue Sep 17, 2023 · 1 comment
Open

Question: multiple ways to deserialize / date example #507

xpe opened this issue Sep 17, 2023 · 1 comment
Labels

Comments

@xpe
Copy link

xpe commented Sep 17, 2023

What are some recommended ways to handle this situation?

Given this Date struct:

pub struct Date {
    pub year: u16,
    pub month: u8,
    pub day: u8,
}

I want to allow a person typing into a .ron file to use the usual syntax or (2023, 9, 17) corresponding to:

pub struct DateTuple(pub u16, pub u8, pub u8)

RON leans on Serde heavily, and I've started looking at ways to let Serde handle this.

I'm asking this question mostly as a jumping off point so that I can suggest some content for RON documentation and FAQs.

@xpe xpe changed the title Question Question: multiple ways to deserialize / date example Sep 17, 2023
@juntyr
Copy link
Member

juntyr commented Sep 17, 2023

If you only want to support the (2023, 9, 17) syntax, you could define the DateTuple type as a private helper and forward the Serialize and Deserialize impls to it. You can either use serde's #[serde(from = DataTuple, into = DataTuple)] attributes for that, or write an explicit impl that just calls the helper.

If you want to support both (2023, 9, 17) and (year: 2023, month: 9, day: 17), you will need to use deserialize_any. My strategy for this is to go to Rust playground and expand the auto-generated impls and to customise them (note that I have not cleaned up this code at all, though I would recommend doing that):

#[derive(serde::Serialize)]
pub struct Date {
    pub year: u16,
    pub month: u8,
    pub day: u8,
}

#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        #[automatically_derived]
        impl<'de> _serde::Deserialize<'de> for Date {
            fn deserialize<__D>(__deserializer: __D)
                -> _serde::__private::Result<Self, __D::Error> where
                __D: _serde::Deserializer<'de> {
                #[allow(non_camel_case_types)]
                #[doc(hidden)]
                enum __Field { __field0, __field1, __field2, }
                #[doc(hidden)]
                struct __FieldVisitor;
                impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
                    type Value = __Field;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private::Formatter)
                        -> _serde::__private::fmt::Result {
                        _serde::__private::Formatter::write_str(__formatter,
                            "field identifier")
                    }
                    fn visit_u64<__E>(self, __value: u64)
                        -> _serde::__private::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            0u64 => _serde::__private::Ok(__Field::__field0),
                            1u64 => _serde::__private::Ok(__Field::__field1),
                            2u64 => _serde::__private::Ok(__Field::__field2),
                            _ =>
                                _serde::__private::Err(_serde::de::Error::invalid_value(_serde::de::Unexpected::Unsigned(__value),
                                        &"field index 0 <= i < 3")),
                        }
                    }
                    fn visit_str<__E>(self, __value: &str)
                        -> _serde::__private::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            "year" => _serde::__private::Ok(__Field::__field0),
                            "month" => _serde::__private::Ok(__Field::__field1),
                            "day" => _serde::__private::Ok(__Field::__field2),
                            _ => {
                                _serde::__private::Err(_serde::de::Error::unknown_field(__value,
                                        FIELDS))
                            }
                        }
                    }
                    fn visit_bytes<__E>(self, __value: &[u8])
                        -> _serde::__private::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            b"year" => _serde::__private::Ok(__Field::__field0),
                            b"month" => _serde::__private::Ok(__Field::__field1),
                            b"day" => _serde::__private::Ok(__Field::__field2),
                            _ => {
                                let __value = &_serde::__private::from_utf8_lossy(__value);
                                _serde::__private::Err(_serde::de::Error::unknown_field(__value,
                                        FIELDS))
                            }
                        }
                    }
                }
                impl<'de> _serde::Deserialize<'de> for __Field {
                    #[inline]
                    fn deserialize<__D>(__deserializer: __D)
                        -> _serde::__private::Result<Self, __D::Error> where
                        __D: _serde::Deserializer<'de> {
                        _serde::Deserializer::deserialize_identifier(__deserializer,
                            __FieldVisitor)
                    }
                }
                #[doc(hidden)]
                struct __Visitor<'de> {
                    marker: _serde::__private::PhantomData<Date>,
                    lifetime: _serde::__private::PhantomData<&'de ()>,
                }
                impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
                    type Value = Date;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private::Formatter)
                        -> _serde::__private::fmt::Result {
                        _serde::__private::Formatter::write_str(__formatter,
                            "struct Date")
                    }
                    #[inline]
                    fn visit_seq<__A>(self, mut __seq: __A)
                        -> _serde::__private::Result<Self::Value, __A::Error> where
                        __A: _serde::de::SeqAccess<'de> {
                        let __field0 =
                            match _serde::de::SeqAccess::next_element::<u16>(&mut __seq)?
                                {
                                _serde::__private::Some(__value) => __value,
                                _serde::__private::None =>
                                    return _serde::__private::Err(_serde::de::Error::invalid_length(0usize,
                                                &"struct Date with 3 elements")),
                            };
                        let __field1 =
                            match _serde::de::SeqAccess::next_element::<u8>(&mut __seq)?
                                {
                                _serde::__private::Some(__value) => __value,
                                _serde::__private::None =>
                                    return _serde::__private::Err(_serde::de::Error::invalid_length(1usize,
                                                &"struct Date with 3 elements")),
                            };
                        let __field2 =
                            match _serde::de::SeqAccess::next_element::<u8>(&mut __seq)?
                                {
                                _serde::__private::Some(__value) => __value,
                                _serde::__private::None =>
                                    return _serde::__private::Err(_serde::de::Error::invalid_length(2usize,
                                                &"struct Date with 3 elements")),
                            };
                        _serde::__private::Ok(Date {
                                year: __field0,
                                month: __field1,
                                day: __field2,
                            })
                    }
                    #[inline]
                    fn visit_map<__A>(self, mut __map: __A)
                        -> _serde::__private::Result<Self::Value, __A::Error> where
                        __A: _serde::de::MapAccess<'de> {
                        let mut __field0: _serde::__private::Option<u16> =
                            _serde::__private::None;
                        let mut __field1: _serde::__private::Option<u8> =
                            _serde::__private::None;
                        let mut __field2: _serde::__private::Option<u8> =
                            _serde::__private::None;
                        while let _serde::__private::Some(__key) =
                                _serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
                            match __key {
                                __Field::__field0 => {
                                    if _serde::__private::Option::is_some(&__field0) {
                                            return _serde::__private::Err(<__A::Error as
                                                            _serde::de::Error>::duplicate_field("year"));
                                        }
                                    __field0 =
                                        _serde::__private::Some(_serde::de::MapAccess::next_value::<u16>(&mut __map)?);
                                }
                                __Field::__field1 => {
                                    if _serde::__private::Option::is_some(&__field1) {
                                            return _serde::__private::Err(<__A::Error as
                                                            _serde::de::Error>::duplicate_field("month"));
                                        }
                                    __field1 =
                                        _serde::__private::Some(_serde::de::MapAccess::next_value::<u8>(&mut __map)?);
                                }
                                __Field::__field2 => {
                                    if _serde::__private::Option::is_some(&__field2) {
                                            return _serde::__private::Err(<__A::Error as
                                                            _serde::de::Error>::duplicate_field("day"));
                                        }
                                    __field2 =
                                        _serde::__private::Some(_serde::de::MapAccess::next_value::<u8>(&mut __map)?);
                                }
                            }
                        }
                        let __field0 =
                            match __field0 {
                                _serde::__private::Some(__field0) => __field0,
                                _serde::__private::None =>
                                    _serde::__private::de::missing_field("year")?,
                            };
                        let __field1 =
                            match __field1 {
                                _serde::__private::Some(__field1) => __field1,
                                _serde::__private::None =>
                                    _serde::__private::de::missing_field("month")?,
                            };
                        let __field2 =
                            match __field2 {
                                _serde::__private::Some(__field2) => __field2,
                                _serde::__private::None =>
                                    _serde::__private::de::missing_field("day")?,
                            };
                        _serde::__private::Ok(Date {
                                year: __field0,
                                month: __field1,
                                day: __field2,
                            })
                    }
                }
                #[doc(hidden)]
                const FIELDS: &'static [&'static str] =
                    &["year", "month", "day"];

                // NOTE: switch from deserialize_struct to deserialize_any here

                // _serde::Deserializer::deserialize_struct(__deserializer,
                //     "Date", FIELDS,
                //     __Visitor {
                //         marker: _serde::__private::PhantomData::<Date>,
                //         lifetime: _serde::__private::PhantomData,
                //     })
                _serde::Deserializer::deserialize_any(__deserializer,
                    __Visitor {
                        marker: _serde::__private::PhantomData::<Date>,
                        lifetime: _serde::__private::PhantomData,
                    })
            }
        }
    };

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants