From f06e2e01d2b45c399aa84815bf075016f30043d9 Mon Sep 17 00:00:00 2001 From: Nathan Ringo Date: Wed, 21 Nov 2018 01:04:31 -0600 Subject: [PATCH 1/2] Adds FuncMut and PolyMut, which parallel Func and Poly. --- CHANGELOG.md | 1 + core/src/coproduct.rs | 19 +++++++++++++++++-- core/src/hlist.rs | 27 +++++++++++++++++++++------ core/src/traits.rs | 17 +++++++++++++++++ src/lib.rs | 4 ++-- 5 files changed, 58 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91225eba9..217cbf6c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased]: - Added `ToMut` trait, which allows borrowing mutably from a Coproduct or HList. +- Added `FuncMut` and `PolyMut`, which parallel `Func` and `Poly`. ## [0.2.2] - 2018-10-21 - Added support for [transmogrifying (recursively sculpting)](https://docs.rs/frunk/0.2.2/frunk/labelled/trait.Transmogrifier.html) one data type into another diff --git a/core/src/coproduct.rs b/core/src/coproduct.rs index 3cb6033b0..71f86c534 100644 --- a/core/src/coproduct.rs +++ b/core/src/coproduct.rs @@ -73,7 +73,7 @@ use hlist::{HCons, HNil}; use indices::{Here, There}; -use traits::{Func, Poly, ToMut, ToRef}; +use traits::{Func, FuncMut, Poly, PolyMut, ToMut, ToRef}; /// Enum type representing a Coproduct. Think of this as a Result, but capable /// of supporting any arbitrary number of types instead of just 2. @@ -506,9 +506,10 @@ impl Coproduct { /// /// * An `hlist![]` of closures (one for each type, in order). /// * A single closure (for a Coproduct that is homogenous). - /// * A single [`Poly`]. + /// * A single [`Poly`] or [`PolyMut`]. /// /// [`Poly`]: ../traits/struct.Poly.html + /// [`PolyMut`]: ../traits/struct.PolyMut.html /// /// # Example /// @@ -745,6 +746,20 @@ where } } +impl CoproductFoldable, R> for Coproduct +where + P: FuncMut, + CTail: CoproductFoldable, R>, +{ + fn fold(self, mut f: PolyMut

) -> R { + use self::Coproduct::*; + match self { + Inl(r) => f.0.call(r), + Inr(rest) => rest.fold(f), + } + } +} + impl CoproductFoldable, R> for Coproduct where F: FnOnce(CH) -> R, diff --git a/core/src/hlist.rs b/core/src/hlist.rs index 7928eadb6..98f31a99f 100644 --- a/core/src/hlist.rs +++ b/core/src/hlist.rs @@ -57,7 +57,7 @@ //! ``` use indices::{Here, Suffixed, There}; -use traits::{Func, IntoReverse, Poly, ToMut, ToRef}; +use traits::{Func, FuncMut, IntoReverse, Poly, PolyMut, ToMut, ToRef}; use std::ops::Add; @@ -352,9 +352,10 @@ macro_rules! gen_inherent_methods { /// /// * An `hlist![]` of closures (one for each element). /// * A single closure (for mapping an HList that is homogenous). - /// * A single [`Poly`]. + /// * A single [`Poly`] or [`PolyMut`]. /// /// [`Poly`]: ../traits/struct.Poly.html + /// [`PolyMut`]: ../traits/struct.PolyMut.html /// /// # Examples /// @@ -908,6 +909,20 @@ where } } +impl HMappable> for HCons +where + P: FuncMut, + Tail: HMappable>, +{ + type Output = HCons<

