Hi all,
I have a crazy idea and wonder if it could work.
tl;dr
Cast a trait object to another trait based on a runtime check.
The background:
I work on a library that has roughly following structure:
trait A {
fn aa(&self) -> &str;
fn ab(&self) -> &str;
}
struct AImpl;
impl A for AImpl { /* ... */ }
trait B {
fn ba(&self) -> &str;
fn bb(&self) -> &str;
}
struct BImpl;
impl B for BImpl { /* ... */ }
// and more impls for A and B
trait AorB {
fn aa(&self) -> Option<&str>;
fn ab(&self) -> Option<&str>;
fn ba(&self) -> Option<&str>;
fn bb(&self) -> Option<&str>;
}
If a type implements A
then AorB
returns Some(...)
for the a*
methods and for B
respectively. &str
is just a placeholder for different, more complex types.
The problem is that there are more methods which means AorB
gets really messy and it would be a lot nicer if we could downcast dyn AorB
to dyn A
and so on. This could easily be done with a as_a(&self) -> Option<&dyn A>
.
Now for the problem:
- Semantically we need
AorB
and as users should be able to supply their own implementations ofA
andB
we can not use anenum
. - As there are a lot of traits we have many functions that are generic over those traits (sometimes with 3 and more type parameters). Given the possibility of many implementations this blows up compile time and code size.
- The crate has various use-cases some where size matters more and some where performance is of more interest.
- As a solution we want to offer to either use monomorphization with concrete types or use trait objects, i.e. use
dyn AorB
for type parameters. - This means
AorB
must be trait safe and allow to monomorphize based on a concrete type. In turn, this prevents us from usingas_a(&self) -> Option<&dyn A>
as it returns again a trait object which blocks monomorphization.
Has anyone an idea how this could work without returning Option
from each method?