blob: 71f1d3c96bacb87544bbfabbe213c1c4b92ec153 [file] [log] [blame]
/////////////////////////////////////////////////////////////////////
// Suppose these are the real traits from Serde.
trait Querializer {}
trait Generic {
// Not object safe because of this generic method.
fn generic_fn<Q: Querializer>(&self, querializer: Q);
}
impl<'a, T: ?Sized> Querializer for &'a T where T: Querializer {}
impl<'a, T: ?Sized> Generic for Box<T> where T: Generic {
fn generic_fn<Q: Querializer>(&self, querializer: Q) {
(**self).generic_fn(querializer)
}
}
/////////////////////////////////////////////////////////////////////
// This is an object-safe equivalent that interoperates seamlessly.
trait ErasedGeneric {
fn erased_fn(&self, querializer: &Querializer);
}
impl Generic for ErasedGeneric {
// Depending on the trait method signatures and the upstream
// impls, could also implement for:
//
// - &'a ErasedGeneric
// - &'a (ErasedGeneric + Send)
// - &'a (ErasedGeneric + Sync)
// - &'a (ErasedGeneric + Send + Sync)
// - Box<ErasedGeneric>
// - Box<ErasedGeneric + Send>
// - Box<ErasedGeneric + Sync>
// - Box<ErasedGeneric + Send + Sync>
fn generic_fn<Q: Querializer>(&self, querializer: Q) {
self.erased_fn(&querializer)
}
}
impl<T> ErasedGeneric for T where T: Generic {
fn erased_fn(&self, querializer: &Querializer) {
self.generic_fn(querializer)
}
}
fn main() {
struct T;
impl Querializer for T {}
struct S;
impl Generic for S {
fn generic_fn<Q: Querializer>(&self, _querializer: Q) {
println!("querying the real S");
}
}
// Construct a trait object.
let trait_object: Box<ErasedGeneric> = Box::new(S);
// Seamlessly invoke the generic method on the trait object.
//
// THIS LINE LOOKS LIKE MAGIC. We have a value of type trait
// object and we are invoking a generic method on it.
trait_object.generic_fn(T);
}