manual/
manual.rs

1//! This example demonstrates how to manually implement the `TraitcastableAny` trait for a non generic struct `HybridPet`.
2#![allow(clippy::undocumented_unsafe_blocks, clippy::use_self)]
3#![expect(
4  unsafe_code,
5  reason = "Manual traitcast implementations require unsafe code."
6)]
7#![cfg_attr(feature = "min_specialization", feature(min_specialization))]
8#![allow(incomplete_features)]
9#![feature(ptr_metadata)]
10
11use trait_cast::{
12  TraitcastTarget, TraitcastableAny, TraitcastableAnyInfra, TraitcastableAnyInfraExt,
13  TraitcastableTo,
14};
15
16struct HybridPet {
17  name: String,
18}
19impl TraitcastableTo<dyn Dog> for HybridPet {
20  const METADATA: ::core::ptr::DynMetadata<dyn Dog> = {
21    let self_ptr: *const HybridPet = ::core::ptr::null::<HybridPet>();
22    let dyn_ptr: *const dyn Dog = self_ptr as _;
23
24    dyn_ptr.to_raw_parts().1
25  };
26}
27
28impl TraitcastableTo<dyn Cat> for HybridPet {
29  const METADATA: ::core::ptr::DynMetadata<dyn Cat> = {
30    let self_ptr: *const Self = ::core::ptr::null::<Self>();
31    let dyn_ptr: *const dyn Cat = self_ptr as _;
32
33    dyn_ptr.to_raw_parts().1
34  };
35}
36
37unsafe impl TraitcastableAny for HybridPet {
38  fn traitcast_targets(&self) -> &[TraitcastTarget] {
39    const TARGETS: &[TraitcastTarget] = &[
40      TraitcastTarget::from::<HybridPet, dyn Dog>(),
41      TraitcastTarget::from::<HybridPet, dyn Cat>(),
42    ];
43    TARGETS
44  }
45}
46impl HybridPet {
47  fn greet(&self) {
48    println!("{}: Hi", self.name);
49  }
50}
51
52impl Dog for HybridPet {
53  fn bark(&self) {
54    println!("{}: Woof!", self.name);
55  }
56}
57impl Cat for HybridPet {
58  fn meow(&self) {
59    println!("{}: Meow!", self.name);
60  }
61}
62
63trait Dog {
64  fn bark(&self);
65}
66trait Cat: TraitcastableAny {
67  fn meow(&self);
68}
69trait Mouse {}
70
71#[cfg_attr(test, test)]
72fn main() {
73  // The box is technically not needed but kept for added realism
74  let pet = Box::new(HybridPet {
75    name: "Kokusnuss".to_string(),
76  });
77  pet.greet();
78
79  let castable_pet: Box<dyn TraitcastableAny> = pet;
80
81  let as_dog: &dyn Dog = castable_pet.downcast_ref().unwrap();
82  as_dog.bark();
83
84  let as_cat: &dyn Cat = castable_pet.downcast_ref().unwrap();
85  as_cat.meow();
86
87  let cast_back: &HybridPet = castable_pet.downcast_ref().unwrap();
88  cast_back.greet();
89
90  // upcasting examples
91  // require feature flag trait_upcasting
92  // you must also add TraitcastableAny to your trait
93  let upcast_ref: &dyn TraitcastableAny = as_cat;
94  let downcast_to_cat_again: &dyn Cat = upcast_ref.downcast_ref().unwrap();
95  downcast_to_cat_again.meow();
96
97  let as_box_cat: Box<dyn Cat> = castable_pet.downcast().unwrap();
98  let castable_pet: Box<dyn TraitcastableAny> = as_box_cat;
99
100  // failed cast example
101  // shows how to recover the box without dropping it
102  let no_mouse: Result<Box<dyn Mouse>, _> = castable_pet.downcast();
103  if let Err(no_mouse) = no_mouse {
104    let as_cat: &dyn Cat = no_mouse.downcast_ref().unwrap();
105    as_cat.meow();
106  }
107}