manual_generic_struct/
manual_generic_struct.rs1#![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#![feature(ptr_metadata)]
9
10use core::{any::type_name, fmt::Display};
11
12use trait_cast::{TraitcastTarget, TraitcastableAny, TraitcastableAnyInfra, TraitcastableTo};
13
14struct HybridPet<T: Display> {
15 name: T,
16}
17impl<T: Display> HybridPet<T> {
18 fn greet(&self) {
19 println!("{}: Hi {}", self.name, type_name::<T>());
20 }
21}
22
23impl<T: Display> Dog for HybridPet<T> {
24 fn bark(&self) {
25 println!("{}: Woof!", self.name);
26 }
27}
28impl<V: Display + ?Sized, T: Display> Cat<V> for HybridPet<T> {
29 fn meow(&self, speak: &V) {
30 println!("{}: Meow! {speak}", self.name);
31 }
32}
33
34trait Dog {
35 fn bark(&self);
36}
37
38trait Cat<T: Display + ?Sized> {
39 fn meow(&self, speak: &T);
40}
41
42impl<T: Display + 'static> TraitcastableTo<dyn Dog> for HybridPet<T> {
43 const METADATA: ::core::ptr::DynMetadata<dyn Dog> = {
44 let self_ptr: *const HybridPet<T> = ::core::ptr::null::<HybridPet<T>>();
45 let dyn_ptr: *const dyn Dog = self_ptr as _;
46
47 dyn_ptr.to_raw_parts().1
48 };
49}
50
51impl<T: Display + 'static, V: Display + 'static + ?Sized> TraitcastableTo<dyn Cat<V>>
52 for HybridPet<T>
53{
54 const METADATA: ::core::ptr::DynMetadata<dyn Cat<V>> = {
55 let self_ptr: *const HybridPet<T> = ::core::ptr::null::<HybridPet<T>>();
56 let dyn_ptr: *const dyn Cat<V> = self_ptr as _;
57
58 dyn_ptr.to_raw_parts().1
59 };
60}
61
62impl<T: Display + 'static> HybridPet<T> {
65 const TARGETS: &[TraitcastTarget] = &[
66 TraitcastTarget::from::<Self, dyn Dog>(),
67 TraitcastTarget::from::<Self, dyn Cat<str>>(),
68 ];
69}
70
71unsafe impl<T: Display + 'static> TraitcastableAny for HybridPet<T> {
72 fn traitcast_targets(&self) -> &[TraitcastTarget] {
73 Self::TARGETS
74 }
75}
76
77#[cfg_attr(test, test)]
78fn main() {
79 let pet = Box::new(HybridPet {
81 name: "Kokusnuss".to_string(),
82 });
83 pet.greet();
84
85 let castable_pet: Box<dyn TraitcastableAny> = pet;
86
87 let as_dog: &dyn Dog = castable_pet.downcast_ref().unwrap();
88 as_dog.bark();
89
90 let as_cat: &dyn Cat<str> = castable_pet.downcast_ref().unwrap();
91 as_cat.meow("Text");
92
93 let cast_back: &HybridPet<String> = castable_pet.downcast_ref().unwrap();
94 cast_back.greet();
95
96 let invalid_cast: Option<&dyn Cat<String>> = castable_pet.downcast_ref();
99 assert!(invalid_cast.is_none());
100}