Skip to content

Commit

Permalink
support where clauses, generics, and additional trait bounds
Browse files Browse the repository at this point in the history
  • Loading branch information
romnn committed May 24, 2024
1 parent 5a45b80 commit a281a11
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 4 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 29 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
use quote::quote;
use syn::parse::Parse;

#[proc_macro_attribute]
pub fn box_dyn(
_args: proc_macro::TokenStream,
args: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
// let mut input: syn::DeriveInput = syn::parse2(input.into()).unwrap();
let additional_bounds = syn::parse_macro_input!(args with syn::punctuated::Punctuated::<syn::Path, syn::Token![,]>::parse_terminated);
// let args_parsed: syn::punctuated::Punctuated<syn::Path, syn::Token![,]>::parse_terminated =
// syn::parse2(input.into()).unwrap();
// let args_parsed = syn::punctuated::Punctuated::<syn::Path, syn::Token![,]>::parse_terminated
// .parse2(args)
// .unwrap();
let trait_item: syn::ItemTrait = syn::parse2(input.into()).unwrap();
let trait_name = &trait_item.ident;
let trait_generics = &trait_item.generics;
// let trait_with_generics = quote! { #trait_name };
// generics
// dbg!(trait_name.to_string());

let trait_items: Vec<_> = trait_item
Expand Down Expand Up @@ -102,14 +112,30 @@ pub fn box_dyn(
})
.collect();

let t = quote! { __BoxDynT };
let trait_where_predicates = &trait_generics
.where_clause
.as_ref()
.map(|clause| &clause.predicates);
let trait_generic_params = &trait_generics.params;

let t_bounds: Vec<_> = [quote! { #trait_name #trait_generics }]
.into_iter()
.chain(additional_bounds.into_iter().map(|b| quote! { #b }))
.collect();

let out = quote! {
#trait_item

impl<T> #trait_name for Box<T> where T: #trait_name {
impl<#t, #trait_generic_params> #trait_name #trait_generics for Box<#t>
where
#t: #(#t_bounds)+*,
#trait_where_predicates
{
#(#trait_items)*
}
};
// println!("{}", pretty_print(&out));
println!("{}", pretty_print(&out));
out.into()
}

Expand Down
37 changes: 37 additions & 0 deletions tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,41 @@ mod tests {
Some(("a".to_string(), "b".to_string()))
);
}

#[test]
fn generic_trait() {
#[box_dyn::box_dyn]
pub trait GenericTrait<T>: std::fmt::Display {
fn get(&self, input: T) -> T;
}
}

#[test]
fn generic_trait_where_clause() {
pub trait MyOtherTrait {}

#[box_dyn::box_dyn]
pub trait GenericTrait<T>: std::fmt::Display
where
T: MyOtherTrait,
{
fn get(&self, input: T) -> T;
}
}

#[test]
fn additional_bound() {
// #[box_dyn::box_dyn]
pub trait MySuperTrait {}

impl<T> MySuperTrait for T where T: std::fmt::Display {}

// #[box_dyn::box_dyn]
// #[box_dyn::box_dyn(additional_bound: std::fmt::Display)]
// #[box_dyn::box_dyn(std::fmt::Display + std::fmt::Debug)]
#[box_dyn::box_dyn(std::fmt::Display, std::fmt::Debug)]
pub trait MyTrait: MySuperTrait {
fn get(&self) -> String;
}
}
}

0 comments on commit a281a11

Please sign in to comment.