Skip to content

Magic convert for elements of an array #331

@Zaglim

Description

@Zaglim

I would magic conversion to work for strs that are elements of an array. e.g.

#[rstest]  
#[case::magic_each_element(["10", "20", "30"])]  
#[case::no_op([10, 20, 30])]  
#[case::mixed(["10", 20, "30"])]
fn magic_array_elements(#[case] input: [u8; 3]) {  
    assert_eq!(input, [10, 20, 30]);
}

This reduces boilerplate parsing each element. e.g. I might otherwise write:

// ...
#[case([
		"10".parse().unwrap(),
		"20".parse().unwrap(),
		"30".parse().unwrap(),
	])]
// ...

My main use cases look more like this:

#[rstest::rstest]  
#[case(["hat".to_string(),"Hat".to_string(),"Hot".to_string(),"cap".to_string()], "Hat")]  
fn fuzzy_match(  
    #[case] strings: impl IntoIterator<Item = String>,  
    #[case] fuzzy_match_includes: String,  
) {  
    // ...  
}

Implementation options

If this seems valuable, I've drafted 2 implementations and would like opinions. I'm not sure if this is the best place to discuss this. Please let me know if this should be moved to a draft PR instead.

Option: Convert the array itself

Implement magic conversion [&str; N]) -> [T; N]:

fn magic_conversion(&self, input: [&'a str; N]) -> [T; N] { 
	input.map(|s| (&Magic::<T>(std::marker::PhantomData)).magic_conversion(s))  
    }

and wrap the whole array. See the snippet below of the expanded macro:

use rstest::magic_conversion::*;
(core::marker::PhantomData)).magic_conversion(["10", "20", "30"])

Limitation

  • The input must be a valid array, so cannot be mixed. i.e. ["10", 20, "30] gets a mismatched types error.

Option: Convert each element

Apply magic conversion to each &str element of the array. Then case::mixed expands to (snippet):

//  
[{
            use rstest::magic_conversion::*;
            (&&&Magic::<u8>(core::marker::PhantomData)).magic_conversion("10")
        },
        20,
        {
            use rstest::magic_conversion::*;
            (&&&Magic::<u8>(core::marker::PhantomData)).magic_conversion("30")
        }]

which is valid rust.

Limitation

More processing is required in the procedural macro, but I don't know how that translates to performance (It might even be faster). It feels like there are so many factors to consider to properly compare the performance (e.g. compiler optimisations, whether the return type of magic_conversion requires allocation, how often is a test run, how often is it recompiled...). If anybody has insights I'd love to read them!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions