enum-bitset-derive 0.2.1

Proc macros for the enum-bitset macro
Documentation
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::{LitInt, LitStr};

use crate::derive::config::EnumBitsetConfig;

#[allow(dead_code)]
impl EnumBitsetConfig {
    pub(crate) fn impl_serde_map(&self) -> TokenStream2 {
        let mut output = TokenStream2::new();

        if self.serde.ser {
            output.extend(self.impl_serde_map_ser());
        }

        if self.serde.de {
            output.extend(self.impl_serde_map_de());
        }

        output
    }

    fn impl_serde_map_ser(&self) -> TokenStream2 {
        {
            let n_variants = LitInt::new(&self.variants.len().to_string(), self.base_type.span());
            let base_ty = &self.base_type;
            let set_ty = &self.set_type;
            let serde = &self.serde.serde_crate;

            let variants = self.variants.iter().map(|variant| {
                let name = &variant.ident;

                quote! {
                    map.serialize_key(&#base_ty :: #name)?;
                    map.serialize_value(&self.contains(&#base_ty :: #name))?;
                }
            });

            quote! {
                use #serde::{Serialize, Serializer, ser::{SerializeMap}};

                const _: fn() = || {
                    fn base_enum_for_bitsets_must_be_serializable<T: Serialize>() {}
                    base_enum_for_bitsets_must_be_serializable::<#set_ty>();
                };

                impl Serialize for #set_ty {
                    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
                    where
                        S: Serializer,
                    {
                        let mut map = serializer.serialize_map(Some(#n_variants))?;

                        #(#variants)*

                        map.end()
                    }
                }
            }
        }
    }

    fn impl_serde_map_de(&self) -> TokenStream2 {
        let name = &self.set_type;
        let base = &self.base_type;
        let serde = &self.serde.serde_crate;

        let expect = LitStr::new(
            &format!("a map from `{name}` variants to boolean values"),
            name.span(),
        );

        quote! {
            use #serde::{Deserialize, Deserializer, de::{SeqAccess, Visitor}};

            const _: fn() = || {
                fn base_enum_for_bitsets_must_be_deserializable<T: for<'de> Deserialize<'de>>() {}
                base_enum_for_bitsets_must_be_deserializable::<#name>();
            };

            impl<'de> Deserialize<'de> for #name {
                fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
                where
                    D: Deserializer<'de>,
                {
                    struct VisitMap;

                    impl<'de> Visitor<'de> for VisitMap {
                        type Value = #name;

                        fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
                            formatter.write_str(#expect)
                        }

                        fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
                           where A: #serde::de::MapAccess<'de>
                        {
                            let mut result = #name::new();
                            while let Some(variant) = map.next_key::<#base>()? {

                                let value : bool = map.next_value()?;

                                if value {
                                    result.insert(variant);
                                }
                            }

                            Ok(result)
                        }
                    }

                    deserializer.deserialize_map(VisitMap)
                }
            }
        }
    }
}