Skip to content

Commit

Permalink
#111 Refactored resolve argument function
Browse files Browse the repository at this point in the history
  • Loading branch information
la10736 committed Apr 23, 2021
1 parent 2fefbf3 commit 8337423
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 81 deletions.
6 changes: 3 additions & 3 deletions src/render/fixture.rs
Expand Up @@ -3,7 +3,7 @@ use syn::{parse_quote, Ident, ItemFn};

use quote::quote;

use super::{generics_clean_up, render_exec_call, resolve_new_args};
use super::{generics_clean_up, render_exec_call, resolve_aruments};
use crate::parse::fixture::FixtureInfo;
use crate::resolver::{self, Resolver};
use crate::utils::{fn_args, fn_args_idents};
Expand Down Expand Up @@ -35,7 +35,7 @@ pub(crate) fn render<'a>(fixture: ItemFn, info: FixtureInfo) -> TokenStream {
.map(|tp| &tp.ident)
.cloned()
.collect::<Vec<_>>();
let inject = resolve_new_args(fixture.sig.inputs.iter(), &resolver, &generics_idents);
let inject = resolve_aruments(fixture.sig.inputs.iter(), &resolver, &generics_idents);
let partials =
(1..=orig_args.len()).map(|n| render_partial_impl(&fixture, n, &resolver, &info));

