rspack_cacheable/dyn/
mod.rs1use core::marker::PhantomData;
2use std::{
3 collections::HashMap,
4 hash::{Hash, Hasher},
5};
6
7use inventory;
8use rkyv::{
9 Archived, Portable, SerializeUnsized,
10 bytecheck::{CheckBytes, StructCheckContext},
11 ptr_meta::{DynMetadata, Pointee},
12 rancor::{Fallible, Trace},
13 traits::NoUndef,
14};
15
16pub mod validation;
17mod vtable_ptr;
18
19pub use vtable_ptr::VTablePtr;
20
21use crate::{DeserializeError, Deserializer, SerializeError, Serializer};
22
23pub trait SerializeDyn {
25 fn serialize_dyn(&self, serializer: &mut Serializer) -> Result<usize, SerializeError>;
27}
28
29impl<T> SerializeDyn for T
30where
31 T: for<'a> SerializeUnsized<Serializer<'a>>,
32{
33 fn serialize_dyn(&self, serializer: &mut Serializer) -> Result<usize, SerializeError> {
34 self.serialize_unsized(serializer)
35 }
36}
37
38pub trait DeserializeDyn<T: Pointee + ?Sized> {
42 fn deserialize_dyn(
44 &self,
45 deserializer: &mut Deserializer,
46 out: *mut T,
47 ) -> Result<(), DeserializeError>;
48
49 fn deserialized_pointer_metadata(&self) -> DynMetadata<T>;
51}
52
53pub struct ArchivedDynMetadata<T: ?Sized> {
55 dyn_id: Archived<u64>,
56 phantom: PhantomData<T>,
57}
58
59impl<T: ?Sized> Default for ArchivedDynMetadata<T> {
60 fn default() -> Self {
61 Self {
62 dyn_id: Archived::<u64>::from_native(0),
63 phantom: PhantomData::default(),
64 }
65 }
66}
67impl<T: ?Sized> Hash for ArchivedDynMetadata<T> {
68 #[inline]
69 fn hash<H: Hasher>(&self, state: &mut H) {
70 Hash::hash(&self.dyn_id, state);
71 }
72}
73impl<T: ?Sized> PartialEq for ArchivedDynMetadata<T> {
74 #[inline]
75 fn eq(&self, other: &ArchivedDynMetadata<T>) -> bool {
76 self.dyn_id == other.dyn_id
77 }
78}
79impl<T: ?Sized> Eq for ArchivedDynMetadata<T> {}
80#[allow(clippy::non_canonical_partial_ord_impl)]
81impl<T: ?Sized> PartialOrd for ArchivedDynMetadata<T> {
82 #[inline]
83 fn partial_cmp(&self, other: &ArchivedDynMetadata<T>) -> Option<::core::cmp::Ordering> {
84 Some(self.dyn_id.cmp(&other.dyn_id))
85 }
86}
87impl<T: ?Sized> Ord for ArchivedDynMetadata<T> {
88 #[inline]
89 fn cmp(&self, other: &ArchivedDynMetadata<T>) -> ::core::cmp::Ordering {
90 self.dyn_id.cmp(&other.dyn_id)
91 }
92}
93impl<T: ?Sized> Clone for ArchivedDynMetadata<T> {
94 fn clone(&self) -> ArchivedDynMetadata<T> {
95 *self
96 }
97}
98impl<T: ?Sized> Copy for ArchivedDynMetadata<T> {}
99impl<T: ?Sized> Unpin for ArchivedDynMetadata<T> {}
100unsafe impl<T: ?Sized> Sync for ArchivedDynMetadata<T> {}
101unsafe impl<T: ?Sized> Send for ArchivedDynMetadata<T> {}
102unsafe impl<T: ?Sized> NoUndef for ArchivedDynMetadata<T> {}
103unsafe impl<T: ?Sized> Portable for ArchivedDynMetadata<T> {}
104unsafe impl<T: ?Sized, C> CheckBytes<C> for ArchivedDynMetadata<T>
105where
106 C: Fallible + ?Sized,
107 C::Error: Trace,
108 Archived<u64>: CheckBytes<C>,
109 PhantomData<T>: CheckBytes<C>,
110{
111 unsafe fn check_bytes(
112 value: *const Self,
113 context: &mut C,
114 ) -> ::core::result::Result<(), C::Error> {
115 unsafe {
116 Archived::<u64>::check_bytes(&raw const (*value).dyn_id, context).map_err(|e| {
117 C::Error::trace(
118 e,
119 StructCheckContext {
120 struct_name: "ArchivedDynMetadata",
121 field_name: "dyn_id",
122 },
123 )
124 })?;
125 }
126 unsafe {
127 PhantomData::<T>::check_bytes(&raw const (*value).phantom, context).map_err(|e| {
128 C::Error::trace(
129 e,
130 StructCheckContext {
131 struct_name: "ArchivedDynMetadata",
132 field_name: "phantom",
133 },
134 )
135 })?;
136 }
137 Ok(())
138 }
139}
140
141impl<T: ?Sized> ArchivedDynMetadata<T> {
142 pub fn new(dyn_id: u64) -> Self {
143 Self {
144 dyn_id: Archived::<u64>::from_native(dyn_id),
145 phantom: PhantomData,
146 }
147 }
148
149 pub fn lookup_metadata(&self) -> DynMetadata<T> {
151 unsafe {
152 DYN_REGISTRY
153 .get(&self.dyn_id.to_native())
154 .expect("attempted to get vtable for an unregistered impl")
155 .cast()
156 }
157 }
158}
159
160pub struct DynEntry {
161 dyn_id: u64,
162 vtable: VTablePtr,
163}
164
165impl DynEntry {
166 pub const fn new(dyn_id: u64, vtable: VTablePtr) -> Self {
167 Self { dyn_id, vtable }
168 }
169}
170
171inventory::collect!(DynEntry);
172
173static DYN_REGISTRY: std::sync::LazyLock<HashMap<u64, VTablePtr>> =
174 std::sync::LazyLock::new(|| {
175 let mut result = HashMap::default();
176 for entry in inventory::iter::<DynEntry> {
177 let old_value = result.insert(entry.dyn_id, entry.vtable);
178 if old_value.is_some() {
179 panic!("cacheable_dyn init global REGISTRY error, duplicate implementation.")
180 }
181 }
182 result.shrink_to_fit();
183 result
184 });