I have two traits:
trait Read {
fn read(reader: Reader) -> Self;
}
trait ReadWithData {
fn read(data: GlobalData, reader: Reader) -> Self;
}
I use them for reading my state from a file. I can't just implement ReadWithData for everything because I also need to use this system for reading the data itself.
Rust lacks specialization or mutually exclusive traits so it's really difficult to work with this: There is no way to implement Read and ReadWithData correctly for tuples, since there can be overlap. Here's the problem:
- I blanket impl
ReadWithData for T: Read
- I impl
ReadWithData for (T, U) where T: ReadWithData, U: ReadWithData
- Now I need to impl
Read for (T, U) where T: Read, U: Read, but I can't do that because it produces a ReadWithData impl that overlaps with my previous impl
Is there any way to solve this? I don't mind rearchitecting everything, it just needs to be solved.
Instead of a blanket implementation, can you get away with a default implementation and explicitly implementing the trait for each type?
trait Read {
fn read(reader: Reader) -> Self;
}
trait ReadWithData: Read {
fn read(data: GlobalData, reader: Reader) -> Self {
<Self as Read>::read(reader)
}
}
or
trait Read: ReadWithData {
fn read(reader: Reader) -> Self {
<Self as ReadWithData>::read(Default::default(), reader)
}
}
trait ReadWithData: Read {
fn read(data: GlobalData, reader: Reader) -> Self;
}
You might also be able to do something useful with a generic trait:
trait Read<Globals> {
fn read(data: Globals, reader: Reader) -> Self;
}
impl<T> Read<T> for GlobalData { /* ... */ }
impl Read<GlobalData> for NeedsGlobals { /* ... */ }
impl<T,U,Globals> Read<Globals> for (T, U)
where T: Read<Globals>, U: Read<Globals> {
/* ... */
}
I can't have trait ReadWithData: Read because many types that can implement ReadWithData cannot implement Read as they need the data to read. Also, GlobalData: !Default so the second method won't work either. Your solution with making the trait generic seems to work though. Thanks!