This crate can generate a functor for generic structs and enums.
A functor is a trait that contains an fmap
function that maps a generic parameter.
This enables you to transform the contents of any type without altering its shape.
The following example demonstrates how to derive a functor, providing you with an fmap
method.
For more intricate examples, refer to the tests directory in
the project repository.
use functor_derive::Functor;
#[derive(Functor)]
struct MyType<T> {
value: T,
list: Vec<T>,
unaffected: bool,
}
fn main() {
let original = MyType { value: 42, list: vec![1, 3], unaffected: false };
let transformed = original.fmap(|x| (x, x * 2));
assert_eq!(transformed.value, (42, 84));
assert_eq!(transformed.list, vec![(1, 2), (3, 6)]);
}
Additionally, a try_fmap
function is generated. This can be useful for fallible transformations.
let original = MyType { value: "42", list: vec!["1", "3"], unaffected: false };
let transformed = original.try_fmap(|x| x.parse::<u64>())?;
You can invoke the derive macro in multiple ways. Omitting the attribute defaults to deriving the Functor
trait for
the first generic type parameter, as illustrated in the first example above.
Alternatively, you can specify a default type to override the derive macro, which will prevent the derive macro choosing the first generic type parameter. This is done as follows:
#[derive(Functor)]
#[functor(T2)]
struct MyType<T1, T2> {
field_1: T1,
field_2: T2,
}
Sometimes, you might want to rename your fmap
function using the as keyword. The following example generates the
method fmap_keys
.
#[derive(Functor)]
#[functor(K as keys)]
struct MyType<K> {
keys: Vec<K>
}
The above options can be combined to generate multiple implementations, by separating the options with commas.
The code below generates 3 methods: fmap
, fmap_keys
and fmap_values
.
use std::collections::HashMap;
use std::hash::Hash;
#[functor(V, K as keys, V as values)]
struct MyHashMap<K: Hash + Eq, V> {
v: HashMap<K, V>
}
This crate can handle the following perfectly:
- Structs - except for unit structs, which cannot be generic
- Enums
- Arrays
- Tuples
std::collections
: Vec, VecDeque, LinkedList, HashSet, HashMap, BTreeMap, Result, Option, PhantomData- Nested types, like
Option<Box<T>>
- (Mutually) recursive types
- Bounded parameters, like
T: Display
If you find a case where the derive macro fails, feel free to open an issue here