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 traverse-style maps
// that short-circuit on errors.
#[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>,
}
// implemented externally to the map_with attribute, but you can also use closures
// for the map_with attribute too.
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 “good enough”, butfn map(self, map_numbers)is more explicit.- Lets you rename the type parameter specific arguments for the map method, making it easier for users to know what’s actually being mapped by giving each closure a more specific name.
map_name = ..- Lets you change the name of the map method.
- Uses this method name to recurse down on mappable types, when this becomes an issue you can get around it with
#[map_with(..)].
impl_map_res = true- An option to implement an additional “traverse” style mapping function.
- AKA
(MyData<A>, Fn(A) -> Result<B, E>)in,Result<MyData<B>, E>out. - Useful for when you want to apply function that returns result to a structure but short-circuit with an error.
- The map_with attribute can be fed alternative “map_res” functions for your types as a second parameter.
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 you’d prefer to have this method called
map_result, orendofunctor_traverseif you named the map methodendofunctorand changed the suffix totraverse.
- Changes the suffix for the
§#[map_with(..)]
The map_with attribute lets you set specific 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 for AnotherCratesType<A>, unless that type implements a self-consuming “map(self, f: Fn A -> B)” function already.
This would look like:
use n_functor::derive_n_functor;
// pretend this is defined elsewhere.
struct AnotherCratesType<A>(pub Option<A>);
#[derive_n_functor]
struct MyData<A> {
#[map_with(|other_crate_type: AnotherCratesType<_>, f| AnotherCratesType(other_crate_type.0.map(f)))]
field: AnotherCratesType<A>
}#[map_with(..)] 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, with named and unnamed fields.
Caveats:
- 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 work with data structures that have lifetimes or constants in them at this time.
- Does not support custom visibility for generated methods. Always pub, at the moment.
map_resmethods stop on the first error.
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.