#![feature(universal_impl_trait)]
use std::any::Any;
use std::marker::PhantomData;
trait Foo {
type Item;
fn get(&self) -> Self::Item;
}
#[derive(Clone, Debug)]
struct Bar<T: Clone>(T);
impl<T: Clone> Bar<T> { fn new(t: T) -> Self { Bar(t) } }
impl<T:'static + Clone> Foo for Bar<T> {
type Item = T;
fn get(&self) -> Self::Item {
self.0.clone()
}
}
#[derive(Clone, Debug)]
struct Baz<T: Clone,F: Clone>(T,F);
impl<T: Clone,F: Clone> Baz<T,F> { fn new(t: T, f:F) -> Self { Baz(t,f) } }
impl<T:'static + Clone, F:'static + Clone> Foo for Baz<T,F> {
type Item = (T,F);
fn get(&self) -> Self::Item {
(self.0.clone(), self.1.clone())
}
}
trait Get {
type Item;
fn idx(&self) -> usize;
}
struct GetBar<T> {id: usize, _t: PhantomData<T>}
impl<T> Get for GetBar<T> {
type Item = T;
fn idx(&self) -> usize { self.id }
}
impl<T> GetBar<T> {
fn new(id: usize) -> Self {Self {id, _t: PhantomData} }
}
struct GetBaz<T,F> {id: usize, _t: PhantomData<T>, _f: PhantomData<F> }
impl<T,F> Get for GetBaz<T,F> {
type Item = T;
fn idx(&self) -> usize { self.id }
}
impl<T,F> GetBaz<T,F> {
fn new(id: usize) -> Self { GetBaz {id, _t: PhantomData, _f: PhantomData} }
}
struct Qux {
v: Vec<Box<Any>>,
}
impl Qux {
fn new() -> Self {
Qux {
v: vec![],
}
}
fn add_bar<T:'static + Clone>(&mut self, a: T) -> GetBar<T> {
self.v.push(Box::new(Bar::new(a)) as Box<Any>);
GetBar::new(self.v.len())
}
fn add_baz<T:'static + Clone, F:'static + Clone>(&mut self, a: T, b: F) -> GetBaz<T,F> {
self.v.push(Box::new(Baz::new(a, b)) as Box<Any>);
GetBaz::new(self.v.len())
}
fn get<T:'static + Clone, F: 'static + Clone>(&self, val: &'static impl Get) -> Option<T> {
let node = &self.v[val.idx()];
if let Some(foo) = node.downcast_ref::<Bar<T>>() {
Some(foo.get())
} else if let Some(foo) = node.downcast_ref::<Baz<T, F>>() {
Some(foo.get().0)
} else {
None
}
}
}
fn main() {
let mut qux = Qux::new();
let a = qux.add_bar(1_i32);
let b = qux.add_bar("1");
let c = qux.add_baz(Bar::new('A'), Bar::new('B'));
assert_eq!(qux.get(&a).unwrap(), 1);
assert_eq!(qux.get(&b).unwrap(), "i");
assert_eq!(qux.get(&c).unwrap(), Bar::new('A'));
}
Sorry for the long example but this is the best I can do. So I'm trying to reconcile the Rust static type system with dynamically dispatched trait objects. However, in many occasions I am unable to provide type annotations. What is the best way to achieve this? How can I dynamically supply type information to the trait object system?
Aucun commentaire:
Enregistrer un commentaire