# funcmap - Derivable functorial mappings for Rust [![GitHub](https://img.shields.io/badge/GitHub-informational?logo=GitHub&labelColor=555555)](https://github.com/matthias-stemmler/funcmap) [![crates.io](https://img.shields.io/crates/v/funcmap.svg)](https://crates.io/crates/funcmap) [![docs.rs](https://img.shields.io/docsrs/funcmap)](https://docs.rs/funcmap/latest/funcmap/) [![license](https://img.shields.io/crates/l/funcmap.svg)](https://github.com/matthias-stemmler/funcmap/blob/main/LICENSE-APACHE) [![rustc 1.65+](https://img.shields.io/badge/rustc-1.65+-lightgrey.svg)](https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html) This Rust crate provides the [`FuncMap`] trait (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` and an `FnMut(A) -> B` closure, it can turn any value of type `Foo` into a value of type `Foo`. 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.5" ``` ## Usage Suppose you have a type that is generic over some type parameter `T` and contains a `T` in various places: ```rust struct Foo { value: T, more_values: Vec, } ``` Now suppose you want to turn a `Foo` into a `Foo` 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 { value: T, more_values: Vec, } 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.65`. 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.5/funcmap/examples [docs]: https://docs.rs/funcmap/0.1.5/funcmap/ [`funcmap`]: https://docs.rs/funcmap/0.1.5/funcmap/trait.FuncMap.html [`tryfuncmap`]: https://docs.rs/funcmap/0.1.5/funcmap/trait.TryFuncMap.html [`func_map`]: https://docs.rs/funcmap/0.1.5/funcmap/trait.FuncMap.html#tymethod.func_map