fn derive_chrony_serialize_enum()

in chrony-candm-derive/src/lib.rs [78:119]


fn derive_chrony_serialize_enum(
    name: proc_macro2::Ident,
    attrs: &[syn::Attribute],
    _ds: syn::DataEnum,
) -> TokenStream {
    let repr = attrs
        .iter()
        .find_map(|attr| {
            if let syn::Meta::List(meta_list) = attr.parse_meta().ok()? {
                if meta_list.path.get_ident()? == "repr" {
                    let repr = meta_list.nested.iter().next()?;
                    let repr: syn::Ident = parse_quote! { #repr };
                    Some(repr)
                } else {
                    None
                }
            } else {
                None
            }
        })
        .expect("Must specify a #[repr] attribute to derive ChronySerialize for an enum.");

    let expanded = quote! {
        impl ::chrony_candm::common::ChronySerialize for #name {
            fn length() -> usize {
                ::std::mem::size_of::<#repr>()
            }

            fn serialize<B: ::bytes::BufMut>(&self, buf: &mut B) {
                buf.put_slice((&<#repr>::from(*self).to_be_bytes()) as &[u8]);
            }

            fn deserialize_unchecked<B: ::bytes::Buf>(buf: &mut B) -> ::std::result::Result<Self, ::chrony_candm::common::DeserializationError> {
                let mut dst = [0u8; ::std::mem::size_of::<#repr>()];
                buf.copy_to_slice(&mut dst);
                <Self as ::std::convert::TryFrom<#repr>>::try_from(<#repr>::from_be_bytes(dst)).map_err(|_| ::chrony_candm::common::DeserializationError::new("value outside of enum range"))
            }
        }
    };

    TokenStream::from(expanded)
}