bincode_derive_purplecoin 2.0.0-rc.1

Implementation of #[derive(Encode, Decode)] for bincode
Documentation
use crate::attribute::{ContainerAttributes, FieldAttributes};
use virtue::generate::Generator;
use virtue::parse::Fields;
use virtue::prelude::*;

pub(crate) struct DeriveStruct {
    pub fields: Fields,
    pub attributes: ContainerAttributes,
}

impl DeriveStruct {
    pub fn generate_encode(self, generator: &mut Generator) -> Result<()> {
        let DeriveStruct { fields, attributes } = self;
        let crate_name = attributes.crate_name;

        generator
            .impl_for(&format!("{}::Encode", crate_name))
            .modify_generic_constraints(|generics, where_constraints| {
                for g in generics.iter_generics() {
                    where_constraints
                        .push_constraint(g, format!("{}::Encode", crate_name))
                        .unwrap();
                }
            })
            .generate_fn("encode")
            .with_generic_deps("E", [format!("{}::enc::Encoder", crate_name)])
            .with_self_arg(virtue::generate::FnSelfArg::RefSelf)
            .with_arg("encoder", "&mut E")
            .with_return_type(format!(
                "core::result::Result<(), {}::error::EncodeError>",
                crate_name
            ))
            .body(|fn_body| {
                for field in fields.names() {
                    let attributes = field
                        .attributes()
                        .get_attribute::<FieldAttributes>()?
                        .unwrap_or_default();
                    if attributes.with_serde {
                        fn_body.push_parsed(format!(
                            "{0}::Encode::encode(&{0}::serde::Compat(&self.{1}), encoder)?;",
                            crate_name, field
                        ))?;
                    } else {
                        fn_body.push_parsed(format!(
                            "{}::Encode::encode(&self.{}, encoder)?;",
                            crate_name, field
                        ))?;
                    }
                }
                fn_body.push_parsed("Ok(())")?;
                Ok(())
            })?;
        Ok(())
    }

    pub fn generate_decode(self, generator: &mut Generator) -> Result<()> {
        // Remember to keep this mostly in sync with generate_borrow_decode
        let DeriveStruct { fields, attributes } = self;
        let crate_name = attributes.crate_name;

        generator
            .impl_for(format!("{}::Decode", crate_name))
            .modify_generic_constraints(|generics, where_constraints| {
                for g in generics.iter_generics() {
                    where_constraints.push_constraint(g, format!("{}::Decode", crate_name)).unwrap();
                }
            })
            .generate_fn("decode")
            .with_generic_deps("D", [format!("{}::de::Decoder", crate_name)])
            .with_arg("decoder", "&mut D")
            .with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", crate_name))
            .body(|fn_body| {
                // Ok(Self {
                fn_body.ident_str("Ok");
                fn_body.group(Delimiter::Parenthesis, |ok_group| {
                    ok_group.ident_str("Self");
                    ok_group.group(Delimiter::Brace, |struct_body| {
                        // Fields
                        // {
                        //      a: bincode::Decode::decode(decoder)?,
                        //      b: bincode::Decode::decode(decoder)?,
                        //      ...
                        // }
                        for field in fields.names() {
                            let attributes = field.attributes().get_attribute::<FieldAttributes>()?.unwrap_or_default();
                            if attributes.with_serde {
                                struct_body
                                    .push_parsed(format!(
                                        "{1}: (<{0}::serde::Compat<_> as {0}::Decode>::decode(decoder)?).0,",
                                        crate_name,
                                        field
                                    ))?;
                            } else {
                                struct_body
                                    .push_parsed(format!(
                                        "{1}: {0}::Decode::decode(decoder)?,",
                                        crate_name,
                                        field
                                    ))?;
                            }
                        }
                        Ok(())
                    })?;
                    Ok(())
                })?;
                Ok(())
            })?;
        Ok(())
    }

    pub fn generate_borrow_decode(self, generator: &mut Generator) -> Result<()> {
        // Remember to keep this mostly in sync with generate_decode
        let DeriveStruct { fields, attributes } = self;
        let crate_name = attributes.crate_name;

        generator
            .impl_for_with_lifetimes(format!("{}::BorrowDecode", crate_name), ["__de"])
            .modify_generic_constraints(|generics, where_constraints| {
                for g in generics.iter_generics() {
                    where_constraints.push_constraint(g, format!("{}::BorrowDecode", crate_name)).unwrap();
                }
            })
            .generate_fn("borrow_decode")
            .with_generic_deps("D", [format!("{}::de::BorrowDecoder<'__de>", crate_name)])
            .with_arg("decoder", "&mut D")
            .with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", crate_name))
            .body(|fn_body| {
                // Ok(Self {
                fn_body.ident_str("Ok");
                fn_body.group(Delimiter::Parenthesis, |ok_group| {
                    ok_group.ident_str("Self");
                    ok_group.group(Delimiter::Brace, |struct_body| {
                        for field in fields.names() {
                            let attributes = field.attributes().get_attribute::<FieldAttributes>()?.unwrap_or_default();
                            if attributes.with_serde {
                                struct_body
                                    .push_parsed(format!(
                                        "{1}: (<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode>::borrow_decode(decoder)?).0,",
                                        crate_name,
                                        field
                                    ))?;
                            } else {
                                struct_body
                                    .push_parsed(format!(
                                        "{1}: {0}::BorrowDecode::borrow_decode(decoder)?,",
                                        crate_name,
                                        field
                                    ))?;
                            }
                        }
                        Ok(())
                    })?;
                    Ok(())
                })?;
                Ok(())
            })?;
        Ok(())
    }
}