Skip to content

Commit

Permalink
Feat: Allow generics in method return types and arguments.
Browse files Browse the repository at this point in the history
Partial fix fo #18

This changeset allows generics to method return types and arguments.
Generic impl traits are still not supported in return position (yet?).
  • Loading branch information
o0Ignition0o authored and Jeremy Lempereur committed Nov 19, 2024
1 parent 9f2956b commit 83ea074
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 2 deletions.
18 changes: 16 additions & 2 deletions faux_macros/src/methods/morphed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub struct Signature<'a> {

pub struct MethodData<'a> {
receiver: Receiver,
generics: syn::Generics,
arg_types: Vec<WhenArg<'a>>,
is_private: bool,
}
Expand Down Expand Up @@ -89,6 +90,7 @@ impl<'a> Signature<'a> {
vis: &syn::Visibility,
) -> Signature<'a> {
let receiver = Receiver::from_signature(signature);
let generics = signature.generics.clone();

let output = match &signature.output {
syn::ReturnType::Default => None,
Expand All @@ -110,6 +112,7 @@ impl<'a> Signature<'a> {

MethodData {
receiver,
generics,
arg_types,
is_private: trait_path.is_none() && *vis == syn::Visibility::Inherited,
}
Expand Down Expand Up @@ -332,6 +335,7 @@ impl<'a> MethodData<'a> {
let MethodData {
arg_types,
receiver,
generics,
..
} = self;
let receiver_ty = &receiver.ty;
Expand All @@ -345,8 +349,18 @@ impl<'a> MethodData<'a> {
let output = output.unwrap_or(&empty);
let name_str = name.to_string();

let generics_contents = &generics.params;

let maybe_comma = if generics_contents.is_empty() {
quote! {}
} else {
quote! { , }
};

let generics_where_clause = &generics.where_clause;

let when_method = syn::parse_quote! {
pub fn #when_ident<'m>(&'m mut self) -> faux::When<'m, #receiver_ty, (#(#arg_types),*), #output, faux::matcher::AnyInvocation> {
pub fn #when_ident<'m #maybe_comma #generics_contents>(&'m mut self) -> faux::When<'m, #receiver_ty, (#(#arg_types),*), #output, faux::matcher::AnyInvocation> #generics_where_clause {
match &mut self.0 {
faux::MaybeFaux::Faux(_maybe_faux_faux) => faux::When::new(
<Self>::#faux_ident,
Expand All @@ -362,7 +376,7 @@ impl<'a> MethodData<'a> {
let faux_method = syn::parse_quote! {
#[allow(clippy::needless_arbitrary_self_type)]
#[allow(clippy::boxed_local)]
pub fn #faux_ident(self: #receiver_ty, _: (#(#arg_types),*)) -> #output {
pub fn #faux_ident #generics (self: #receiver_ty, _: (#(#arg_types),*)) -> #output #generics_where_clause {
panic!(#panic_message)
}
};
Expand Down
77 changes: 77 additions & 0 deletions tests/generic_method_return.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#![allow(clippy::disallowed_names)]

pub trait MyTrait {}

#[derive(Clone, PartialEq, Debug)]
struct Entity {}
impl MyTrait for Entity {}

#[faux::create]
pub struct Foo {}

#[faux::create]
pub struct Bar {}



#[faux::methods]
impl Foo {
pub fn foo<E: MyTrait>(&self, _e: E) -> E {
todo!()
}
pub fn bar<E: MyTrait, F: MyTrait>(&self, _e: E, _f: F) -> Result<E, F> {
todo!()
}
pub fn baz<E>(&self, _e: E) -> E where E: MyTrait {
todo!()
}
}


#[faux::create]
struct AsyncFoo {}
#[faux::methods]
impl AsyncFoo {
pub async fn foo<E: MyTrait>(&self, _e: E) -> E {
todo!()
}
pub async fn bar<E: MyTrait, F: MyTrait>(&self, _e: E, _f: F) -> Result<E, F> {
todo!()
}
pub async fn baz<E>(&self, _e: E) -> E where E: MyTrait {
todo!()
}
}


#[test]
fn generics() {
let mut foo = Foo::faux();
faux::when!(foo.foo).then_return(Entity {});
assert_eq!(foo.foo(Entity {}), Entity {});

let mut bar = Foo::faux();
faux::when!(bar.bar).then_return(Ok::<_, Entity>(Entity {}));
assert_eq!(bar.bar(Entity {}, Entity {}), Ok(Entity {}));

let mut baz = Foo::faux();
faux::when!(baz.baz).then_return(Entity {});
assert_eq!(baz.baz(Entity {}), Entity {});
}

#[test]
fn generic_tests_async() {
let mut foo: AsyncFoo = AsyncFoo::faux();
faux::when!(foo.foo).then_return(Entity {});

let mut bar = AsyncFoo::faux();
faux::when!(bar.bar).then_return(Ok::<_, Entity>(Entity {}));

let mut baz = AsyncFoo::faux();
faux::when!(baz.baz).then_return(Entity {});
futures::executor::block_on(async {
assert_eq!(foo.foo(Entity {}).await, Entity {});
assert_eq!(bar.bar(Entity {}, Entity {}).await, Ok(Entity {}));
assert_eq!(baz.baz(Entity {}).await, Entity {});
});
}

0 comments on commit 83ea074

Please sign in to comment.