bincode_derive-2.0.1/.cargo_vcs_info.json0000644000000001440000000000100137740ustar { "git": { "sha1": "4673360aa638b2b907dff24538de54f258d157da" }, "path_in_vcs": "derive" }bincode_derive-2.0.1/.gitignore000064400000000000000000000000241046102023000145510ustar 00000000000000/target /Cargo.lock bincode_derive-2.0.1/Cargo.lock0000644000000005730000000000100117550ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "bincode_derive" version = "2.0.1" dependencies = [ "virtue", ] [[package]] name = "virtue" version = "0.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" bincode_derive-2.0.1/Cargo.toml0000644000000023250000000000100117750ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.85.0" name = "bincode_derive" version = "2.0.1" authors = [ "Zoey Riordan ", "Victor Koenders ", ] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Implementation of #[derive(Encode, Decode)] for bincode" documentation = "https://docs.rs/bincode_derive" readme = "readme.md" keywords = [ "binary", "encode", "decode", "serialize", "deserialize", ] categories = [ "encoding", "network-programming", ] license = "MIT" repository = "https://github.com/bincode-org/bincode" [lib] name = "bincode_derive" path = "src/lib.rs" proc-macro = true [dependencies.virtue] version = "0.0.18" bincode_derive-2.0.1/Cargo.toml.orig000064400000000000000000000011711046102023000154540ustar 00000000000000[package] name = "bincode_derive" version = "2.0.1" # remember to update bincode authors = [ "Zoey Riordan ", "Victor Koenders ", ] edition = "2021" rust-version = "1.85.0" repository = "https://github.com/bincode-org/bincode" documentation = "https://docs.rs/bincode_derive" readme = "./readme.md" categories = ["encoding", "network-programming"] keywords = ["binary", "encode", "decode", "serialize", "deserialize"] license = "MIT" description = "Implementation of #[derive(Encode, Decode)] for bincode" [lib] proc-macro = true [dependencies] virtue = "0.0.18" bincode_derive-2.0.1/LICENSE.md000064400000000000000000000020641046102023000141730ustar 00000000000000The MIT License (MIT) Copyright (c) 2014 Ty Overby Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. bincode_derive-2.0.1/readme.md000064400000000000000000000030751046102023000143510ustar 00000000000000# Bincode-derive The derive crate for bincode. Implements `bincode::Encode` and `bincode::Decode`. This crate is roughly split into 2 parts: # Parsing Most of parsing is done in the `src/parse/` folder. This will generate the following types: - `Attributes`, not being used currently - `Visibility`, not being used currently - `DataType` either `Struct` or `Enum`, with the name of the data type being parsed - `Generics` the generics part of the type, e.g. `struct Foo<'a>` - `GenericConstraints` the "where" part of the type # Generate Generating the code implementation is done in either `src/derive_enum.rs` and `src/derive_struct.rs`. This is supported by the structs in `src/generate`. The most notable points of this module are: - `StreamBuilder` is a thin but friendly wrapper around `TokenStream` - `Generator` is the base type of the code generator. This has helper methods to generate implementations: - `ImplFor` is a helper struct for a single `impl A for B` construction. In this functions can be defined: - `GenerateFnBody` is a helper struct for a single function in the above `impl`. This is created with a callback to `FnBuilder` which helps set some properties. `GenerateFnBody` has a `stream()` function which returns ` StreamBuilder` for the function. For additional derive testing, see the test cases in `../tests` For testing purposes, all generated code is outputted to the current `target/generated/bincode` folder, under file name `_Encode.rs` and `_Decode.rs`. This can help with debugging. bincode_derive-2.0.1/src/attribute.rs000064400000000000000000000127511046102023000157330ustar 00000000000000use virtue::prelude::*; use virtue::utils::{parse_tagged_attribute, ParsedAttribute}; pub struct ContainerAttributes { pub crate_name: String, pub bounds: Option<(String, Literal)>, pub decode_bounds: Option<(String, Literal)>, pub decode_context: Option<(String, Literal)>, pub borrow_decode_bounds: Option<(String, Literal)>, pub encode_bounds: Option<(String, Literal)>, } impl Default for ContainerAttributes { fn default() -> Self { Self { crate_name: "::bincode".to_string(), bounds: None, decode_bounds: None, decode_context: None, encode_bounds: None, borrow_decode_bounds: None, } } } impl FromAttribute for ContainerAttributes { fn parse(group: &Group) -> Result> { let attributes = match parse_tagged_attribute(group, "bincode")? { Some(body) => body, None => return Ok(None), }; let mut result = Self::default(); for attribute in attributes { match attribute { ParsedAttribute::Property(key, val) if key.to_string() == "crate" => { let val_string = val.to_string(); if val_string.starts_with('"') && val_string.ends_with('"') { result.crate_name = val_string[1..val_string.len() - 1].to_string(); } else { return Err(Error::custom_at("Should be a literal str", val.span())); } } ParsedAttribute::Property(key, val) if key.to_string() == "bounds" => { let val_string = val.to_string(); if val_string.starts_with('"') && val_string.ends_with('"') { result.bounds = Some((val_string[1..val_string.len() - 1].to_string(), val)); } else { return Err(Error::custom_at("Should be a literal str", val.span())); } } ParsedAttribute::Property(key, val) if key.to_string() == "decode_bounds" => { let val_string = val.to_string(); if val_string.starts_with('"') && val_string.ends_with('"') { result.decode_bounds = Some((val_string[1..val_string.len() - 1].to_string(), val)); } else { return Err(Error::custom_at("Should be a literal str", val.span())); } } ParsedAttribute::Property(key, val) if key.to_string() == "decode_context" => { let val_string = val.to_string(); if val_string.starts_with('"') && val_string.ends_with('"') { result.decode_context = Some((val_string[1..val_string.len() - 1].to_string(), val)); } else { return Err(Error::custom_at("Should be a literal str", val.span())); } } ParsedAttribute::Property(key, val) if key.to_string() == "encode_bounds" => { let val_string = val.to_string(); if val_string.starts_with('"') && val_string.ends_with('"') { result.encode_bounds = Some((val_string[1..val_string.len() - 1].to_string(), val)); } else { return Err(Error::custom_at("Should be a literal str", val.span())); } } ParsedAttribute::Property(key, val) if key.to_string() == "borrow_decode_bounds" => { let val_string = val.to_string(); if val_string.starts_with('"') && val_string.ends_with('"') { result.borrow_decode_bounds = Some((val_string[1..val_string.len() - 1].to_string(), val)); } else { return Err(Error::custom_at("Should be a literal str", val.span())); } } ParsedAttribute::Tag(i) => { return Err(Error::custom_at("Unknown field attribute", i.span())) } ParsedAttribute::Property(key, _) => { return Err(Error::custom_at("Unknown field attribute", key.span())) } _ => {} } } Ok(Some(result)) } } #[derive(Default)] pub struct FieldAttributes { pub with_serde: bool, } impl FromAttribute for FieldAttributes { fn parse(group: &Group) -> Result> { let attributes = match parse_tagged_attribute(group, "bincode")? { Some(body) => body, None => return Ok(None), }; let mut result = Self::default(); for attribute in attributes { match attribute { ParsedAttribute::Tag(i) if i.to_string() == "with_serde" => { result.with_serde = true; } ParsedAttribute::Tag(i) => { return Err(Error::custom_at("Unknown field attribute", i.span())) } ParsedAttribute::Property(key, _) => { return Err(Error::custom_at("Unknown field attribute", key.span())) } _ => {} } } Ok(Some(result)) } } bincode_derive-2.0.1/src/derive_enum.rs000064400000000000000000000526251046102023000162360ustar 00000000000000use crate::attribute::{ContainerAttributes, FieldAttributes}; use virtue::prelude::*; const TUPLE_FIELD_PREFIX: &str = "field_"; pub(crate) struct DeriveEnum { pub variants: Vec, pub attributes: ContainerAttributes, } impl DeriveEnum { fn iter_fields(&self) -> EnumVariantIterator { EnumVariantIterator { idx: 0, variants: &self.variants, } } pub fn generate_encode(self, generator: &mut Generator) -> Result<()> { let crate_name = self.attributes.crate_name.as_str(); generator .impl_for(format!("{}::Encode", crate_name)) .modify_generic_constraints(|generics, where_constraints| { if let Some((bounds, lit)) = (self.attributes.encode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) { where_constraints.clear(); where_constraints .push_parsed_constraint(bounds) .map_err(|e| e.with_span(lit.span()))?; } else { for g in generics.iter_generics() { where_constraints .push_constraint(g, format!("{}::Encode", crate_name)) .unwrap(); } } Ok(()) })? .generate_fn("encode") .with_generic_deps("__E", [format!("{}::enc::Encoder", crate_name)]) .with_self_arg(FnSelfArg::RefSelf) .with_arg("encoder", "&mut __E") .with_return_type(format!( "core::result::Result<(), {}::error::EncodeError>", crate_name )) .body(|fn_body| { fn_body.ident_str("match"); fn_body.ident_str("self"); fn_body.group(Delimiter::Brace, |match_body| { if self.variants.is_empty() { self.encode_empty_enum_case(match_body)?; } for (variant_index, variant) in self.iter_fields() { // Self::Variant match_body.ident_str("Self"); match_body.puncts("::"); match_body.ident(variant.name.clone()); // if we have any fields, declare them here // Self::Variant { a, b, c } if let Some(fields) = variant.fields.as_ref() { let delimiter = fields.delimiter(); match_body.group(delimiter, |field_body| { for (idx, field_name) in fields.names().into_iter().enumerate() { if idx != 0 { field_body.punct(','); } field_body.push( field_name.to_token_tree_with_prefix(TUPLE_FIELD_PREFIX), ); } Ok(()) })?; } // Arrow // Self::Variant { a, b, c } => match_body.puncts("=>"); // Body of this variant // Note that the fields are available as locals because of the match destructuring above // { // encoder.encode_u32(n)?; // bincode::Encode::encode(a, encoder)?; // bincode::Encode::encode(b, encoder)?; // bincode::Encode::encode(c, encoder)?; // } match_body.group(Delimiter::Brace, |body| { // variant index body.push_parsed(format!("::encode", crate_name))?; body.group(Delimiter::Parenthesis, |args| { args.punct('&'); args.group(Delimiter::Parenthesis, |num| { num.extend(variant_index); Ok(()) })?; args.punct(','); args.push_parsed("encoder")?; Ok(()) })?; body.punct('?'); body.punct(';'); // If we have any fields, encode them all one by one if let Some(fields) = variant.fields.as_ref() { for field_name in fields.names() { let attributes = field_name .attributes() .get_attribute::()? .unwrap_or_default(); if attributes.with_serde { body.push_parsed(format!( "{0}::Encode::encode(&{0}::serde::Compat({1}), encoder)?;", crate_name, field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX), ))?; } else { body.push_parsed(format!( "{0}::Encode::encode({1}, encoder)?;", crate_name, field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX), ))?; } } } body.push_parsed("core::result::Result::Ok(())")?; Ok(()) })?; match_body.punct(','); } Ok(()) })?; Ok(()) })?; Ok(()) } /// If we're encoding an empty enum, we need to add an empty case in the form of: /// `_ => core::unreachable!(),` fn encode_empty_enum_case(&self, builder: &mut StreamBuilder) -> Result { builder.push_parsed("_ => core::unreachable!()").map(|_| ()) } /// Build the catch-all case for an int-to-enum decode implementation fn invalid_variant_case(&self, enum_name: &str, result: &mut StreamBuilder) -> Result { let crate_name = self.attributes.crate_name.as_str(); // we'll be generating: // variant => Err( // bincode::error::DecodeError::UnexpectedVariant { // found: variant, // type_name: // allowed: ..., // } // ) // // Where allowed is either: // - bincode::error::AllowedEnumVariants::Range { min: 0, max: } // if we have no fixed value variants // - bincode::error::AllowedEnumVariants::Allowed(&[, , ...]) // if we have fixed value variants result.ident_str("variant"); result.puncts("=>"); result.push_parsed("core::result::Result::Err")?; result.group(Delimiter::Parenthesis, |err_inner| { err_inner.push_parsed(format!( "{}::error::DecodeError::UnexpectedVariant", crate_name ))?; err_inner.group(Delimiter::Brace, |variant_inner| { variant_inner.ident_str("found"); variant_inner.punct(':'); variant_inner.ident_str("variant"); variant_inner.punct(','); variant_inner.ident_str("type_name"); variant_inner.punct(':'); variant_inner.lit_str(enum_name); variant_inner.punct(','); variant_inner.ident_str("allowed"); variant_inner.punct(':'); if self.variants.iter().any(|i| i.value.is_some()) { // we have fixed values, implement AllowedEnumVariants::Allowed variant_inner.push_parsed(format!( "&{}::error::AllowedEnumVariants::Allowed", crate_name ))?; variant_inner.group(Delimiter::Parenthesis, |allowed_inner| { allowed_inner.punct('&'); allowed_inner.group(Delimiter::Bracket, |allowed_slice| { for (idx, (ident, _)) in self.iter_fields().enumerate() { if idx != 0 { allowed_slice.punct(','); } allowed_slice.extend(ident); } Ok(()) })?; Ok(()) })?; } else { // no fixed values, implement a range variant_inner.push_parsed(format!( "&{0}::error::AllowedEnumVariants::Range {{ min: 0, max: {1} }}", crate_name, self.variants.len() - 1 ))?; } Ok(()) })?; Ok(()) })?; Ok(()) } pub fn generate_decode(self, generator: &mut Generator) -> Result<()> { let crate_name = self.attributes.crate_name.as_str(); let decode_context = if let Some((decode_context, _)) = &self.attributes.decode_context { decode_context.as_str() } else { "__Context" }; // Remember to keep this mostly in sync with generate_borrow_decode let enum_name = generator.target_name().to_string(); let mut impl_for = generator.impl_for(format!("{}::Decode", crate_name)); if self.attributes.decode_context.is_none() { impl_for = impl_for.with_impl_generics(["__Context"]); } impl_for .with_trait_generics([decode_context]) .modify_generic_constraints(|generics, where_constraints| { if let Some((bounds, lit)) = (self.attributes.decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) { where_constraints.clear(); where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?; } else { for g in generics.iter_generics() { where_constraints.push_constraint(g, format!("{}::Decode<__Context>", crate_name))?; } } Ok(()) })? .generate_fn("decode") .with_generic_deps("__D", [format!("{}::de::Decoder", crate_name, decode_context)]) .with_arg("decoder", "&mut __D") .with_return_type(format!("core::result::Result", crate_name)) .body(|fn_builder| { if self.variants.is_empty() { fn_builder.push_parsed(format!( "core::result::Result::Err({}::error::DecodeError::EmptyEnum {{ type_name: core::any::type_name::() }})", crate_name ))?; } else { fn_builder .push_parsed(format!( "let variant_index = >::decode(decoder)?;", crate_name ))?; fn_builder.push_parsed("match variant_index")?; fn_builder.group(Delimiter::Brace, |variant_case| { for (mut variant_index, variant) in self.iter_fields() { // idx => Ok(..) if variant_index.len() > 1 { variant_case.push_parsed("x if x == ")?; variant_case.extend(variant_index); } else { variant_case.push(variant_index.remove(0)); } variant_case.puncts("=>"); variant_case.push_parsed("core::result::Result::Ok")?; variant_case.group(Delimiter::Parenthesis, |variant_case_body| { // Self::Variant { } // Self::Variant { 0: ..., 1: ... 2: ... }, // Self::Variant { a: ..., b: ... c: ... }, variant_case_body.ident_str("Self"); variant_case_body.puncts("::"); variant_case_body.ident(variant.name.clone()); variant_case_body.group(Delimiter::Brace, |variant_body| { if let Some(fields) = variant.fields.as_ref() { let is_tuple = matches!(fields, Fields::Tuple(_)); for (idx, field) in fields.names().into_iter().enumerate() { if is_tuple { variant_body.lit_usize(idx); } else { variant_body.ident(field.unwrap_ident().clone()); } variant_body.punct(':'); let attributes = field.attributes().get_attribute::()?.unwrap_or_default(); if attributes.with_serde { variant_body .push_parsed(format!( "<{0}::serde::Compat<_> as {0}::Decode::<__D::Context>>::decode(decoder)?.0,", crate_name ))?; } else { variant_body .push_parsed(format!( "{}::Decode::<__D::Context>::decode(decoder)?,", crate_name ))?; } } } Ok(()) })?; Ok(()) })?; variant_case.punct(','); } // invalid idx self.invalid_variant_case(&enum_name, variant_case) })?; } Ok(()) })?; self.generate_borrow_decode(generator)?; Ok(()) } pub fn generate_borrow_decode(self, generator: &mut Generator) -> Result<()> { let crate_name = &self.attributes.crate_name; let decode_context = if let Some((decode_context, _)) = &self.attributes.decode_context { decode_context.as_str() } else { "__Context" }; // Remember to keep this mostly in sync with generate_decode let enum_name = generator.target_name().to_string(); let mut impl_for = generator .impl_for_with_lifetimes(format!("{}::BorrowDecode", crate_name), ["__de"]) .with_trait_generics([decode_context]); if self.attributes.decode_context.is_none() { impl_for = impl_for.with_impl_generics(["__Context"]); } impl_for .modify_generic_constraints(|generics, where_constraints| { if let Some((bounds, lit)) = (self.attributes.borrow_decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) { where_constraints.clear(); where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?; } else { for g in generics.iter_generics() { where_constraints.push_constraint(g, format!("{}::de::BorrowDecode<'__de, {}>", crate_name, decode_context)).unwrap(); } for lt in generics.iter_lifetimes() { where_constraints.push_parsed_constraint(format!("'__de: '{}", lt.ident))?; } } Ok(()) })? .generate_fn("borrow_decode") .with_generic_deps("__D", [format!("{}::de::BorrowDecoder<'__de, Context = {}>", crate_name, decode_context)]) .with_arg("decoder", "&mut __D") .with_return_type(format!("core::result::Result", crate_name)) .body(|fn_builder| { if self.variants.is_empty() { fn_builder.push_parsed(format!( "core::result::Result::Err({}::error::DecodeError::EmptyEnum {{ type_name: core::any::type_name::() }})", crate_name ))?; } else { fn_builder .push_parsed(format!("let variant_index = >::decode(decoder)?;", crate_name))?; fn_builder.push_parsed("match variant_index")?; fn_builder.group(Delimiter::Brace, |variant_case| { for (mut variant_index, variant) in self.iter_fields() { // idx => Ok(..) if variant_index.len() > 1 { variant_case.push_parsed("x if x == ")?; variant_case.extend(variant_index); } else { variant_case.push(variant_index.remove(0)); } variant_case.puncts("=>"); variant_case.push_parsed("core::result::Result::Ok")?; variant_case.group(Delimiter::Parenthesis, |variant_case_body| { // Self::Variant { } // Self::Variant { 0: ..., 1: ... 2: ... }, // Self::Variant { a: ..., b: ... c: ... }, variant_case_body.ident_str("Self"); variant_case_body.puncts("::"); variant_case_body.ident(variant.name.clone()); variant_case_body.group(Delimiter::Brace, |variant_body| { if let Some(fields) = variant.fields.as_ref() { let is_tuple = matches!(fields, Fields::Tuple(_)); for (idx, field) in fields.names().into_iter().enumerate() { if is_tuple { variant_body.lit_usize(idx); } else { variant_body.ident(field.unwrap_ident().clone()); } variant_body.punct(':'); let attributes = field.attributes().get_attribute::()?.unwrap_or_default(); if attributes.with_serde { variant_body .push_parsed(format!("<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode::<__D::Context>>::borrow_decode(decoder)?.0,", crate_name))?; } else { variant_body.push_parsed(format!("{}::BorrowDecode::<__D::Context>::borrow_decode(decoder)?,", crate_name))?; } } } Ok(()) })?; Ok(()) })?; variant_case.punct(','); } // invalid idx self.invalid_variant_case(&enum_name, variant_case) })?; } Ok(()) })?; Ok(()) } } struct EnumVariantIterator<'a> { variants: &'a [EnumVariant], idx: usize, } impl<'a> Iterator for EnumVariantIterator<'a> { type Item = (Vec, &'a EnumVariant); fn next(&mut self) -> Option { let idx = self.idx; let variant = self.variants.get(self.idx)?; self.idx += 1; let tokens = vec![TokenTree::Literal(Literal::u32_suffixed(idx as u32))]; Some((tokens, variant)) } } bincode_derive-2.0.1/src/derive_struct.rs000064400000000000000000000233411046102023000166070ustar 00000000000000use crate::attribute::{ContainerAttributes, FieldAttributes}; use virtue::prelude::*; pub(crate) struct DeriveStruct { pub fields: Option, pub attributes: ContainerAttributes, } impl DeriveStruct { pub fn generate_encode(self, generator: &mut Generator) -> Result<()> { let crate_name = &self.attributes.crate_name; generator .impl_for(format!("{}::Encode", crate_name)) .modify_generic_constraints(|generics, where_constraints| { if let Some((bounds, lit)) = (self.attributes.encode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) { where_constraints.clear(); where_constraints .push_parsed_constraint(bounds) .map_err(|e| e.with_span(lit.span()))?; } else { for g in generics.iter_generics() { where_constraints .push_constraint(g, format!("{}::Encode", crate_name)) .unwrap(); } } Ok(()) })? .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| { if let Some(fields) = self.fields.as_ref() { for field in fields.names() { let attributes = field .attributes() .get_attribute::()? .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("core::result::Result::Ok(())")?; Ok(()) })?; Ok(()) } pub fn generate_decode(self, generator: &mut Generator) -> Result<()> { // Remember to keep this mostly in sync with generate_borrow_decode let crate_name = &self.attributes.crate_name; let decode_context = if let Some((decode_context, _)) = &self.attributes.decode_context { decode_context.as_str() } else { "__Context" }; let mut impl_for = generator.impl_for(format!("{}::Decode", crate_name)); if self.attributes.decode_context.is_none() { impl_for = impl_for.with_impl_generics(["__Context"]); } impl_for .with_trait_generics([decode_context]) .modify_generic_constraints(|generics, where_constraints| { if let Some((bounds, lit)) = (self.attributes.decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) { where_constraints.clear(); where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?; } else { for g in generics.iter_generics() { where_constraints.push_constraint(g, format!("{}::Decode<{}>", crate_name, decode_context)).unwrap(); } } Ok(()) })? .generate_fn("decode") .with_generic_deps("__D", [format!("{}::de::Decoder", crate_name, decode_context)]) .with_arg("decoder", "&mut __D") .with_return_type(format!("core::result::Result", crate_name)) .body(|fn_body| { // Ok(Self { fn_body.push_parsed("core::result::Result::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)?, // ... // } if let Some(fields) = self.fields.as_ref() { for field in fields.names() { let attributes = field.attributes().get_attribute::()?.unwrap_or_default(); if attributes.with_serde { struct_body .push_parsed(format!( "{1}: (<{0}::serde::Compat<_> as {0}::Decode::<{2}>>::decode(decoder)?).0,", crate_name, field, decode_context, ))?; } else { struct_body .push_parsed(format!( "{1}: {0}::Decode::decode(decoder)?,", crate_name, field ))?; } } } Ok(()) })?; Ok(()) })?; Ok(()) })?; self.generate_borrow_decode(generator)?; Ok(()) } pub fn generate_borrow_decode(self, generator: &mut Generator) -> Result<()> { // Remember to keep this mostly in sync with generate_decode let crate_name = self.attributes.crate_name; let decode_context = if let Some((decode_context, _)) = &self.attributes.decode_context { decode_context.as_str() } else { "__Context" }; let mut impl_for = generator .impl_for_with_lifetimes(format!("{}::BorrowDecode", crate_name), ["__de"]) .with_trait_generics([decode_context]); if self.attributes.decode_context.is_none() { impl_for = impl_for.with_impl_generics(["__Context"]); } impl_for .modify_generic_constraints(|generics, where_constraints| { if let Some((bounds, lit)) = (self.attributes.borrow_decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) { where_constraints.clear(); where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?; } else { for g in generics.iter_generics() { where_constraints.push_constraint(g, format!("{}::de::BorrowDecode<'__de, {}>", crate_name, decode_context)).unwrap(); } for lt in generics.iter_lifetimes() { where_constraints.push_parsed_constraint(format!("'__de: '{}", lt.ident))?; } } Ok(()) })? .generate_fn("borrow_decode") .with_generic_deps("__D", [format!("{}::de::BorrowDecoder<'__de, Context = {}>", crate_name, decode_context)]) .with_arg("decoder", "&mut __D") .with_return_type(format!("core::result::Result", crate_name)) .body(|fn_body| { // Ok(Self { fn_body.push_parsed("core::result::Result::Ok")?; fn_body.group(Delimiter::Parenthesis, |ok_group| { ok_group.ident_str("Self"); ok_group.group(Delimiter::Brace, |struct_body| { if let Some(fields) = self.fields.as_ref() { for field in fields.names() { let attributes = field.attributes().get_attribute::()?.unwrap_or_default(); if attributes.with_serde { struct_body .push_parsed(format!( "{1}: (<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode::<'_, {2}>>::borrow_decode(decoder)?).0,", crate_name, field, decode_context, ))?; } else { struct_body .push_parsed(format!( "{1}: {0}::BorrowDecode::<'_, {2}>::borrow_decode(decoder)?,", crate_name, field, decode_context, ))?; } } } Ok(()) })?; Ok(()) })?; Ok(()) })?; Ok(()) } } bincode_derive-2.0.1/src/lib.rs000064400000000000000000000061701046102023000144740ustar 00000000000000mod attribute; mod derive_enum; mod derive_struct; use attribute::ContainerAttributes; use virtue::prelude::*; #[proc_macro_derive(Encode, attributes(bincode))] pub fn derive_encode(input: proc_macro::TokenStream) -> proc_macro::TokenStream { derive_encode_inner(input).unwrap_or_else(|e| e.into_token_stream()) } fn derive_encode_inner(input: TokenStream) -> Result { let parse = Parse::new(input)?; let (mut generator, attributes, body) = parse.into_generator(); let attributes = attributes .get_attribute::()? .unwrap_or_default(); match body { Body::Struct(body) => { derive_struct::DeriveStruct { fields: body.fields, attributes, } .generate_encode(&mut generator)?; } Body::Enum(body) => { derive_enum::DeriveEnum { variants: body.variants, attributes, } .generate_encode(&mut generator)?; } } generator.export_to_file("bincode", "Encode"); generator.finish() } #[proc_macro_derive(Decode, attributes(bincode))] pub fn derive_decode(input: proc_macro::TokenStream) -> proc_macro::TokenStream { derive_decode_inner(input).unwrap_or_else(|e| e.into_token_stream()) } fn derive_decode_inner(input: TokenStream) -> Result { let parse = Parse::new(input)?; let (mut generator, attributes, body) = parse.into_generator(); let attributes = attributes .get_attribute::()? .unwrap_or_default(); match body { Body::Struct(body) => { derive_struct::DeriveStruct { fields: body.fields, attributes, } .generate_decode(&mut generator)?; } Body::Enum(body) => { derive_enum::DeriveEnum { variants: body.variants, attributes, } .generate_decode(&mut generator)?; } } generator.export_to_file("bincode", "Decode"); generator.finish() } #[proc_macro_derive(BorrowDecode, attributes(bincode))] pub fn derive_borrow_decode(input: proc_macro::TokenStream) -> proc_macro::TokenStream { derive_borrow_decode_inner(input).unwrap_or_else(|e| e.into_token_stream()) } fn derive_borrow_decode_inner(input: TokenStream) -> Result { let parse = Parse::new(input)?; let (mut generator, attributes, body) = parse.into_generator(); let attributes = attributes .get_attribute::()? .unwrap_or_default(); match body { Body::Struct(body) => { derive_struct::DeriveStruct { fields: body.fields, attributes, } .generate_borrow_decode(&mut generator)?; } Body::Enum(body) => { derive_enum::DeriveEnum { variants: body.variants, attributes, } .generate_borrow_decode(&mut generator)?; } } generator.export_to_file("bincode", "BorrowDecode"); generator.finish() }