Hello everyone!
Suppose I have a trait that looks like this:
trait Wrapper {
type Inner;
fn set(&mut self, v: Self::Inner);
fn mutate(&mut self, f: impl FnOnce(&mut Self::Inner))
where
Self::Inner: Clone;
}
I could implement it using generic struct like this:
struct Wrapped<T>(T);
impl<T> Wrapper for Wrapped<T> {
type Inner = T;
fn set(&mut self, v: T) {
self.0 = v;
}
fn mutate(&mut self, f: impl FnOnce(&mut T))
where
T: Clone,
{
let mut clone = self.0.clone();
f(&mut clone);
self.0 = clone;
}
}
#[derive(Clone)]
struct Clonable;
// <ContainsClonable as Wrapper>::mutate exists
type ContainsClonable = Wrapped<Clonable>;
struct NonClonable;
// <ContainsNonClonable as Wrapper>::mutate doesn't exist
type ContainsNonClonable = Wrapped<NonClonable>;
But I can't use that approach in my situation. Instead, I need to do something like this:
struct ContainsClonable(Clonable);
impl Wrapper for ContainsClonable {
type Inner = Clonable;
fn set(&mut self, v: Self::Inner) {
self.0 = v;
}
fn mutate(&mut self, f: impl FnOnce(&mut Self::Inner)) {
// this is a simplification, of course
let mut clone = self.0.clone();
f(&mut clone);
self.0 = clone;
}
}
struct ContainsNonClonable(NonClonable);
impl Wrapper for ContainsNonClonable {
type Inner = NonClonable;
fn set(&mut self, v: Self::Inner) {
self.0 = v;
}
fn mutate(&mut self, f: impl FnOnce(&mut Self::Inner))
where
Self::Inner: Clone
{
let mut clone = self.0.clone();
f(&mut clone);
self.0 = clone;
}
}
But this code doesn't compile for the ContainsNonClonable
, because where
clause in it's impl Wrapper
block doesn't make the compiler ignore this method like it does in the impl Wrapper
block of the generic Wrapped<T>
.
I wonder if it's possible to somehow make it work? I'm aware that I can do something like this:
trait Wrapper {
type Inner;
fn set(&mut self, v: Self::Inner);
fn mutate(&mut self, f: impl FnOnce(&mut Self::Inner))
where
Self::Inner: Clone
{
unimplemented!()
}
}
struct ContainsNonClonable(NonClonable);
impl Wrapper for ContainsNonClonable {
type Inner = NonClonable;
fn set(&mut self, v: Self::Inner) {
self.0 = v;
}
}
But
a) It requires explicit remove of mutate
method implementation (which I can't do since both ContainsClonable
and ContainsNonClonable
are generated with one macro);
b) It makes ContainsNonClonable::mutate
available thing that just panics, which is less than ideal.
Any ideas? I hope the solution doesn't require specialization...