Expand description
Generate a map function for a given type that maps across all its type parameters.
i.e.
use n_functor::derive_n_functor;
#[derive(Debug, /* etc. */)]
// optional: setting a name for the type parameters, doesn't affect the structure
// of the data in any way, just the values of type params. In this instance this
// will generate a mapping function of the form:
// `Data::map(self, map_a: impl Fn(A) -> A2, map_second_type_param: impl B -> B2) -> Data<A2, B2>`.
#[derive_n_functor(B = second_type_param)]
// We can also choose a different map name, the default being `map`.
// This will recurse down to child elements without a custom `map_with` declaration.
// #[derive_n_functor(map_name = different_map)]
struct Data<A, B> {
a: A,
// The map_with argument is an arbitrary expression.
#[map_with(Option::map)]
b: Option<B>
}
// This one shows off "map_res" which lets you do structure-wide functor-style maps
// but short circuit on functions that return an error.
#[derive_n_functor(impl_map_res = true)]
struct HasMapResult<A> {
inner: A,
// Arbitrary expressions / closures can go in here, but for map_res it can get
// too complex for a closure.
#[map_with(Option::map, map_res_for_option)]
inner_opt: Option<A>,
}
fn map_res_for_option<A, A2, E>(
opt: Option<A>,
f: impl Fn(A) -> Result<A2, E>
) -> Result<Option<A2>, E> {
match opt {
Some(value) => Ok(Some(f(value)?)),
None => Ok(None),
}
}§Macro configuration
Macro attribute arguments:
A = a_better_name_for_this_type_parameterfn map(self, map_N)can be informative, butfn map(self, map_numbers)is more explicit and autocompletes better.- This option lets you rename the in-function variables for the map method, making it easier for you and other programmers to know what’s actually being mapped.
map_name = ..- Lets you change the name of the method for the mapping function.
- Also uses this name to recurse down on mappable types.
impl_map_res = true- An option to implement an additional “traverse” style mapping function that, given a type
MyType<A, ..>and a bunch of mapping functionsf: A -> Result<B, E>, ..will give you backResult<MyType<B, ..> E> - Useful for when you want to apply function that returns result to a structure but short-circuit with an error.
- If you want all of the errors from this kind of operation, you’ll need to implement that yourself still.
- The map_with attribute can be fed alternative “map_res” functions for your types as a second parameter.
- An option to implement an additional “traverse” style mapping function that, given a type
map_res_suffix = result_is_a_better_suffix:- Changes the suffix for the
map_resstyle method from the default (res, which with the default map name would createmap_res) to one of your choice. - Useful if your crate would prefer to have this method called
map_result, orendofunctor_traversableif you named the map methodendofunctorand changed the suffix totraversable.
- Changes the suffix for the
§#[map_with(..)]
The map_with attribute lets you set functions to call when performing functor maps on types that aren’t just the “raw” types in the type parameter. For example, if you have a struct MyData<A> {field: AnotherCratesType<A>} you’ll need to provide a mapping function, unless that type implements a self-consuming “map(self, f: Fn A -> B)” function already.
This attribute takes an expression, so it can be a closure or the name of a function in scope.
§Details and Limitations
See examples and use cargo-expand to see how different code generates.
Currently works with enums and structs.
Caveats:
- Does not work with data structures that have lifetimes or constants in them at this time.
- Does not currently work well with i.e. tuples where one of the types within is a type parameter. if you need to deal with this, write an external function that applies the mappings (see examples.)
- Does not support custom visibility for generated methods. Always pub, at the moment.
Attribute Macros§
- derive_
n_ functor - The main macro of this crate. See the main page of the docs for an explanation of use, or check the examples.