Skip to content

Commit

Permalink
Merge pull request #28 from matteopolak/feature/add_crate_alias
Browse files Browse the repository at this point in the history
feat: add `#[bitcode(crate = "...")]` for crate alias
  • Loading branch information
finnbear authored Jul 14, 2024
2 parents 0ab408c + 64b4723 commit d615984
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 24 deletions.
36 changes: 35 additions & 1 deletion bitcode_derive/src/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use syn::{parse2, Attribute, Expr, ExprLit, Lit, Meta, Path, Result, Token, Type

enum BitcodeAttr {
BoundType(Type),
CrateAlias(Path),
}

impl BitcodeAttr {
Expand All @@ -30,6 +31,26 @@ impl BitcodeAttr {
}
_ => err(&nested, "expected name value"),
},
"crate" => match nested {
Meta::NameValue(name_value) => {
let expr = &name_value.value;
let str_lit = match expr {
Expr::Lit(ExprLit {
lit: Lit::Str(v), ..
}) => v,
_ => return err(&expr, "expected path string e.g. \"my_crate::bitcode\""),
};

let mut path = syn::parse_str::<Path>(&str_lit.value())
.map_err(|e| error(str_lit, &e.to_string()))?;

// ensure there's a leading `::`
path.leading_colon = Some(Token![::](str_lit.span()));

Ok(Self::CrateAlias(path))
}
_ => err(&nested, "expected name value"),
},
_ => err(&nested, "unknown attribute"),
}
}
Expand All @@ -47,13 +68,23 @@ impl BitcodeAttr {
err(nested, "can only apply bound to fields")
}
}
Self::CrateAlias(crate_name) => {
if let AttrType::Derive = attrs.attr_type {
attrs.crate_name = crate_name;
Ok(())
} else {
err(nested, "can only apply crate rename to derives")
}
}
}
}
}

#[derive(Clone)]
pub struct BitcodeAttrs {
attr_type: AttrType,
/// The crate name to use for the generated code, defaults to "bitcode".
pub crate_name: Path,
}

