Trait funcmap::TryFuncMap
source · pub trait TryFuncMap<A, B, P = TypeParam<0>>: Sizedwhere
P: FuncMarker<P>,{
type Output;
// Required method
fn try_func_map<E, F>(self, f: F) -> Result<Self::Output, E>
where F: FnMut(A) -> Result<B, E>;
// Provided method
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 range0..=n
.- The parameter of
Foo
at indexN
(not counting lifetime parameters) must beA
. In particular, it must be a type parameter, not a const generic. Foo::Output
must beFoo
with the parameter at indexN
replaced withB
.
Furthermore:
try_func_map_over
must behave in exactly the same way astry_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 ofFoo
:#[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 typesTypeParam<N>
andTypeParam<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§
Required Methods§
Provided Methods§
sourcefn try_func_map_over<Q, E, F>(self, f: F) -> Result<Self::Output, E>where
F: FnMut(A) -> Result<B, E>,
Q: FuncMarker<P>,
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>,
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