Skip to content

Commit

Permalink
Added support for arbitrary self types minus Pin
Browse files Browse the repository at this point in the history
Rc<Self>, Arc<Self>, and Box<Self> should now work albeit with
restrictions.

Pin<T> where T is a pointer type is still undone
  • Loading branch information
nrxus authored and Andres Medina committed Jan 27, 2020
1 parent 9d03567 commit e3545ef
Show file tree
Hide file tree
Showing 10 changed files with 886 additions and 328 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# CHANGELOG

## UPCOMING
* `self: Box<Self>`, `self: Rc<Self>`, and `self: Arc<Self>` are now
allowed in methods inside an impl blocked tagged by `#[methods]`

### Breaking Change

* Specifying a path in `#[methods]` has changed from:
`#[methods(path::to::mod)]` to `#[methods(path =
"path::to::mod")]`. This is done to allow further current and future
arguments to be passed to the attribute.

## v0.0.3
* Async methods may now be mocked
* [tests](/tests/asynchronous.rs)
Expand Down
1 change: 1 addition & 0 deletions faux_macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ syn = { version = "1.0", features = ["full", "extra-traits"] }
quote = "1.0"
proc-macro2 = "1.0"
proc-macro-hack = "0.5"
darling = "0.10"

[dev-dependencies]
faux = { path = "../" }
Expand Down
75 changes: 75 additions & 0 deletions faux_macros/src/create.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use crate::self_type::SelfType;
use darling::FromMeta;
use quote::quote;

#[derive(Default, FromMeta)]
#[darling(default)]
pub struct Args {
#[darling(default)]
self_type: SelfType,
}

pub struct Mockable {
// the real definition of the struct
real: syn::ItemStruct,
// the morphed definition, wraps the real struct around a MaybeFaux
morphed: syn::ItemStruct,
}

impl Mockable {
pub fn new(original: syn::ItemStruct, args: Args) -> Self {
// clone original before changing anything
let mut morphed = original.clone();

// change the name of the original struct and then stop mutating it
let mut real = original;
real.ident = real_struct_new_ident(&real.ident);
let real = real;

// change the fields in morphed to wrap the original struct
morphed.fields = {
let wrapped_self = {
let modified_name = &real.ident;
let (_, ty_generics, _) = morphed.generics.split_for_impl();

match args.self_type {
SelfType::Rc => quote! { std::rc::Rc<#modified_name #ty_generics> },
SelfType::Arc => quote! { std::sync::Arc<#modified_name #ty_generics> },
SelfType::Owned => quote! {#modified_name #ty_generics },
SelfType::Box => quote! { std::boxed::Box<#modified_name #ty_generics>},
}
};
let vis = &morphed.vis;
syn::Fields::Unnamed(
syn::parse2(quote! { (#vis faux::MaybeFaux<#wrapped_self>) }).unwrap(),
)
};

Mockable { real, morphed }
}
}

impl From<Mockable> for proc_macro::TokenStream {
fn from(mockable: Mockable) -> Self {
let Mockable { real, morphed } = mockable;
let (impl_generics, ty_generics, where_clause) = real.generics.split_for_impl();
let name = &morphed.ident;

proc_macro::TokenStream::from(quote! {
#morphed

impl #impl_generics #name #ty_generics #where_clause {
pub fn faux() -> Self {
Self(faux::MaybeFaux::faux())
}
}

#[allow(non_camel_case_types)]
#real
})
}
}

pub fn real_struct_new_ident(original: &syn::Ident) -> syn::Ident {
syn::Ident::new(&format!("_FauxOriginal_{}", original), original.span())
}
Loading

0 comments on commit e3545ef

Please sign in to comment.