From 068b1120cc728843be074d7d185e8d2cf8add492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Medina?= Date: Mon, 19 Feb 2024 09:43:23 -0800 Subject: [PATCH] wip --- faux_macros/src/create.rs | 25 +- faux_macros/src/methods/morphed.rs | 6 +- faux_macros/src/methods/receiver.rs | 155 ++----------- tests/arbitrary_self.rs | 338 ++++++++++++++-------------- 4 files changed, 207 insertions(+), 317 deletions(-) diff --git a/faux_macros/src/create.rs b/faux_macros/src/create.rs index bd4b152..0b6a11c 100644 --- a/faux_macros/src/create.rs +++ b/faux_macros/src/create.rs @@ -14,6 +14,8 @@ pub struct Mockable { real: syn::ItemStruct, // the morphed definition, wraps the real struct around a MaybeFaux morphed: syn::ItemStruct, + // Whether the real object should be wrapped when putting it in MaybeFaux::Real + self_type: SelfType, } impl Mockable { @@ -43,18 +45,35 @@ impl Mockable { syn::Fields::Unnamed(syn::parse_quote! { (#vis faux::MaybeFaux<#wrapped_self>) }) }; - Mockable { real, morphed } + Mockable { + real, + morphed, + self_type: args.self_type, + } } } impl From for proc_macro::TokenStream { fn from(mockable: Mockable) -> Self { - let Mockable { real, morphed } = mockable; + let Mockable { + real, + morphed, + self_type, + } = mockable; let (impl_generics, ty_generics, where_clause) = real.generics.split_for_impl(); let name = &morphed.ident; let name_str = name.to_string(); let real_name = &real.ident; + let inner = match self_type { + // TODO: deprecate Box + SelfType::Owned | SelfType::Box => { + quote! { ::faux::MaybeFaux<#real_name #ty_generics> } + } + SelfType::Rc => quote! { ::faux::MaybeFaux> }, + SelfType::Arc => quote! { ::faux::MaybeFaux> }, + }; + proc_macro::TokenStream::from(quote! { #morphed @@ -65,7 +84,7 @@ impl From for proc_macro::TokenStream { } unsafe impl #impl_generics ::faux::MockWrapper for #name #ty_generics #where_clause { - type Inner = ::faux::MaybeFaux<#real_name #ty_generics>; + type Inner = #inner; fn inner(self) -> Self::Inner { self.0 diff --git a/faux_macros/src/methods/morphed.rs b/faux_macros/src/methods/morphed.rs index 0fca202..5fc1606 100644 --- a/faux_macros/src/methods/morphed.rs +++ b/faux_macros/src/methods/morphed.rs @@ -232,11 +232,9 @@ impl<'a> Signature<'a> { proxy_real = quote! { std::boxed::Box::new(#proxy_real) }; } - let call_stub = quote! { self.#faux_ident(#args) }; + let call_stub = quote! { wrapper.#faux_ident(#args) }; - method_data - .self_kind - .method_body(real_self, proxy_real, call_stub) + Ok(method_data.self_kind.method_body(proxy_real, call_stub)) } fn proxy_real<'p>( diff --git a/faux_macros/src/methods/receiver.rs b/faux_macros/src/methods/receiver.rs index d6e743c..0c2d9ed 100644 --- a/faux_macros/src/methods/receiver.rs +++ b/faux_macros/src/methods/receiver.rs @@ -1,7 +1,4 @@ -use crate::self_type::SelfType; - use proc_macro2::TokenStream; -use quote::quote; use std::{ boxed::Box, @@ -44,146 +41,22 @@ impl SelfKind { } } - fn matchable_self(&self) -> darling::Result { - let get_self = match self { - SelfKind::Owned - | SelfKind::Pointer(PointerKind::Ref) - | SelfKind::Pointer(PointerKind::MutRef) => { - quote! { self } - } - SelfKind::Pointer(PointerKind::Arc) | SelfKind::Pointer(PointerKind::Rc) => { - quote! { &*self } - } - SelfKind::Pointer(PointerKind::Box) => quote! { *self }, - SelfKind::Pointer(PointerKind::Pin(p)) => { - let unpinned = quote! { unsafe { std::pin::Pin::into_inner_unchecked(self) } }; - match **p { - PointerKind::Ref | PointerKind::MutRef => unpinned, - PointerKind::Rc | PointerKind::Arc => { - let panic_msg = "faux tried to get a unique instance of Self and failed"; - let self_of_receiver = match **p { - PointerKind::Arc => SelfType::Arc, - PointerKind::Rc => SelfType::Rc, - _ => unreachable!(), - }; - let path = self_of_receiver.path().unwrap(); - quote! {{ - match #path::try_unwrap(#unpinned) { - Ok(owned) => owned, - Err(_) => panic!(#panic_msg), - } - }} - } - PointerKind::Box => quote! { *#unpinned }, - PointerKind::Pin(_) => { - return Err(darling::Error::custom("faux does not support nest Pins")); - } - } - } - }; - - Ok(get_self) - } - - pub fn method_body( - &self, - self_type: SelfType, - proxy_real: TokenStream, - call_stub: TokenStream, - ) -> darling::Result { - let get_self = self.matchable_self()?; - - let project_real = match self.project_real(self_type) { - Ok(value) => value, - Err(value) => return value, - }; - - let proxy_real = quote! { - #project_real - #proxy_real - }; - - Ok(syn::parse_quote! { - match &self.0 { - faux::MaybeFaux::Faux(_) => { #call_stub }, - _ => match #get_self { - Self(faux::MaybeFaux::Real(_maybe_faux_real)) => { #proxy_real }, - Self(faux::MaybeFaux::Faux(_)) => unreachable!(), + pub fn method_body(&self, proxy_real: TokenStream, call_stub: TokenStream) -> syn::Expr { + syn::parse_quote! {{ + use ::faux::MockWrapper; + let inner = self.inner(); + if let Some(_) = ::faux::FauxCaller::<_>::try_as_faux(&inner) { + let wrapper = ::faux::MockWrapper::wrap(inner); + #call_stub + } else { + match ::faux::FauxCaller::<_>::try_into_real(inner) { + Some(_maybe_faux_real) => { + #proxy_real + }, + None => unreachable!(), } } - }) - } - - fn project_real(&self, self_type: SelfType) -> Result> { - Ok(match (self, self_type) { - (SelfKind::Owned, SelfType::Owned) - | (SelfKind::Pointer(PointerKind::Ref), SelfType::Owned) - | (SelfKind::Pointer(PointerKind::MutRef), SelfType::Owned) - | (SelfKind::Pointer(PointerKind::Box), SelfType::Box) => quote! {}, - (SelfKind::Pointer(PointerKind::Ref), _) => quote! { - let _maybe_faux_real = &*_maybe_faux_real; - }, - (SelfKind::Pointer(PointerKind::MutRef), SelfType::Box) => quote! { - let _maybe_faux_real = &mut *_maybe_faux_real; - }, - (SelfKind::Owned, SelfType::Box) => quote! { - let _maybe_faux_real = *_maybe_faux_real; - }, - (SelfKind::Pointer(PointerKind::Box), SelfType::Owned) => quote! { - let _maybe_faux_real = std::boxed::Box::new(_maybe_faux_real); - }, - (SelfKind::Pointer(PointerKind::Rc), SelfType::Rc) - | (SelfKind::Pointer(PointerKind::Arc), SelfType::Arc) => quote! { - let _maybe_faux_real = _maybe_faux_real.clone(); - }, - (SelfKind::Pointer(PointerKind::Rc), SelfType::Owned) - | (SelfKind::Pointer(PointerKind::Arc), SelfType::Owned) => { - let self_of_receiver = match self { - SelfKind::Pointer(PointerKind::Arc) => SelfType::Arc, - SelfKind::Pointer(PointerKind::Rc) => SelfType::Rc, - _ => unreachable!(), - }; - let path = self_of_receiver.path(); - let new_path = self_of_receiver.new_path().unwrap(); - let panic_msg = format!("faux tried to get a unique instance of Self from and failed. Consider adding a `self_type = \"{}\"` argument to both the #[create] and #[method] attributes tagging this struct and its impl.", self_of_receiver); - - quote! { - let owned = match #path::try_unwrap(self) { - Ok(owned) => owned, - Err(_) => panic!(#panic_msg), - }; - - let _maybe_faux_real = match owned { - Self(faux::MaybeFaux::Real(_maybe_faux_real)) => #new_path(_maybe_faux_real), - _ => unreachable!() - }; - } - } - (SelfKind::Pointer(PointerKind::Pin(pointer)), SelfType::Owned) => match **pointer { - PointerKind::Ref | PointerKind::MutRef => quote! { - let _maybe_faux_real = unsafe { std::pin::Pin::new_unchecked(_maybe_faux_real) }; - }, - PointerKind::Box => quote! { - let _maybe_faux_real = unsafe { std::pin::Pin::new_unchecked(std::boxed::Box::new(_maybe_faux_real)) }; - }, - PointerKind::Rc | PointerKind::Arc => { - let self_of_receiver = match **pointer { - PointerKind::Arc => SelfType::Arc, - PointerKind::Rc => SelfType::Rc, - _ => unreachable!(), - }; - let new_path = self_of_receiver.new_path().unwrap(); - - quote! { - let _maybe_faux_real = unsafe { std::pin::Pin::new_unchecked(#new_path(_maybe_faux_real)) }; - } - } - PointerKind::Pin(_) => unreachable!(), - }, - (receiver, specified) => { - return Err(Err(darling::Error::custom(format!("faux cannot convert from the receiver_type of this method: `{}`, into the self_type specified: `{}`", receiver, specified)))); - } - }) + }} } } diff --git a/tests/arbitrary_self.rs b/tests/arbitrary_self.rs index 8196060..b5402e2 100644 --- a/tests/arbitrary_self.rs +++ b/tests/arbitrary_self.rs @@ -20,32 +20,32 @@ impl Owned { pub fn by_ref(&self) {} pub fn by_mut_ref(&mut self) {} pub fn by_value(self) {} - #[allow(unused_mut)] - pub fn by_mut_value(mut self) {} - - //self with a type - pub fn by_value2(self: Self) {} - pub fn by_ref2(self: &Self) {} - pub fn by_mut_ref2(self: &mut Self) {} - #[allow(unused_mut)] - pub fn by_mut_value2(mut self: Self) {} - pub fn by_box(self: std::boxed::Box) {} - - // the following two will compile - // but they will only work if self is the *only* - // reference to the object. Otherwise they will panic - // with a message about using the self_type argument instead - pub fn by_rc(self: Rc) {} - pub fn by_arc(self: Arc) {} - - pub fn by_pinmut(self: Pin<&mut Self>) {} - pub fn by_pinmut2(self: Pin<&mut Owned>) {} - pub fn by_pinrc(self: Pin>) {} - pub fn by_pinrc2(self: Pin>) {} - pub fn by_pinarc(self: Pin>) {} - pub fn by_pinarc2(self: Pin>) {} - pub fn by_pinbox(self: Pin>) {} - pub fn by_pinbox2(self: Pin>) {} + q// #[allow(unused_mut)] + // pub fn by_mut_value(mut self) {} + + // //self with a type + // pub fn by_value2(self: Self) {} + // pub fn by_ref2(self: &Self) {} + // pub fn by_mut_ref2(self: &mut Self) {} + // #[allow(unused_mut)] + // pub fn by_mut_value2(mut self: Self) {} + // pub fn by_box(self: std::boxed::Box) {} + + // // the following two will compile + // // but they will only work if self is the *only* + // // reference to the object. Otherwise they will panic + // // with a message about using the self_type argument instead + // pub fn by_rc(self: Rc) {} + // pub fn by_arc(self: Arc) {} + + // pub fn by_pinmut(self: Pin<&mut Self>) {} + // pub fn by_pinmut2(self: Pin<&mut Owned>) {} + // pub fn by_pinrc(self: Pin>) {} + // pub fn by_pinrc2(self: Pin>) {} + // pub fn by_pinarc(self: Pin>) {} + // pub fn by_pinarc2(self: Pin>) {} + // pub fn by_pinbox(self: Pin>) {} + // pub fn by_pinbox2(self: Pin>) {} } #[faux::create(self_type = "Rc")] @@ -57,150 +57,150 @@ impl ByRc { ByRc {} } - pub fn new_rc() -> Rc { - Rc::new(ByRc {}) - } - - pub fn new_rc2() -> Rc { - Rc::new(ByRc {}) - } - - pub fn by_rc(self: Rc) {} - pub fn by_rc2(self: std::rc::Rc) {} - pub fn by_ref(&self) {} -} - -#[faux::create(self_type = "Arc")] -pub struct ByArc {} - -#[faux::methods(self_type = "Arc")] -impl ByArc { - pub fn new() -> ByArc { - ByArc {} - } - - pub fn new_arc() -> Arc { - Arc::new(ByArc {}) - } - - pub fn new_arc2() -> Arc { - Arc::new(ByArc {}) - } - - pub fn by_arc(self: Arc) {} - pub fn by_arc2(self: std::sync::Arc) {} - pub fn by_ref(&self) {} -} - -#[faux::create(self_type = "Box")] -pub struct ByBox {} - -#[faux::methods(self_type = "Box")] -impl ByBox { - pub fn new() -> ByBox { - ByBox {} - } - - pub fn new_box() -> Box { - Box::new(ByBox {}) - } - - pub fn new_box2() -> Box { - Box::new(ByBox {}) - } - - pub fn by_box(self: Box) {} - pub fn by_box2(self: std::boxed::Box) {} - pub fn by_ref(&self) {} - pub fn by_mut_ref(&mut self) {} - pub fn by_value(self) {} -} - -#[test] -fn by_rc_from_owned() { - // getting and invoking real instances/methods works - let real_rcd = Rc::new(Owned::new()); - real_rcd.by_rc(); - - // mocking also works BUT - // mocks need a `&mut` when mocking a method - // so prepare the mock before wrapping it around an Rc - let mut faux_owned = Owned::faux(); - faux::when!(faux_owned.by_rc).then(|_| {}); - - let faux_rcd = Rc::new(faux_owned); - faux_rcd.by_rc(); -} - -#[test] -#[should_panic] -fn by_rc_from_owned_panics_if_cloned() { - let rcd = Rc::new(Owned::new()); - let clone = rcd.clone(); - // panics because faux cannot get the owned value from the Rc. - clone.by_rc(); - // rcd.by_rc(); would also have panicked -} - -#[test] -fn by_rc() { - let rcd = Rc::new(ByRc::new()); - let clone = rcd.clone(); - - // cloning the Rc works when self_type = Rc was specified in the mock - clone.by_rc(); - rcd.by_rc(); + // pub fn new_rc() -> Rc { + // Rc::new(ByRc {}) + // } - // or get it already wrapped - let rcd = ByRc::new_rc(); - rcd.by_rc(); + // pub fn new_rc2() -> Rc { + // Rc::new(ByRc {}) + // } - // mocking must be done prior to wrapping it in an Rc - let mut owned = ByRc::faux(); - faux::when!(owned.by_rc).then(|_| {}); - - let rcd = Rc::new(owned); - rcd.by_rc(); + // pub fn by_rc(self: Rc) {} + // pub fn by_rc2(self: std::rc::Rc) {} + // pub fn by_ref(&self) {} } -#[test] -fn by_box_from_owned() { - let real_boxed = Box::new(Owned::new()); - real_boxed.by_box(); - - // can be boxed right away because a &mut can be obtained from a Box - let mut faux_boxed = Box::new(Owned::faux()); - faux::when!(faux_boxed.by_box).then(|_| {}); - faux_boxed.by_box(); -} - -#[test] -fn by_box() { - let real_boxed = ByBox::new_box(); - real_boxed.by_box(); - - // can be boxed right away because a &mut can be obtained from a Box - let mut faux_boxed = Box::new(ByBox::faux()); - faux::when!(faux_boxed.by_box).then(|_| {}); - faux_boxed.by_box(); -} - -#[test] -fn by_pin_from_owned() { - let mut owned = Owned::new(); - Pin::new(&mut owned).by_pinmut(); - Pin::new(&mut owned).by_pinmut2(); - Pin::new(Rc::new(Owned::new())).by_pinrc(); - Pin::new(Rc::new(Owned::new())).by_pinrc2(); - Pin::new(Arc::new(Owned::new())).by_pinarc(); - Pin::new(Arc::new(Owned::new())).by_pinarc2(); - Pin::new(Box::new(Owned::new())).by_pinbox(); - Pin::new(Box::new(Owned::new())).by_pinbox2(); - - let mut faux = Owned::faux(); - let mut faux_pinmut = Pin::new(&mut faux); - - faux::when!(faux_pinmut.by_pinmut).then(|_| {}); - faux::when!(faux_pinmut.by_pinmut2).then(|_| {}); - faux_pinmut.by_pinmut(); -} +// #[faux::create(self_type = "Arc")] +// pub struct ByArc {} + +// #[faux::methods(self_type = "Arc")] +// impl ByArc { +// pub fn new() -> ByArc { +// ByArc {} +// } + +// pub fn new_arc() -> Arc { +// Arc::new(ByArc {}) +// } + +// pub fn new_arc2() -> Arc { +// Arc::new(ByArc {}) +// } + +// pub fn by_arc(self: Arc) {} +// pub fn by_arc2(self: std::sync::Arc) {} +// pub fn by_ref(&self) {} +// } + +// #[faux::create(self_type = "Box")] +// pub struct ByBox {} + +// #[faux::methods(self_type = "Box")] +// impl ByBox { +// pub fn new() -> ByBox { +// ByBox {} +// } + +// pub fn new_box() -> Box { +// Box::new(ByBox {}) +// } + +// pub fn new_box2() -> Box { +// Box::new(ByBox {}) +// } + +// pub fn by_box(self: Box) {} +// pub fn by_box2(self: std::boxed::Box) {} +// pub fn by_ref(&self) {} +// pub fn by_mut_ref(&mut self) {} +// pub fn by_value(self) {} +// } + +// #[test] +// fn by_rc_from_owned() { +// // getting and invoking real instances/methods works +// let real_rcd = Rc::new(Owned::new()); +// real_rcd.by_rc(); + +// // mocking also works BUT +// // mocks need a `&mut` when mocking a method +// // so prepare the mock before wrapping it around an Rc +// let mut faux_owned = Owned::faux(); +// faux::when!(faux_owned.by_rc).then(|_| {}); + +// let faux_rcd = Rc::new(faux_owned); +// faux_rcd.by_rc(); +// } + +// #[test] +// #[should_panic] +// fn by_rc_from_owned_panics_if_cloned() { +// let rcd = Rc::new(Owned::new()); +// let clone = rcd.clone(); +// // panics because faux cannot get the owned value from the Rc. +// clone.by_rc(); +// // rcd.by_rc(); would also have panicked +// } + +// #[test] +// fn by_rc() { +// let rcd = Rc::new(ByRc::new()); +// let clone = rcd.clone(); + +// // cloning the Rc works when self_type = Rc was specified in the mock +// clone.by_rc(); +// rcd.by_rc(); + +// // or get it already wrapped +// let rcd = ByRc::new_rc(); +// rcd.by_rc(); + +// // mocking must be done prior to wrapping it in an Rc +// let mut owned = ByRc::faux(); +// faux::when!(owned.by_rc).then(|_| {}); + +// let rcd = Rc::new(owned); +// rcd.by_rc(); +// } + +// #[test] +// fn by_box_from_owned() { +// let real_boxed = Box::new(Owned::new()); +// real_boxed.by_box(); + +// // can be boxed right away because a &mut can be obtained from a Box +// let mut faux_boxed = Box::new(Owned::faux()); +// faux::when!(faux_boxed.by_box).then(|_| {}); +// faux_boxed.by_box(); +// } + +// #[test] +// fn by_box() { +// let real_boxed = ByBox::new_box(); +// real_boxed.by_box(); + +// // can be boxed right away because a &mut can be obtained from a Box +// let mut faux_boxed = Box::new(ByBox::faux()); +// faux::when!(faux_boxed.by_box).then(|_| {}); +// faux_boxed.by_box(); +// } + +// #[test] +// fn by_pin_from_owned() { +// let mut owned = Owned::new(); +// Pin::new(&mut owned).by_pinmut(); +// Pin::new(&mut owned).by_pinmut2(); +// Pin::new(Rc::new(Owned::new())).by_pinrc(); +// Pin::new(Rc::new(Owned::new())).by_pinrc2(); +// Pin::new(Arc::new(Owned::new())).by_pinarc(); +// Pin::new(Arc::new(Owned::new())).by_pinarc2(); +// Pin::new(Box::new(Owned::new())).by_pinbox(); +// Pin::new(Box::new(Owned::new())).by_pinbox2(); + +// let mut faux = Owned::faux(); +// let mut faux_pinmut = Pin::new(&mut faux); + +// faux::when!(faux_pinmut.by_pinmut).then(|_| {}); +// faux::when!(faux_pinmut.by_pinmut2).then(|_| {}); +// faux_pinmut.by_pinmut(); +// }