turbo_tasks/registry/
mod.rs1use std::{cell::SyncUnsafeCell, num::NonZeroU16, sync::LazyLock};
2
3use anyhow::Error;
4use scattered_collect::slice::ScatteredSlice;
5
6use crate::{
7 TraitType, ValueType,
8 id::{FunctionId, TraitTypeId, ValueTypeId},
9 native_function::NativeFunction,
10};
11
12mod registry_type;
13
14pub use registry_type::RegistryType;
15
16macro_rules! impl_ptr_identity {
18 ($ty:ty) => {
19 impl ::core::cmp::Eq for $ty {}
20 impl ::core::cmp::PartialEq for $ty {
21 fn eq(&self, other: &$ty) -> bool {
22 ::core::ptr::eq(self, other)
23 }
24 }
25 impl ::core::hash::Hash for $ty {
26 fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
27 ::core::ptr::hash(self, state)
28 }
29 }
30 impl ::core::cmp::Ord for $ty {
31 fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
32 (self as *const Self).cmp(&(other as *const Self))
33 }
34 }
35 impl ::core::cmp::PartialOrd for $ty {
36 fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
37 Some(self.cmp(other))
38 }
39 }
40 };
41}
42
43pub(crate) use impl_ptr_identity;
44
45#[doc(hidden)]
47#[scattered_collect::gather]
48pub static FUNCTIONS_SLICE: ScatteredSlice<&'static NativeFunction>;
49
50#[doc(hidden)]
51#[scattered_collect::gather]
52pub static VALUES_SLICE: ScatteredSlice<&'static ValueType>;
53
54#[doc(hidden)]
55#[scattered_collect::gather]
56pub static TRAITS_SLICE: ScatteredSlice<&'static TraitType>;
57
58#[macro_export]
60#[doc(hidden)]
61macro_rules! register_function {
62 ($name:ident = $value:expr) => {
63 static $name: $crate::macro_helpers::NativeFunction = $value;
64 $crate::macro_helpers::scattered_collect::declarative::scatter! {
65 #[scatter($crate::registry::FUNCTIONS_SLICE)]
66 const _: &'static $crate::macro_helpers::NativeFunction = &$name;
67 }
68 };
69}
70
71#[macro_export]
74#[doc(hidden)]
75macro_rules! register_value {
76 ($reg:ty => $name:ident = $value:expr) => {
77 static $name: $crate::ValueType = $value;
78 $crate::macro_helpers::scattered_collect::declarative::scatter! {
79 #[scatter($crate::registry::VALUES_SLICE)]
80 const _: &'static $crate::ValueType = &$name;
81 }
82
83 impl $crate::macro_helpers::RegistryDef<$crate::ValueType> for $reg {
84 const DEF: &'static $crate::ValueType = &$name;
85 }
86 };
87}
88
89#[macro_export]
92#[doc(hidden)]
93macro_rules! register_trait {
94 ($reg:ty => $name:ident = $value:expr) => {
95 static $name: $crate::TraitType = $value;
96 $crate::macro_helpers::scattered_collect::declarative::scatter! {
97 #[scatter($crate::registry::TRAITS_SLICE)]
98 const _: &'static $crate::TraitType = &$name;
99 }
100
101 impl $crate::macro_helpers::RegistryDef<$crate::TraitType> for $reg {
102 const DEF: &'static $crate::TraitType = &$name;
103 }
104 };
105}
106
107#[doc(hidden)]
108pub trait RegistryDef<T: 'static> {
109 const DEF: &'static T;
110}
111
112trait Registerable: 'static + Eq + std::hash::Hash {
117 type Id: Copy + From<NonZeroU16> + std::ops::Deref<Target = u16> + std::fmt::Display;
119 const TYPE_NAME: &'static str;
120
121 const MAX_ID: u16 = u16::MAX;
123
124 fn ty(&self) -> &RegistryType;
126}
127
128impl Registerable for NativeFunction {
129 type Id = FunctionId;
130 const TYPE_NAME: &'static str = "Function";
131
132 fn ty(&self) -> &RegistryType {
133 &self.ty
134 }
135}
136
137impl Registerable for ValueType {
138 type Id = ValueTypeId;
139 const TYPE_NAME: &'static str = "Value";
140 const MAX_ID: u16 = ValueTypeId::MAX.to_primitive();
141 fn ty(&self) -> &RegistryType {
142 &self.ty
143 }
144}
145
146impl Registerable for TraitType {
147 type Id = TraitTypeId;
148 const TYPE_NAME: &'static str = "Trait";
149 fn ty(&self) -> &RegistryType {
150 &self.ty
151 }
152}
153
154fn init_registry<T: Registerable>(mut items: Vec<&'static T>) -> Box<[&'static T]> {
156 items.sort_unstable_by_key(|item| item.ty().global_name);
158
159 let mut id = NonZeroU16::MIN;
160 let mut prev_name: Option<&str> = None;
161 for item in items.iter() {
162 let global_name = item.ty().global_name;
163 if let Some(prev) = prev_name {
164 assert!(
165 prev != global_name,
166 "multiple {ty} items registered with name: {global_name}!",
167 ty = T::TYPE_NAME
168 );
169 }
170 prev_name = Some(global_name);
171 assert!(
172 u16::from(id) <= T::MAX_ID,
173 "too many {ty} items registered: id {id} exceeds the cap of {max}",
174 ty = T::TYPE_NAME,
175 max = T::MAX_ID,
176 );
177 unsafe { std::ptr::write(SyncUnsafeCell::raw_get(&item.ty().id), u16::from(id)) };
179 id = id.checked_add(1).expect("overflowing item ids");
180 }
181
182 items.into_boxed_slice()
183}
184
185#[inline]
187fn get_item<T: Registerable>(registry: &LazyLock<Box<[&'static T]>>, id: T::Id) -> &'static T {
188 registry[*id as usize - 1]
189}
190
191#[inline]
197unsafe fn get_id_unchecked<T: Registerable>(item: &'static T) -> T::Id {
198 let n = unsafe { std::ptr::read(item.ty().id.get()) };
201 let Some(id) = NonZeroU16::new(n) else {
202 panic!(
203 "{ty} isn't registered: {item}",
204 ty = T::TYPE_NAME,
205 item = item.ty().global_name
206 );
207 };
208 T::Id::from(id)
209}
210
211#[inline]
214fn get_id<T: Registerable>(registry: &LazyLock<Box<[&'static T]>>, item: &'static T) -> T::Id {
215 LazyLock::force(registry);
216 unsafe { get_id_unchecked(item) }
218}
219
220fn validate_id<T: Registerable>(
222 registry: &LazyLock<Box<[&'static T]>>,
223 id: T::Id,
224) -> Option<Error> {
225 let len = registry.len();
226 if *id as usize <= len {
227 None
228 } else {
229 Some(anyhow::anyhow!(
230 "Invalid {ty} id, {id} expected a value <= {len}",
231 ty = T::TYPE_NAME
232 ))
233 }
234}
235
236static FUNCTIONS: LazyLock<Box<[&'static NativeFunction]>> =
237 LazyLock::new(|| init_registry(FUNCTIONS_SLICE.iter().copied().collect()));
238
239#[inline]
240pub fn get_native_function(id: FunctionId) -> &'static NativeFunction {
241 get_item(&FUNCTIONS, id)
242}
243
244#[inline]
245pub fn get_function_id(func: &'static NativeFunction) -> FunctionId {
246 get_id(&FUNCTIONS, func)
247}
248
249pub fn validate_function_id(id: FunctionId) -> Option<Error> {
250 validate_id(&FUNCTIONS, id)
251}
252
253static VALUES: LazyLock<Box<[&'static ValueType]>> = LazyLock::new(|| {
254 let items = init_registry(VALUES_SLICE.iter().copied().collect());
255 crate::value_type::register_all_trait_methods();
256 items
257});
258
259#[inline]
260pub fn get_value_type_id(value: &'static ValueType) -> ValueTypeId {
261 get_id(&VALUES, value)
262}
263
264#[inline]
273pub(crate) unsafe fn get_value_type_id_unchecked(value: &'static ValueType) -> ValueTypeId {
274 unsafe { get_id_unchecked(value) }
275}
276
277#[inline]
278pub fn get_value_type(id: ValueTypeId) -> &'static ValueType {
279 get_item(&VALUES, id)
280}
281
282pub fn validate_value_type_id(id: ValueTypeId) -> Option<Error> {
283 validate_id(&VALUES, id)
284}
285
286#[inline]
288pub(crate) fn trait_type_count() -> usize {
289 TRAITS.len()
290}
291
292static TRAITS: LazyLock<Box<[&'static TraitType]>> =
293 LazyLock::new(|| init_registry(TRAITS_SLICE.iter().copied().collect()));
294
295#[inline]
296pub fn get_trait_type_id(trait_type: &'static TraitType) -> TraitTypeId {
297 get_id(&TRAITS, trait_type)
298}
299
300#[inline]
301pub fn get_trait(id: TraitTypeId) -> &'static TraitType {
302 get_item(&TRAITS, id)
303}
304
305pub fn validate_trait_type_id(id: TraitTypeId) -> Option<Error> {
306 validate_id(&TRAITS, id)
307}