-use std::sync::mpsc;
-use std::future::Future;
-use std::pin::Pin;
-async fn awaitpoint(_: ()) { }
+use std::any::{Any,TypeId};
+use std::sync::Arc;
-async fn failure() {
- let (_, rx) = mpsc::channel::<()>();
+pub trait CastToAnyTrait {
+ fn cast_to_instance(&self, tp: TypeId) -> Option<Box<dyn Any>>;
+}
+
+pub trait CastToAnyTraitExt {
+ fn cast_to<T: 'static>(&self) -> Option<Box<T>>;
+}
- while let Ok(event) = rx.recv() {
- awaitpoint(event).await;
+impl<T:CastToAnyTrait+?Sized> CastToAnyTraitExt for T {
+ fn cast_to<U: 'static>(&self) -> Option<Box<U>> {
+ let instance = self.cast_to_instance(TypeId::of::<U>())?;
+ instance.downcast().ok()
+ }
+}
+
+trait HasFeet {
+ fn how_many_feet(&self) -> usize;
+}
+
+trait EatsFood {
+ fn favorite_food(&self) -> &'static str;
+}
+
+struct Frog;
+
+impl EatsFood for Frog {
+ fn favorite_food(&self) -> &'static str {
+ "flies"
+ }
+}
+
+impl HasFeet for Frog {
+ fn how_many_feet(&self) -> usize { 4 }
+}
+
+impl CastToAnyTrait for Arc<Frog> {
+ // Note: if you wanted to be able to add more traits to Frog elsewhere, you would
+ // need a registry of cast-to-trait objects, similar to the existing dispatch
+ // table. I'm not sure if that's needed.
+ fn cast_to_instance(&self, tp: TypeId) -> Option<Box<dyn Any>> {
+ if tp == TypeId::of::<Arc<dyn HasFeet>>() {
+ let arc: Arc<dyn HasFeet> = self.clone();
+ return Some(Box::new(arc));
+ } else if tp == TypeId::of::<Arc<dyn EatsFood>>() {
+ let arc: Arc<dyn EatsFood> = self.clone();
+ return Some(Box::new(arc));
+ }
+ None
}
}
fn main() {
- let _: Pin<Box<dyn Future<Output=()> + Send>> = Box::pin(
- async {
- failure().await;
- }
- );
+ let frog = Arc::new(Frog);
+ let erased_frog: &dyn CastToAnyTrait = &frog;
+
+ let with_feet: Arc<dyn HasFeet> = *erased_frog.cast_to::<Arc<dyn HasFeet>>().unwrap();
+ let eats_food: Arc<dyn EatsFood> = *erased_frog.cast_to::<Arc<dyn EatsFood>>().unwrap();
+
+ println!("A frog has {} feet and eats {}.",
+ with_feet.how_many_feet(),
+ eats_food.favorite_food())
}