# funcmap - Derivable functorial mappings for Rust
[](https://github.com/matthias-stemmler/funcmap)
[](https://crates.io/crates/funcmap)
[](https://docs.rs/funcmap/latest/funcmap/)
[](https://github.com/matthias-stemmler/funcmap/blob/main/LICENSE-APACHE)
[](https://blog.rust-lang.org/2021/10/21/Rust-1.56.0.html)
This Rust crate provides the [`FuncMap`] (and its fallible version
[`TryFuncMap`] that can be automatically derived for a type that is generic over
a type parameter. It provides a method that applies a given closure to all
(potentially nested) occurrences of the type parameter within the type, removing
the need to write verbose mapping code.
Concretely, given a generic type `Foo<T>` and an `FnMut(A) -> B` closure, it can
turn any value of type `Foo<A>` into a value of type `Foo<B>`. This is called a
_functorial mapping_ following the _functor_ design pattern of functional
programming.
## Installation
This crate is available on [crates.io](https://crates.io/crates/funcmap). In
order to use it, add this to the `dependencies` table of your `Cargo.toml`:
```toml
[dependencies]
funcmap = "0.1.1"
```
## Usage
Suppose you have a type that is generic over some type parameter `T` and
contains a `T` in various places:
```rust
struct Foo<T> {
value: T,
more_values: Vec<T>,
}
```
Now suppose you want to turn a `Foo<i32>` into a `Foo<String>` by converting
each `i32` contained in the type into a `String` by applying `to_string`. You
can do this by deriving the [`FuncMap`] trait provided by this crate and then
invoking its [`func_map`] method like this:
```rust
#[derive(FuncMap)]
struct Foo<T> {
value: T,
more_values: Vec<T>,
}
let foo = Foo {
value: 1,
more_values: vec![2, 3, 4],
};
let bar = foo.func_map(|v| v.to_string());
assert_eq!(bar.value, "1");
assert_eq!(bar.more_values, vec!["2", "3", "4"]);
```
The expression `foo.func_map(|v| v.to_string())` is equivalent to this:
```rust
Foo {
value: foo.value.to_string(),
more_values: foo.more_values.into_iter().map(|v| v.to_string()).collect()
}
```
This way, you avoid writing boilerplate mapping code, especially in cases where
your type contains many and/or deeply nested occurrences of `T`. This works for
both structs and enums and many ways of nesting `T` within your type such as
arrays, tuples and many types from the standard library as well as your own
types as long as they implement [`FuncMap`] themselves. Note that the purpose of
the `funcmap` crate is just to provide utility functionality, so
- you shouldn't depend on any of the items it exports in your public API,
- it shouldn't be necessary to use bounds on the traits it exports anywhere
except in generic implementations of those same traits.
For a more detailed explanation and more features, see the
[crate documentation][docs].
For larger examples, see the [examples] folder.
## Minimum Supported Rust Version (MSRV) Policy
The current MSRV of this crate is `1.56`.
Increasing the MSRV of this crate is _not_ considered a breaking change.
However, in such cases there will be at least a minor version bump. Each version
of this crate will support at least the four latest stable Rust versions at the
time it is published.
## Changelog
See [CHANGELOG.md](https://github.com/matthias-stemmler/funcmap/blob/main/CHANGELOG.md)
## License
Licensed under either of
- Apache License, Version 2.0
([LICENSE-APACHE](https://github.com/matthias-stemmler/funcmap/blob/main/LICENSE-APACHE)
or https://www.apache.org/licenses/LICENSE-2.0)
- MIT license
([LICENSE-MIT](https://github.com/matthias-stemmler/funcmap/blob/main/LICENSE-MIT)
or https://opensource.org/licenses/MIT)
at your option.
## Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.
[examples]: https://github.com/matthias-stemmler/funcmap/tree/v0.1.1/funcmap/examples
[docs]: https://docs.rs/funcmap/0.1.1/funcmap/
[`funcmap`]: https://docs.rs/funcmap/0.1.1/funcmap/trait.FuncMap.html
[`tryfuncmap`]: https://docs.rs/funcmap/0.1.1/funcmap/trait.TryFuncMap.html
[`func_map`]: https://docs.rs/funcmap/0.1.1/funcmap/trait.FuncMap.html#tymethod.func_map