chiark / gitweb /
frogs
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Mon, 5 Jun 2023 15:47:17 +0000 (16:47 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Mon, 5 Jun 2023 15:48:41 +0000 (16:48 +0100)
c&p from
  https://gitlab.torproject.org/tpo/core/arti/-/merge_requests/1208#note_2907850

src/main.rs

index 4b49bee39a2841aac4edb584203e91a6f4fda2f1..59582c80f87d323ebb21ab4e6afc5390de8c6ddc 100644 (file)
@@ -1,21 +1,66 @@
-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())
 }