Skip to main content

turbo_tasks/
id.rs

1use std::{
2    fmt::{Debug, Display},
3    mem::transmute_copy,
4    num::{NonZero, NonZeroU64, TryFromIntError},
5    ops::Deref,
6};
7
8use bincode::{
9    Decode, Encode,
10    de::Decoder,
11    enc::Encoder,
12    error::{DecodeError, EncodeError},
13    impl_borrow_decode,
14};
15use serde::{Deserialize, Serialize, de::Visitor};
16
17use crate::{
18    TaskPersistence, registry,
19    trace::{TraceRawVcs, TraceRawVcsContext},
20};
21
22macro_rules! define_id {
23    (
24        $name:ident : $primitive:ty
25        $(,max = $max:expr)?
26        $(,derive($($derive:ty),*))?
27        $(,serde($serde:tt))?
28        $(,doc = $doc:literal)*
29        $(,)?
30    ) => {
31        $(#[doc = $doc])*
32        #[derive(Hash, Clone, Copy, PartialEq, Eq, PartialOrd, Ord $($(,$derive)*)? )]
33        $(#[serde($serde)])?
34        pub struct $name {
35            id: NonZero<$primitive>,
36        }
37
38        impl $name {
39            pub const MIN: Self = Self { id: NonZero::<$primitive>::MIN };
40            // `max` defaults to the primitive's max; types packed into a smaller
41            // bit field (e.g. `TaskId` in `RawVc`) override it.
42            pub const MAX: Self = {
43                let _max: $primitive = NonZero::<$primitive>::MAX.get();
44                $( let _max: $primitive = $max; )?
45                // SAFETY: `_max` is either `NonZero::MAX` or a caller-provided
46                // positive constant; both are non-zero.
47                Self { id: unsafe { NonZero::<$primitive>::new_unchecked(_max) } }
48            };
49
50            /// Constructs a wrapper type from the numeric identifier.
51            ///
52            /// # Safety
53            ///
54            /// The passed `id` must not be zero.
55            pub const unsafe fn new_unchecked(id: $primitive) -> Self {
56                Self { id: unsafe { NonZero::<$primitive>::new_unchecked(id) } }
57            }
58            /// Constructs a wrapper type from the numeric identifier.
59            ///
60            /// Returns `None` if the provided `id` is zero, otherwise returns
61            /// `Some(Self)` containing the wrapped non-zero identifier.
62            pub fn new(id: $primitive) -> Option<Self> {
63                NonZero::<$primitive>::new(id).map(|id| Self{id})
64            }
65            /// Allows `const` conversion to a [`NonZeroU64`], useful with
66            /// [`crate::id_factory::IdFactory::new_const`].
67            pub const fn to_non_zero_u64(self) -> NonZeroU64 {
68                const {
69                    assert!(<$primitive>::BITS <= u64::BITS);
70                }
71                unsafe { NonZeroU64::new_unchecked(self.id.get() as u64) }
72            }
73            /// Allows `const` conversion to [`NonZero<$primitive>`]
74            pub const fn to_non_zero_primitive(self) -> NonZero<$primitive> {
75                self.id
76            }
77            pub const fn to_primitive(self) -> $primitive {
78                self.id.get()
79            }
80        }
81
82        impl Display for $name {
83            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84                write!(f, concat!(stringify!($name), " {}"), self.id)
85            }
86        }
87
88        impl Deref for $name {
89            type Target = $primitive;
90
91            fn deref(&self) -> &Self::Target {
92                // SAFETY: `NonZero<T>` is guaranteed to have the same layout as `T`
93                unsafe { transmute_copy(&&self.id) }
94            }
95        }
96
97        define_id!(@impl_try_from_primitive_conversion $name $primitive);
98
99        impl From<NonZero<$primitive>> for $name {
100            fn from(id: NonZero::<$primitive>) -> Self {
101                Self {
102                    id,
103                }
104            }
105        }
106
107        impl From<$name> for NonZeroU64 {
108            fn from(id: $name) -> Self {
109                id.to_non_zero_u64()
110            }
111        }
112
113        impl TraceRawVcs for $name {
114            fn trace_raw_vcs(&self, _trace_context: &mut TraceRawVcsContext) {}
115        }
116    };
117    (
118        @impl_try_from_primitive_conversion $name:ident u64
119    ) => {
120        // we get a `TryFrom` blanket impl for free via the `From` impl
121    };
122    (
123        @impl_try_from_primitive_conversion $name:ident $primitive:ty
124    ) => {
125        impl TryFrom<$primitive> for $name {
126            type Error = TryFromIntError;
127
128            fn try_from(id: $primitive) -> Result<Self, Self::Error> {
129                Ok(Self {
130                    id: NonZero::try_from(id)?
131                })
132            }
133        }
134
135        impl TryFrom<NonZeroU64> for $name {
136            type Error = TryFromIntError;
137
138            fn try_from(id: NonZeroU64) -> Result<Self, Self::Error> {
139                Ok(Self { id: NonZero::try_from(id)? })
140            }
141        }
142    };
143}
144
145define_id!(
146    TaskId: u32,
147    // Capped below `u32::MAX` so the id fits in 31 bits when packed into `RawVc`.
148    max = TASK_ID_MAX,
149    derive(Serialize, Deserialize, Encode, Decode),
150    serde(transparent),
151);
152define_id!(
153    ValueTypeId: u16,
154    // Capped below `u16::MAX` so the id fits in 10 bits when packed into `CellId`.
155    max = crate::CellId::MAX_VALUE_TYPE_ID,
156);
157define_id!(FunctionId: u16);
158define_id!(TraitTypeId: u16);
159define_id!(
160    LocalTaskId: u32,
161    derive(Debug, Serialize, Deserialize, Encode, Decode),
162    serde(transparent),
163    doc = "Represents the nth `local` function call inside a task.",
164);
165define_id!(
166    ExecutionId: u16,
167    derive(Debug, Serialize, Deserialize, Encode, Decode),
168    serde(transparent),
169    doc = "An identifier for a specific task execution. Used to assert that local `Vc`s don't \
170        leak. This value may overflow and re-use old values.",
171);
172
173impl Debug for TaskId {
174    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175        f.debug_struct("TaskId").field("id", &self.id).finish()
176    }
177}
178
179unsafe impl crate::NonLocalValue for TaskId {}
180
181/// `TaskId` values are constrained to 31 bits to preserve a niche for [`crate::RawVc`]. Bit 30
182/// marks transient tasks; bit 31 is always zero.
183pub const TRANSIENT_TASK_BIT: u32 = 0x4000_0000;
184
185/// The largest value a [`TaskId`] may hold (31 bits set).
186pub const TASK_ID_MAX: u32 = 0x7FFF_FFFF;
187
188impl TaskId {
189    pub fn is_transient(&self) -> bool {
190        **self & TRANSIENT_TASK_BIT != 0
191    }
192    pub fn persistence(&self) -> TaskPersistence {
193        // tasks with `TaskPersistence::LocalCells` have no `TaskId`, so we can ignore that case
194        if self.is_transient() {
195            TaskPersistence::Transient
196        } else {
197            TaskPersistence::Persistent
198        }
199    }
200}
201
202macro_rules! make_registered_serializable {
203    ($ty:ty, $primitive:ty, $get_object:path, $validate_type_id:path $(,)?) => {
204        impl Serialize for $ty {
205            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
206            where
207                S: serde::Serializer,
208            {
209                serializer.serialize_u16(self.id.into())
210            }
211        }
212
213        impl<'de> Deserialize<'de> for $ty {
214            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
215            where
216                D: serde::Deserializer<'de>,
217            {
218                struct DeserializeVisitor;
219                impl<'de> Visitor<'de> for DeserializeVisitor {
220                    type Value = $ty;
221
222                    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
223                        formatter.write_str(concat!("an id of a registered ", stringify!($ty)))
224                    }
225
226                    fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
227                    where
228                        E: serde::de::Error,
229                    {
230                        match Self::Value::new(v) {
231                            Some(value) => {
232                                if let Some(error) = $validate_type_id(value) {
233                                    Err(E::custom(error))
234                                } else {
235                                    Ok(value)
236                                }
237                            }
238                            None => Err(E::unknown_variant(&format!("{v}"), &["a non zero u16"])),
239                        }
240                    }
241                }
242
243                deserializer.deserialize_u16(DeserializeVisitor)
244            }
245        }
246
247        impl Debug for $ty {
248            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249                f.debug_struct(stringify!($ty))
250                    .field("id", &self.id)
251                    .field("name", &$get_object(*self))
252                    .finish()
253            }
254        }
255
256        impl Encode for $ty {
257            fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
258                <NonZero<$primitive> as Encode>::encode(&self.id, encoder)
259            }
260        }
261
262        impl<Context> Decode<Context> for $ty {
263            fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
264                let value = Self {
265                    id: NonZero::<$primitive>::decode(decoder)?,
266                };
267                if let Some(error) = $validate_type_id(value) {
268                    Err(DecodeError::OtherString(error.to_string()))
269                } else {
270                    Ok(value)
271                }
272            }
273        }
274
275        impl_borrow_decode!($ty);
276    };
277}
278
279make_registered_serializable!(
280    ValueTypeId,
281    u16,
282    registry::get_value_type,
283    registry::validate_value_type_id,
284);
285make_registered_serializable!(
286    TraitTypeId,
287    u16,
288    registry::get_trait,
289    registry::validate_trait_type_id,
290);
291make_registered_serializable!(
292    FunctionId,
293    u16,
294    registry::get_native_function,
295    registry::validate_function_id,
296);