turbo_tasks/registry/
mod.rs1use std::{cell::SyncUnsafeCell, num::NonZeroU16, sync::LazyLock};
2
3use anyhow::Error;
4
5use crate::{
6 TraitType, ValueType,
7 id::{FunctionId, TraitTypeId, ValueTypeId},
8 native_function::NativeFunction,
9};
10
11mod registry_type;
12
13pub use registry_type::RegistryType;
14
15macro_rules! turbo_registry {
20 ($name:literal, $ty:ty) => {
21 inventory::collect!(&'static $ty);
22
23 impl ::core::cmp::Eq for $ty {}
24 impl ::core::cmp::PartialEq for $ty {
25 fn eq(&self, other: &$ty) -> bool {
26 ::core::ptr::eq(self, other)
27 }
28 }
29 impl ::core::hash::Hash for $ty {
30 fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
31 ::core::ptr::hash(self, state)
32 }
33 }
34 impl ::core::cmp::Ord for $ty {
35 fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
36 (self as *const Self).cmp(&(other as *const Self))
37 }
38 }
39 impl ::core::cmp::PartialOrd for $ty {
40 fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
41 Some(self.cmp(other))
42 }
43 }
44 };
45}
46
47pub(crate) use turbo_registry;
48
49#[macro_export]
50#[doc(hidden)]
51macro_rules! turbo_register {
52 ($name:ident : $ty:ty = $value:expr) => {
53 static $name: $ty = $value;
54 $crate::macro_helpers::inventory_submit! { &$name }
55 };
56 ($reg:ty => $name:ident : $ty:ty = $value:expr) => {
57 static $name: $ty = $value;
58 $crate::macro_helpers::inventory_submit! { &$name }
59
60 impl $crate::macro_helpers::RegistryDef<$ty> for $reg {
61 const DEF: &'static $ty = &$name;
62 }
63 };
64}
65
66#[doc(hidden)]
67pub trait RegistryDef<T: 'static> {
68 const DEF: &'static T;
69}
70
71trait Registerable: 'static + Eq + std::hash::Hash {
76 type Id: Copy + From<NonZeroU16> + std::ops::Deref<Target = u16> + std::fmt::Display;
78 const TYPE_NAME: &'static str;
79
80 fn ty(&self) -> &RegistryType;
82}
83
84impl Registerable for NativeFunction {
85 type Id = FunctionId;
86 const TYPE_NAME: &'static str = "Function";
87
88 fn ty(&self) -> &RegistryType {
89 &self.ty
90 }
91}
92
93impl Registerable for ValueType {
94 type Id = ValueTypeId;
95 const TYPE_NAME: &'static str = "Value";
96 fn ty(&self) -> &RegistryType {
97 &self.ty
98 }
99}
100
101impl Registerable for TraitType {
102 type Id = TraitTypeId;
103 const TYPE_NAME: &'static str = "Trait";
104 fn ty(&self) -> &RegistryType {
105 &self.ty
106 }
107}
108
109fn init_registry<T: Registerable>(mut items: Vec<&'static T>) -> Box<[&'static T]> {
111 items.sort_unstable_by_key(|item| item.ty().global_name);
113
114 let mut id = NonZeroU16::MIN;
115 let mut prev_name: Option<&str> = None;
116 for item in items.iter() {
117 let global_name = item.ty().global_name;
118 if let Some(prev) = prev_name {
119 assert!(
120 prev != global_name,
121 "multiple {ty} items registered with name: {global_name}!",
122 ty = T::TYPE_NAME
123 );
124 }
125 prev_name = Some(global_name);
126 unsafe { std::ptr::write(SyncUnsafeCell::raw_get(&item.ty().id), u16::from(id)) };
128 id = id.checked_add(1).expect("overflowing item ids");
129 }
130
131 items.into_boxed_slice()
132}
133
134#[inline]
136fn get_item<T: Registerable>(registry: &LazyLock<Box<[&'static T]>>, id: T::Id) -> &'static T {
137 registry[*id as usize - 1]
138}
139
140#[inline]
146unsafe fn get_id_unchecked<T: Registerable>(item: &'static T) -> T::Id {
147 let n = unsafe { std::ptr::read(item.ty().id.get()) };
150 let Some(id) = NonZeroU16::new(n) else {
151 panic!(
152 "{ty} isn't registered: {item}",
153 ty = T::TYPE_NAME,
154 item = item.ty().global_name
155 );
156 };
157 T::Id::from(id)
158}
159
160#[inline]
163fn get_id<T: Registerable>(registry: &LazyLock<Box<[&'static T]>>, item: &'static T) -> T::Id {
164 LazyLock::force(registry);
165 unsafe { get_id_unchecked(item) }
167}
168
169fn validate_id<T: Registerable>(
171 registry: &LazyLock<Box<[&'static T]>>,
172 id: T::Id,
173) -> Option<Error> {
174 let len = registry.len();
175 if *id as usize <= len {
176 None
177 } else {
178 Some(anyhow::anyhow!(
179 "Invalid {ty} id, {id} expected a value <= {len}",
180 ty = T::TYPE_NAME
181 ))
182 }
183}
184
185static FUNCTIONS: LazyLock<Box<[&'static NativeFunction]>> = LazyLock::new(|| {
186 init_registry(
187 inventory::iter::<&'static NativeFunction>
188 .into_iter()
189 .copied()
190 .collect(),
191 )
192});
193
194#[inline]
195pub fn get_native_function(id: FunctionId) -> &'static NativeFunction {
196 get_item(&FUNCTIONS, id)
197}
198
199#[inline]
200pub fn get_function_id(func: &'static NativeFunction) -> FunctionId {
201 get_id(&FUNCTIONS, func)
202}
203
204pub fn validate_function_id(id: FunctionId) -> Option<Error> {
205 validate_id(&FUNCTIONS, id)
206}
207
208pub(crate) static VALUES: LazyLock<Box<[&'static ValueType]>> = LazyLock::new(|| {
209 let items = init_registry(
210 inventory::iter::<&'static ValueType>
211 .into_iter()
212 .copied()
213 .collect(),
214 );
215 crate::value_type::register_all_trait_methods(&items);
216 items
217});
218
219#[inline]
220pub fn get_value_type_id(value: &'static ValueType) -> ValueTypeId {
221 get_id(&VALUES, value)
222}
223
224#[inline]
234pub(crate) unsafe fn get_value_type_id_unchecked(value: &'static ValueType) -> ValueTypeId {
235 unsafe { get_id_unchecked(value) }
236}
237
238#[inline]
239pub fn get_value_type(id: ValueTypeId) -> &'static ValueType {
240 get_item(&VALUES, id)
241}
242
243pub fn validate_value_type_id(id: ValueTypeId) -> Option<Error> {
244 validate_id(&VALUES, id)
245}
246
247#[inline]
249pub(crate) fn trait_type_count() -> usize {
250 TRAITS.len()
251}
252
253static TRAITS: LazyLock<Box<[&'static TraitType]>> = LazyLock::new(|| {
254 init_registry(
255 inventory::iter::<&'static TraitType>
256 .into_iter()
257 .copied()
258 .collect(),
259 )
260});
261
262#[inline]
263pub fn get_trait_type_id(trait_type: &'static TraitType) -> TraitTypeId {
264 get_id(&TRAITS, trait_type)
265}
266
267#[inline]
268pub fn get_trait(id: TraitTypeId) -> &'static TraitType {
269 get_item(&TRAITS, id)
270}
271
272pub fn validate_trait_type_id(id: TraitTypeId) -> Option<Error> {
273 validate_id(&TRAITS, id)
274}