Expand Down Expand Up @@ -86,7 +86,7 @@ fn render_partial_impl(
.map(|tp| &tp.ident)
.cloned()
.collect::<Vec<_>>();
let inject = resolve_new_args(fixture.sig.inputs.iter().skip(n), resolver, &genercs_idents);
let inject = resolve_aruments(fixture.sig.inputs.iter().skip(n), resolver, &genercs_idents);

let sign_args = fn_args(fixture).take(n);
let fixture_args = fn_args_idents(fixture).cloned().collect::<Vec<_>>();
Expand Down
191 changes: 113 additions & 78 deletions src/render/mod.rs
Expand Up @@ -209,7 +209,7 @@ fn single_test_case<'a>(
if trace_me.len() > 0 {
attributes.add_trace(format_ident!("trace"));
}
let inject = resolve_new_args(args.iter(), &resolver, generic_types);
let inject = resolve_aruments(args.iter(), &resolver, generic_types);
let args = args
.iter()
.filter_map(MaybeIdent::maybe_ident)
Expand Down Expand Up @@ -268,7 +268,113 @@ fn trace_arguments<'a>(
fn default_fixture_resolve(ident: &Ident) -> Cow<Expr> {
Cow::Owned(parse_quote! { #ident::default() })
}
fn fnarg_2_fixture(arg: &FnArg, resolver: &impl Resolver, generic_types: &[Ident]) -> Option<Stmt> {

fn handling_magic_conversion_code(fixture: Cow<Expr>, arg_type: &Type) -> Expr {
parse_quote! {
{
struct __Wrap<T>(std::marker::PhantomData<T>);

trait __ViaParseDebug<'a, T> {
fn magic_conversion(&self, input: &'a str) -> T;
}

impl<'a, T> __ViaParseDebug<'a, T> for &&__Wrap<T>
where
T: std::str::FromStr,
T::Err: std::fmt::Debug,
{
fn magic_conversion(&self, input: &'a str) -> T {
T::from_str(input).unwrap()
}
}

trait __ViaParse<'a, T> {
fn magic_conversion(&self, input: &'a str) -> T;
}

impl<'a, T> __ViaParse<'a, T> for &__Wrap<T>
where
T: std::str::FromStr,
{
fn magic_conversion(&self, input: &'a str) -> T {
match T::from_str(input) {
Ok(v) => v,
Err(_) => {
panic!("Cannot parse '{}' to get {}", input, std::stringify!(#arg_type));
}
}
}
}

trait __ViaIdent<'a, T> {
fn magic_conversion(&self, input: &'a str) -> T;
}

impl<'a> __ViaIdent<'a, &'a str> for &&__Wrap<&'a str> {
fn magic_conversion(&self, input: &'a str) -> &'a str {
input
}
}
(&&&__Wrap::<#arg_type>(std::marker::PhantomData)).magic_conversion(#fixture)
}
}
}

trait IsLiteralExpression {
fn is_literal(&self) -> bool;
}

impl<E: AsRef<Expr>> IsLiteralExpression for E {
fn is_literal(&self) -> bool {
match self.as_ref() {
&Expr::Lit(syn::ExprLit { ref lit, .. }) => match lit {
syn::Lit::Str(_) => true,
_ => false,
},
_ => false,
}
}
}

trait IsExplicitType {
fn is_explicit(&self) -> bool;
}

impl IsExplicitType for &Type {
fn is_explicit(&self) -> bool {
match self {
Type::ImplTrait(_)
| Type::TraitObject(_)
| Type::Infer(_)
| Type::Group(_)
| Type::Macro(_)
| Type::Never(_)
| Type::Paren(_)
| Type::Verbatim(_) => false,
_ => true,
}
}
}

fn ident_contains(haystack: &[Ident], needle: &Ident) -> bool {
haystack.iter().find(|&id| id == needle).is_some()
}

fn type_can_be_get_from_literal_str(t: &Type, generics: &[Ident]) -> bool {
if !t.is_explicit() {
return false
}
match t.maybe_ident() {
Some(id) => !ident_contains(generics, id),
None => false
}
}

fn resolve_argument(
arg: &FnArg,
resolver: &impl Resolver,
generic_types: &[Ident],
) -> Option<Stmt> {
let ident = arg.maybe_ident()?;
let arg_type = arg.maybe_type()?;
let id_str = ident.to_string();
Expand All @@ -283,93 +389,22 @@ fn fnarg_2_fixture(arg: &FnArg, resolver: &impl Resolver, generic_types: &[Ident
.map(|e| e.clone())
.unwrap_or_else(|| default_fixture_resolve(&fixture_name));

let is_explicit_type = match arg_type {
Type::ImplTrait(_)
| Type::TraitObject(_)
| Type::Infer(_)
| Type::Group(_)
| Type::Macro(_)
| Type::Never(_)
| Type::Paren(_)
| Type::Verbatim(_) => false,
_ => true,
};

let is_literal_str = match fixture.as_ref() {
&Expr::Lit(syn::ExprLit { ref lit, .. }) => match lit {
syn::Lit::Str(_) => true,
_ => false,
},
_ => false,
};
if is_literal_str
&& is_explicit_type
&& arg_type
.maybe_ident()
.map(|id| generic_types.iter().find(|&tp| tp == id).is_none())
.unwrap_or_default()
if fixture.is_literal()
&& type_can_be_get_from_literal_str(arg_type, generic_types)
{
let new_fixture: Expr = parse_quote! {
{
struct __Wrap<T>(std::marker::PhantomData<T>);

trait __ViaParseDebug<'a, T> {
fn magic_conversion(&self, input: &'a str) -> T;
}

impl<'a, T> __ViaParseDebug<'a, T> for &&__Wrap<T>
where
T: std::str::FromStr,
T::Err: std::fmt::Debug,
{
fn magic_conversion(&self, input: &'a str) -> T {
T::from_str(input).unwrap()
}
}

trait __ViaParse<'a, T> {
fn magic_conversion(&self, input: &'a str) -> T;
}

impl<'a, T> __ViaParse<'a, T> for &__Wrap<T>
where
T: std::str::FromStr,
{
fn magic_conversion(&self, input: &'a str) -> T {
match T::from_str(input) {
Ok(v) => v,
Err(_) => {
panic!("Cannot parse '{}' to get {}", input, std::stringify!(#arg_type));
}
}
}
}

trait __ViaIdent<'a, T> {
fn magic_conversion(&self, input: &'a str) -> T;
}

impl<'a> __ViaIdent<'a, &'a str> for &&__Wrap<&'a str> {
fn magic_conversion(&self, input: &'a str) -> &'a str {
input
}
}
(&&&__Wrap::<#arg_type>(std::marker::PhantomData)).magic_conversion(#fixture)
}
};
fixture = Cow::Owned(new_fixture);
fixture = Cow::Owned(handling_magic_conversion_code(fixture, arg_type));
}
Some(parse_quote! {
let #ident = #fixture;
})
}

fn resolve_new_args<'a>(
fn resolve_aruments<'a>(
args: impl Iterator<Item = &'a FnArg>,
resolver: &impl Resolver,
generic_types: &[Ident],
) -> TokenStream {
let define_vars = args.map(|arg| fnarg_2_fixture(arg, resolver, generic_types));
let define_vars = args.map(|arg| resolve_argument(arg, resolver, generic_types));
quote! {
#(#define_vars)*
}
Expand Down

0 comments on commit 8337423

Please sign in to comment.