Reputation: 1349
I'm trying to implement syntax sugar for my library so that someone can write .render(|image| { … })
instead of .render(|(), image| { … })
if they have no interesting state management going on. I thought I would be able to do this by implementing a trait for all FnMut(&State, &Image)
, and having a unit implementation for FnMut(&Image)
. Unfortunately, I get "conflicting implementation" errors when I try to implement this, because there's no reason something can't implement both of those FnMut
traits.
My current attempt looks like this:
trait RenderCallback<State> {
fn render(&mut self, state: &mut State, image: &mut Image);
}
impl<F, State> RenderCallback<State> for F
where
F: FnMut(&mut State, &mut Image),
{
fn render(&mut self, state: &mut State, image: &mut Image) {
self(state, image)
}
}
impl<F> RenderCallback<()> for F
where
F: FnMut(&mut Image),
{
fn render(&mut self, state: &mut State, image: &mut Image) {
self(&mut (), image)
}
}
Is there some way to achieve this effect?
Upvotes: 2
Views: 97
Reputation: 21229
I think that the only way is to use auto traits with opt out if you want stick with this design. But it requires nightly. An example:
#![feature(optin_builtin_traits)]
// Implement DummyState for everything ...
auto trait DummyState {}
// ... but opt-out for ()
impl !DummyState for () {}
trait RenderCallback<State> {
fn render(&mut self, state: &mut State, num: u8);
}
// Implement render callback for any type that implements DummyState
impl<F, State> RenderCallback<State> for F
where
F: FnMut(&mut State, u8),
State: DummyState, // DummyState means any type except opted out ()
{
fn render(&mut self, state: &mut State, num: u8) {
self(state, num)
}
}
// Implement render callback for (), which doesn't implement DummyState,
// so there's no overlap
impl<F> RenderCallback<()> for F
where
F: FnMut(u8),
{
fn render(&mut self, _state: &mut (), num: u8) {
self(num)
}
}
fn with_state() {
struct MyState {
x: u8,
};
println!("with_state...");
let mut state = MyState { x: 0 };
let mut callback = |state: &mut MyState, num: u8| {
state.x += num;
println!("{}", state.x);
};
callback.render(&mut state, 1);
callback.render(&mut state, 2);
callback.render(&mut state, 3);
}
fn without_state() {
println!("without state...");
let mut callback = |num: u8| {
println!("{}", num);
};
callback.render(&mut (), 1);
callback.render(&mut (), 2);
callback.render(&mut (), 3);
}
fn main() {
with_state();
without_state();
}
Upvotes: 1