From: Ian Jackson Date: Mon, 5 Jun 2023 15:47:17 +0000 (+0100) Subject: frogs X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;h=8ff8b67fef31cbb718b9d9ae23046b0dbdb0b17a;p=rust-experiments.git frogs c&p from https://gitlab.torproject.org/tpo/core/arti/-/merge_requests/1208#note_2907850 --- diff --git a/src/main.rs b/src/main.rs index 4b49bee..59582c8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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>; +} + +pub trait CastToAnyTraitExt { + fn cast_to(&self) -> Option>; +} - while let Ok(event) = rx.recv() { - awaitpoint(event).await; +impl CastToAnyTraitExt for T { + fn cast_to(&self) -> Option> { + let instance = self.cast_to_instance(TypeId::of::())?; + 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 { + // 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> { + if tp == TypeId::of::>() { + let arc: Arc = self.clone(); + return Some(Box::new(arc)); + } else if tp == TypeId::of::>() { + let arc: Arc = self.clone(); + return Some(Box::new(arc)); + } + None } } fn main() { - let _: Pin + Send>> = Box::pin( - async { - failure().await; - } - ); + let frog = Arc::new(Frog); + let erased_frog: &dyn CastToAnyTrait = &frog; + + let with_feet: Arc = *erased_frog.cast_to::>().unwrap(); + let eats_food: Arc = *erased_frog.cast_to::>().unwrap(); + + println!("A frog has {} feet and eats {}.", + with_feet.how_many_feet(), + eats_food.favorite_food()) }