pub trait TryFuncMap<A, B, P = TypeParam<0>>: Sized where
    P: FuncMarker<P>, 
{ type Output; fn try_func_map<E, F>(self, f: F) -> Result<Self::Output, E>
    where
        F: FnMut(A) -> Result<B, E>
; fn try_func_map_over<Q, E, F>(self, f: F) -> Result<Self::Output, E>
    where
        F: FnMut(A) -> Result<B, E>,
        Q: FuncMarker<P>
, { ... } }
Expand description

Fallible functorial mapping of a generic type over any of its type parameters

Deriving TryFuncMap

In most cases, implementations of this trait can and should be derived automatically:

#[derive(TryFuncMap)]
struct Foo<T> {
    // ...
}

See the crate-level documentation for details.

Manually Implementing TryFuncMap

If you need to implement TryFuncMap manually, make sure to uphold the following contract:

Let Foo be a type that is generic over the type or const parameters T0, ..., Tn.

If Foo implements TryFuncMap<A, B, TypeParam<N>>, then

  • N must be in the range 0..=n.
  • The parameter of Foo at index N (not counting lifetime parameters) must be A. In particular, it must be a type parameter, not a const generic.
  • Foo::Output must be Foo with the parameter at index N replaced with B.

Furthermore:

  • try_func_map_over must behave in exactly the same way as try_func_map. This is the default behavior and must not be changed.
  • If the closure provided to try_func_map fails, then the result must be the first error according to the order of the fields in the definition of Foo:
    #[derive(TryFuncMap, Copy, Clone, Debug, PartialEq)]
    struct Foo<T> {
        value1: T,
        value2: T,
    }
     
    let foo = Foo {
        value1: "1a",
        value2: ""
    };
    
    let result: Result<Foo<i32>, ParseIntError> = foo.try_func_map(|v| v.parse());
     
    assert!(result.is_err());
    assert_eq!(*result.unwrap_err().kind(), IntErrorKind::InvalidDigit);
  • When implementing TryFuncMap for different marker types TypeParam<N> and TypeParam<M>, the result of mapping over both type parameters in sequence must not depend on the order of the two mappings, i.e.
    foo.try_func_map_over::<TypeParam<N>, _, _>(f)
       .and_then(|x| x.try_func_map_over::<TypeParam<M>, _, _>(g))
    
    // must be equivalent to
    
    foo.try_func_map_over::<TypeParam<M>, _, _>(g)
       .and_then(|x| x.try_func_map_over::<TypeParam<N>, _, _>(f))

Required Associated Types

The output type of the functorial mapping

This is Self with the parameter at index N replaced with B, where N is such that P is TypeParam<N>.

In the simplest case of a type with just a single type parameter, if Self is Foo<A>, then this is Foo<B>.

Required Methods

Tries to apply the closure f to self in a functorial way

Errors

Fails if and only if f fails, returning the first error according to the order of the fields in the definition of Self

Provided Methods

Tries to apply the closure f to self in a functorial way, allowing explicit specification of the marker type P

This is a convenience method that has the exact same functionality as try_func_map but can be used to specify the marker type P in a convenient way in cases where it is ambiguous.

So if you have

#[derive(TryFuncMap, Debug, PartialEq)]
struct Foo<S, T> {
    s: S,
    t: T,
}

let foo = Foo {
    s: "42",
    t: "42",
};

then instead of writing

let bar = TryFuncMap::<_, _, TypeParam<1>>::try_func_map(foo, |v| v.parse::<i32>());
assert_eq!(bar, Ok(Foo { s: "42", t: 42 }));

you can more conveniently write

let bar = foo.try_func_map_over::<TypeParam<1>, _, _>(|v| v.parse::<i32>());
assert_eq!(bar, Ok(Foo { s: "42", t: 42 }));

This lets you chain method calls more easily as in

foo.try_func_map_over::<TypeParam<0>, _, _>(|v| v.parse::<i32>())
    .and_then(|foo| foo.try_func_map_over::<TypeParam<1>, _, _>(|v| v.parse::<i32>()))

Note that you still need to specify the inferred type _ for the error type E and the closure type F.

Errors

Fails if and only if f fails, returning the first error according to the order of the fields in the definition of Self

Implementations on Foreign Types

Implementors