>::Output, >>::Output>; + fn map(self, mut poly: PolyMut

) -> Self::Output { + HCons { + head: poly.0.call(self.head), + tail: self.tail.map(poly), + } + } +} + /// Trait for mapping over an HList /// /// This trait is part of the implementation of the inherent method @@ -943,12 +958,12 @@ impl HMappable for HNil { impl HMappable for HCons where - F: Fn(H) -> R, + F: FnMut(H) -> R, Tail: HMappable, { type Output = HCons>::Output>; - fn map(self, f: F) -> Self::Output { + fn map(self, mut f: F) -> Self::Output { let HCons { head, tail } = self; HCons { head: f(head), @@ -1143,11 +1158,11 @@ where impl HFoldLeftable for HCons where Tail: HFoldLeftable, - F: Fn(Acc, H) -> Acc, + F: FnMut(Acc, H) -> Acc, { type Output = >::Output; - fn foldl(self, f: F, acc: Acc) -> Self::Output { + fn foldl(self, mut f: F, acc: Acc) -> Self::Output { let HCons { head, tail } = self; let acc = f(acc, head); tail.foldl(f, acc) diff --git a/core/src/traits.rs b/core/src/traits.rs index 19f0ed528..bc1d9cc21 100644 --- a/core/src/traits.rs +++ b/core/src/traits.rs @@ -58,6 +58,13 @@ pub trait IntoReverse { #[derive(Debug, Copy, Clone, Default)] pub struct Poly(pub T); +/// A wrapper like [`Poly`] for [`FuncMut`]. +/// +/// [`FuncMut`]: trait.FuncMut.html +/// [`Poly`]: trait.Poly.html +#[derive(Debug, Copy, Clone, Default)] +pub struct PolyMut(pub T); + /// This is a simple, user-implementable alternative to `Fn`. /// /// Might not be necessary if/when Fn(Once, Mut) traits are implementable @@ -74,3 +81,13 @@ pub trait Func { /// use cases. fn call(i: Input) -> Self::Output; } + +/// This is a user-implementable alternative to `FnMut`. +/// +/// Not necessary if/when the FnMut trait is implementable in stable Rust. +pub trait FuncMut { + type Output; + + /// Call the `FuncMut`. + fn call(&mut self, i: Input) -> Self::Output; +} diff --git a/src/lib.rs b/src/lib.rs index b423a9643..deb89e192 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -238,9 +238,9 @@ pub use hlist::HCons; #[doc(no_inline)] pub use hlist::HNil; #[doc(no_inline)] -pub use traits::Func; +pub use traits::{Func, FuncMut}; #[doc(no_inline)] -pub use traits::Poly; +pub use traits::{Poly, PolyMut}; #[doc(no_inline)] pub use traits::{ToMut, ToRef}; // useful for where bounds From b6ea9dc9f2893b6e07e5c22cd418e4bcdafe2e87 Mon Sep 17 00:00:00 2001 From: Nathan Ringo Date: Sat, 24 Nov 2018 17:03:31 -0600 Subject: [PATCH 2/2] Adds documentation example of FuncMut. --- core/src/traits.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/core/src/traits.rs b/core/src/traits.rs index bc1d9cc21..923898b4a 100644 --- a/core/src/traits.rs +++ b/core/src/traits.rs @@ -85,6 +85,38 @@ pub trait Func { /// This is a user-implementable alternative to `FnMut`. /// /// Not necessary if/when the FnMut trait is implementable in stable Rust. +/// +/// ``` +/// # #[macro_use] +/// # extern crate frunk; +/// # use frunk::{FuncMut, PolyMut}; +/// # use std::fmt::{Debug, Write}; +/// +/// struct ConcatDebug<'a>(&'a mut String); +/// +/// impl<'a, T: Debug> FuncMut for ConcatDebug<'a> { +/// type Output = (); +/// fn call(&mut self, t: T) { +/// write!(self.0, "{:?}", t).unwrap(); +/// } +/// } +/// +/// fn main() { +/// let mut string = String::new(); +/// +/// { +/// let mut concatter = ConcatDebug(&mut string); +/// let l = hlist![ +/// 23, +/// "foo", +/// (1, "two", 3.0) +/// ]; +/// l.map(PolyMut(concatter)); +/// } +/// +/// assert_eq!(string, r#"23"foo"(1, "two", 3.0)"#); +/// } +/// ``` pub trait FuncMut { type Output;