#[derive(Clone)]
Expand All @@ -65,7 +96,10 @@ enum AttrType {

impl BitcodeAttrs {
fn new(attr_type: AttrType) -> Self {
Self { attr_type }
Self {
attr_type,
crate_name: syn::parse_str("bitcode").expect("invalid crate name"),
}
}

pub fn bound_type(&self) -> Option<Type> {
Expand Down
17 changes: 10 additions & 7 deletions bitcode_derive/src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ impl Item {
impl crate::shared::Item for Item {
fn field_impl(
self,
crate_name: &Path,
field_name: TokenStream,
global_field_name: TokenStream,
real_field_name: TokenStream,
Expand All @@ -43,7 +44,7 @@ impl crate::shared::Item for Item {
match self {
Self::Type => {
let de_type = replace_lifetimes(field_type, DE_LIFETIME);
let private = private();
let private = private(crate_name);
let de = de_lifetime();
quote! {
#global_field_name: <#de_type as #private::Decode<#de>>::Decoder,
Expand All @@ -61,7 +62,7 @@ impl crate::shared::Item for Item {
},
Self::DecodeInPlace => {
let de_type = replace_lifetimes(field_type, DE_LIFETIME);
let private = private();
let private = private(crate_name);
quote! {
self.#global_field_name.decode_in_place(#private::uninit_field!(out.#real_field_name: #de_type));
}
Expand All @@ -83,6 +84,7 @@ impl crate::shared::Item for Item {

fn enum_impl(
self,
crate_name: &Path,
variant_count: usize,
pattern: impl Fn(usize) -> TokenStream,
inner: impl Fn(Self, usize) -> TokenStream,
Expand All @@ -97,7 +99,7 @@ impl crate::shared::Item for Item {
let inners: TokenStream = (0..variant_count).map(|i| inner(self, i)).collect();
let variants = decode_variants
.then(|| {
let private = private();
let private = private(crate_name);
let c_style = inners.is_empty();
quote! { variants: #private::VariantDecoder<#de, #variant_count, #c_style>, }
})
Expand All @@ -119,7 +121,7 @@ impl crate::shared::Item for Item {
}
Self::Populate => {
if never {
let private = private();
let private = private(crate_name);
return quote! {
if __length != 0 {
return #private::invalid_enum_variant();
Expand Down Expand Up @@ -220,14 +222,15 @@ impl crate::shared::Derive<{ Item::COUNT }> for Decode {
type Item = Item;
const ALL: [Self::Item; Item::COUNT] = Item::ALL;

fn bound(&self) -> Path {
let private = private();
fn bound(&self, crate_name: &Path) -> Path {
let private = private(crate_name);
let de = de_lifetime();
parse_quote!(#private::Decode<#de>)
}

fn derive_impl(
&self,
crate_name: &Path,
output: [TokenStream; Item::COUNT],
ident: Ident,
mut generics: Generics,
Expand Down Expand Up @@ -281,7 +284,7 @@ impl crate::shared::Derive<{ Item::COUNT }> for Decode {

let decoder_ident = Ident::new(&format!("{ident}Decoder"), Span::call_site());
let decoder_ty = quote! { #decoder_ident #decoder_generics };
let private = private();
let private = private(crate_name);

quote! {
const _: () = {
Expand Down
13 changes: 8 additions & 5 deletions bitcode_derive/src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ impl Item {
impl crate::shared::Item for Item {
fn field_impl(
self,
crate_name: &Path,
field_name: TokenStream,
global_field_name: TokenStream,
real_field_name: TokenStream,
Expand All @@ -35,7 +36,7 @@ impl crate::shared::Item for Item {
match self {
Self::Type => {
let static_type = replace_lifetimes(field_type, "static");
let private = private();
let private = private(crate_name);
quote! {
#global_field_name: <#static_type as #private::Encode>::Encoder,
}
Expand Down Expand Up @@ -99,6 +100,7 @@ impl crate::shared::Item for Item {

fn enum_impl(
self,
crate_name: &Path,
variant_count: usize,
pattern: impl Fn(usize) -> TokenStream,
inner: impl Fn(Self, usize) -> TokenStream,
Expand All @@ -109,7 +111,7 @@ impl crate::shared::Item for Item {
Self::Type => {
let variants = encode_variants
.then(|| {
let private = private();
let private = private(crate_name);
quote! { variants: #private::VariantEncoder<#variant_count>, }
})
.unwrap_or_default();
Expand Down Expand Up @@ -224,13 +226,14 @@ impl crate::shared::Derive<{ Item::COUNT }> for Encode {
type Item = Item;
const ALL: [Self::Item; Item::COUNT] = Item::ALL;

fn bound(&self) -> Path {
let private = private();
fn bound(&self, crate_name: &Path) -> Path {
let private = private(crate_name);
parse_quote!(#private::Encode)
}

fn derive_impl(
&self,
crate_name: &Path,
output: [TokenStream; Item::COUNT],
ident: Ident,
mut generics: Generics,
Expand All @@ -248,7 +251,7 @@ impl crate::shared::Derive<{ Item::COUNT }> for Encode {
output;
let encoder_ident = Ident::new(&format!("{ident}Encoder"), Span::call_site());
let encoder_ty = quote! { #encoder_ident #encoder_generics };
let private = private();
let private = private(crate_name);

quote! {
const _: () = {
Expand Down
4 changes: 2 additions & 2 deletions bitcode_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ pub(crate) fn err<T>(spanned: &impl Spanned, s: &str) -> Result<T, Error> {
Err(error(spanned, s))
}

pub(crate) fn private() -> proc_macro2::TokenStream {
quote! { bitcode::__private }
pub(crate) fn private(crate_name: &syn::Path) -> proc_macro2::TokenStream {
quote! { #crate_name::__private }
}
38 changes: 29 additions & 9 deletions bitcode_derive/src/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub fn variant_index(i: usize) -> VariantIndex {
pub trait Item: Copy + Sized {
fn field_impl(
self,
crate_name: &Path,
field_name: TokenStream,
global_field_name: TokenStream,
real_field_name: TokenStream,
Expand All @@ -32,12 +33,18 @@ pub trait Item: Copy + Sized {

fn enum_impl(
self,
crate_name: &Path,
variant_count: usize,
pattern: impl Fn(usize) -> TokenStream,
inner: impl Fn(Self, usize) -> TokenStream,
) -> TokenStream;

fn field_impls(self, global_prefix: Option<&str>, fields: &Fields) -> TokenStream {
fn field_impls(
self,
crate_name: &Path,
global_prefix: Option<&str>,
fields: &Fields,
) -> TokenStream {
fields
.iter()
.enumerate()
Expand All @@ -52,7 +59,7 @@ pub trait Item: Copy + Sized {
})
.unwrap_or_else(|| name.clone());

self.field_impl(name, global_name, real_name, &field.ty)
self.field_impl(crate_name, name, global_name, real_name, &field.ty)
})
.collect()
}
Expand All @@ -63,18 +70,20 @@ pub trait Derive<const ITEM_COUNT: usize> {
const ALL: [Self::Item; ITEM_COUNT];

/// `Encode` in `T: Encode`.
fn bound(&self) -> Path;
fn bound(&self, crate_name: &Path) -> Path;

/// Generates the derive implementation.
fn derive_impl(
&self,
crate_name: &Path,
output: [TokenStream; ITEM_COUNT],
ident: Ident,
generics: Generics,
) -> TokenStream;

fn field_attrs(
&self,
crate_name: &Path,
fields: &Fields,
attrs: &BitcodeAttrs,
bounds: &mut FieldBounds,
Expand All @@ -83,7 +92,7 @@ pub trait Derive<const ITEM_COUNT: usize> {
.iter()
.map(|field| {
let field_attrs = BitcodeAttrs::parse_field(&field.attrs, attrs)?;
bounds.add_bound_type(field.clone(), &field_attrs, self.bound());
bounds.add_bound_type(field.clone(), &field_attrs, self.bound(crate_name));
Ok(field_attrs)
})
.collect()
Expand All @@ -98,12 +107,13 @@ pub trait Derive<const ITEM_COUNT: usize> {
let output = match input.data {
Data::Struct(DataStruct { ref fields, .. }) => {
// Only used for adding `bounds`. Would be used by `#[bitcode(with_serde)]`.
let field_attrs = self.field_attrs(fields, &attrs, &mut bounds)?;
let field_attrs =
self.field_attrs(&attrs.crate_name, fields, &attrs, &mut bounds)?;
let _ = field_attrs;

let destructure_fields = &destructure_fields(fields);
Self::ALL.map(|item| {
let field_impls = item.field_impls(None, fields);
let field_impls = item.field_impls(&attrs.crate_name, None, fields);
item.struct_impl(&ident, destructure_fields, &field_impls)
})
}
Expand All @@ -122,13 +132,14 @@ pub trait Derive<const ITEM_COUNT: usize> {
.iter()
.map(|variant| {
let attrs = BitcodeAttrs::parse_variant(&variant.attrs, &attrs)?;
self.field_attrs(&variant.fields, &attrs, &mut bounds)
self.field_attrs(&attrs.crate_name, &variant.fields, &attrs, &mut bounds)
})
.collect::<Result<Vec<_>>>()?;
let _ = variant_attrs;

Self::ALL.map(|item| {
item.enum_impl(
&attrs.crate_name,
data_enum.variants.len(),
|i| {
let variant = &data_enum.variants[i];
Expand All @@ -141,14 +152,23 @@ pub trait Derive<const ITEM_COUNT: usize> {
|item, i| {
let variant = &data_enum.variants[i];
let global_prefix = format!("{}_", &variant.ident);
item.field_impls(Some(&global_prefix), &variant.fields)
item.field_impls(
&attrs.crate_name,
Some(&global_prefix),
&variant.fields,
)
},
)
})
}
Data::Union(_) => err(&ident, "unions are not supported")?,
};
Ok(self.derive_impl(output, ident, bounds.added_to(input.generics)))
Ok(self.derive_impl(
&attrs.crate_name,
output,
ident,
bounds.added_to(input.generics),
))
}
}

Expand Down

0 comments on commit d615984

Please sign in to comment.