Suppose I have the following trait:
pub trait FunctionTrait<Input, Output, Context> {
fn call(&mut self, input: &Input, context: Option<&Context>) -> Option<Output>;
}
I'd like to implement it for multiple closure types, for example like this:
impl<F, Input, Output, Context> FunctionTrait<Input, Output, Context> for F
where
F: FnMut(&Input, Option<&Context>) -> Option<Output>,
{
fn call(&mut self, input: &Input, context: Option<&Context>) -> Option<Output> {
(self)(input, context)
}
}
impl<F, Input, Output, Context> FunctionTrait<Input, Output, Context> for F
where
F: FnMut(&Input, Option<&Context>) -> Output,
{
fn call(&mut self, input: &Input, context: Option<&Context>) -> Option<Output> {
Some((self)(input, context))
}
}
But I get the following error:
error[E0119]: conflicting implementations of trait `strategy::basic::function_node::FunctionTrait<_, _, _>`
And I get it, the type F could somehow implement both traits, and then it conflicts.
So my first question is: is that even possible with these closure traits? Can something implement both FnMut() -> X
and FnMut() -> Y
at the same time?
My second question is: how can I do something like this?
I was looking at the axum
code to see how they support functions with variable parameter quantity, and it's something similar to what I did, except that the trait itself also has the same generic parameters that are varying in the closure trait, but I couldn't think of a way to do that in my case.
Another solution I was trying was to have a wrapper type that had a call
method, and could be converted from multiple closure types. But my From
implementation resulted in errors:
struct FunctionWrapper<T>(T);
impl<T> FunctionWrapper<T> {
fn call<Input, Output, Context>(
&mut self,
input: &Input,
context: Option<&Context>,
) -> Option<Output>
where
T: FnMut(&Input, Option<&Context>) -> Option<Output>,
{
(self.0)(input, context)
}
}
impl<Input, Output, Context, F, T> From<F> for FunctionWrapper<T>
where
F: FnMut(&Input, Option<&Context>) -> Output,
T: FnMut(&Input, Option<&Context>) -> Option<Output>,
{
fn from(value: F) -> Self {
Self(move |input, context| Some(value(input, context)))
}
}
The error that got me puzzled the most was this:
error[E0308]: mismatched types
--> src/strategy/basic/function_node.rs:50:14
|
44 | impl<Input, Output, Context, F, T> From<F> for FunctionWrapper<T>
| - expected this type parameter
...
50 | Self(move |input, context| Some(value(input, context)))
| ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found closure
| |
| arguments to this function are incorrect
|
= note: expected type parameter `T`
found closure `{closure@src/strategy/basic/function_node.rs:50:14: 50:35}`
= help: every closure has a distinct type and so could not always match the caller-chosen type of parameter `T`
note: tuple struct defined here
--> src/strategy/basic/function_node.rs:29:8
|
29 | struct FunctionWrapper<T>(T);
| ^^^^^^^^^^^^^^^
Which I think I understand, but how can I solve this kind of situation? Having a generic type defined by the code itself in the implementation, is that possible somehow?
Well, it's late and I'm out of ideas for now, so I'm giving up for the day!
Thanks in advance for any insight!