1use bevy_platform::{hash::FixedHasher, sync::Arc};
2use core::{
3 any::{Any, TypeId},
4 hash::{BuildHasher, Hash, Hasher},
5};
6
7#[derive(Clone, Copy)]
9pub struct ErasedMeshPipelineKey {
10 bits: u64,
11 type_id: TypeId,
12}
13
14impl ErasedMeshPipelineKey {
15 #[inline]
16 pub fn new<T: 'static>(key: T) -> Self
17 where
18 u64: From<T>,
19 {
20 Self {
21 bits: key.into(),
22 type_id: TypeId::of::<T>(),
23 }
24 }
25
26 #[inline]
27 pub fn downcast<T: 'static + From<u64>>(&self) -> T {
28 assert_eq!(
29 self.type_id,
30 TypeId::of::<T>(),
31 "ErasedMeshPipelineKey::downcast called with wrong type"
32 );
33 self.bits.into()
34 }
35}
36
37impl PartialEq for ErasedMeshPipelineKey {
38 #[inline]
39 fn eq(&self, other: &Self) -> bool {
40 self.type_id == other.type_id && self.bits == other.bits
41 }
42}
43
44impl Eq for ErasedMeshPipelineKey {}
45
46impl Hash for ErasedMeshPipelineKey {
47 #[inline]
48 fn hash<H: Hasher>(&self, state: &mut H) {
49 self.type_id.hash(state);
50 self.bits.hash(state);
51 }
52}
53
54impl Default for ErasedMeshPipelineKey {
55 fn default() -> Self {
56 Self {
57 bits: 0,
58 type_id: TypeId::of::<()>(),
59 }
60 }
61}
62
63impl core::fmt::Debug for ErasedMeshPipelineKey {
64 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
65 f.debug_struct("ErasedMeshPipelineKey")
66 .field("type_id", &self.type_id)
67 .field("bits", &format_args!("{:#018x}", self.bits))
68 .finish()
69 }
70}
71
72#[derive(Clone, Debug, PartialEq, Eq, Hash)]
73pub struct ErasedMaterialPipelineKey {
74 pub mesh_key: ErasedMeshPipelineKey,
75 pub material_key: ErasedMaterialKey,
76 pub type_id: TypeId,
77}
78
79#[derive(Debug)]
80pub struct ErasedMaterialKey {
81 type_id: TypeId,
82 hash: u64,
83 value: Box<dyn Any + Send + Sync>,
84 vtable: Arc<ErasedMaterialKeyVTable>,
85}
86
87#[derive(Debug)]
88pub struct ErasedMaterialKeyVTable {
89 clone_fn: fn(&dyn Any) -> Box<dyn Any + Send + Sync>,
90 partial_eq_fn: fn(&dyn Any, &dyn Any) -> bool,
91}
92
93impl ErasedMaterialKey {
94 pub fn new<T>(material_key: T) -> Self
95 where
96 T: Clone + Hash + PartialEq + Send + Sync + 'static,
97 {
98 let type_id = TypeId::of::<T>();
99 let hash = FixedHasher::hash_one(&FixedHasher, &material_key);
100
101 fn clone<T: Clone + Send + Sync + 'static>(any: &dyn Any) -> Box<dyn Any + Send + Sync> {
102 Box::new(any.downcast_ref::<T>().unwrap().clone())
103 }
104 fn partial_eq<T: PartialEq + 'static>(a: &dyn Any, b: &dyn Any) -> bool {
105 a.downcast_ref::<T>().unwrap() == b.downcast_ref::<T>().unwrap()
106 }
107
108 Self {
109 type_id,
110 hash,
111 value: Box::new(material_key),
112 vtable: Arc::new(ErasedMaterialKeyVTable {
113 clone_fn: clone::<T>,
114 partial_eq_fn: partial_eq::<T>,
115 }),
116 }
117 }
118
119 pub fn to_key<T: Clone + 'static>(&self) -> T {
120 debug_assert_eq!(self.type_id, TypeId::of::<T>());
121 self.value.downcast_ref::<T>().unwrap().clone()
122 }
123}
124
125impl PartialEq for ErasedMaterialKey {
126 fn eq(&self, other: &Self) -> bool {
127 self.type_id == other.type_id
128 && (self.vtable.partial_eq_fn)(self.value.as_ref(), other.value.as_ref())
129 }
130}
131
132impl Eq for ErasedMaterialKey {}
133
134impl Clone for ErasedMaterialKey {
135 fn clone(&self) -> Self {
136 Self {
137 type_id: self.type_id,
138 hash: self.hash,
139 value: (self.vtable.clone_fn)(self.value.as_ref()),
140 vtable: self.vtable.clone(),
141 }
142 }
143}
144
145impl Hash for ErasedMaterialKey {
146 fn hash<H: Hasher>(&self, state: &mut H) {
147 self.type_id.hash(state);
148 self.hash.hash(state);
149 }
150}
151
152impl Default for ErasedMaterialKey {
153 fn default() -> Self {
154 Self::new(())
155 }
156}