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
Nmust be in the range0..=n.- The parameter of
Fooat indexN(not counting lifetime parameters) must beA. In particular, it must be a type parameter, not a const generic. Foo::Outputmust beFoowith the parameter at indexNreplaced withB.
Furthermore:
try_func_map_overmust 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_mapfails, 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
TryFuncMapfor 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