Skip to main content

turbo_tasks/vc/
ord.rs

1use std::{
2    cmp::Ordering,
3    fmt::{self, Debug},
4    hash::{Hash, Hasher},
5    ops::Deref,
6    slice,
7};
8
9use bincode::{Decode, Encode};
10use serde::{Deserialize, Serialize};
11
12use crate::{
13    ResolvedVc, Vc,
14    trace::{TraceRawVcs, TraceRawVcsContext},
15    vc::into_future,
16};
17#[cfg(debug_assertions)]
18use crate::{
19    UpcastStrict,
20    debug::{ValueDebug, ValueDebugFormat, ValueDebugFormatString},
21};
22
23/// A thin wrapper on [`ResolvedVc`] that implements [`Ord`]. You must not depend on this to provide
24/// deterministic execution (i.e. to produce externally-visible outputs, like when performing
25/// chunking) as task ids are non-deterministic across cold executions.
26///
27/// This can be useful to provide a cache key. Given a single instance of `turbo-tasks`, this will
28/// give stable results.
29#[derive(Serialize, Deserialize, Encode, Decode)]
30#[serde(transparent, bound = "")]
31#[bincode(bounds = "T: ?Sized")]
32#[repr(transparent)]
33pub struct OrdResolvedVc<T>
34where
35    T: ?Sized,
36{
37    node: ResolvedVc<T>,
38}
39
40impl<T> OrdResolvedVc<T>
41where
42    T: ?Sized,
43{
44    /// Wraps a [`ResolvedVc`] so that it can be ordered. See the type-level documentation for the
45    /// caveats around determinism.
46    pub fn new(node: ResolvedVc<T>) -> Self {
47        Self { node }
48    }
49
50    /// Cheaply converts a [`Vec`] of ordered [`ResolvedVc`]s to a [`Vec`] of [`ResolvedVc`]s.
51    pub fn deref_vec(vec: Vec<OrdResolvedVc<T>>) -> Vec<ResolvedVc<T>> {
52        debug_assert!(size_of::<OrdResolvedVc<T>>() == size_of::<ResolvedVc<T>>());
53        let (ptr, len, capacity) = vec.into_raw_parts();
54        // Safety: The memory layout of `OrdResolvedVc<T>` and `ResolvedVc<T>` is
55        // the same.
56        unsafe { Vec::from_raw_parts(ptr as *mut ResolvedVc<T>, len, capacity) }
57    }
58
59    /// Cheaply converts a slice of [`OrdResolvedVc`]s to a slice of
60    /// [`ResolvedVc`]s.
61    pub fn deref_slice(s: &[OrdResolvedVc<T>]) -> &[ResolvedVc<T>] {
62        debug_assert!(size_of::<OrdResolvedVc<T>>() == size_of::<ResolvedVc<T>>());
63        // Safety: The memory layout of `OrdResolvedVc<T>` and `ResolvedVc<T>` is
64        // the same.
65        unsafe { slice::from_raw_parts(s.as_ptr() as *const ResolvedVc<T>, s.len()) }
66    }
67}
68
69impl<T> From<ResolvedVc<T>> for OrdResolvedVc<T>
70where
71    T: ?Sized,
72{
73    fn from(node: ResolvedVc<T>) -> Self {
74        Self::new(node)
75    }
76}
77
78impl<T> PartialEq<OrdResolvedVc<T>> for OrdResolvedVc<T>
79where
80    T: ?Sized,
81{
82    fn eq(&self, other: &Self) -> bool {
83        self.node == other.node
84    }
85}
86
87impl<T> Eq for OrdResolvedVc<T> where T: ?Sized {}
88
89impl<T> Hash for OrdResolvedVc<T>
90where
91    T: ?Sized,
92{
93    fn hash<H: Hasher>(&self, state: &mut H) {
94        self.node.hash(state);
95    }
96}
97
98impl<T> PartialOrd for OrdResolvedVc<T>
99where
100    T: ?Sized,
101{
102    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
103        Some(self.cmp(other))
104    }
105}
106impl<T> Ord for OrdResolvedVc<T>
107where
108    T: ?Sized,
109{
110    fn cmp(&self, other: &Self) -> Ordering {
111        Vc::into_raw(*self.node)
112            .bits()
113            .cmp(&Vc::into_raw(*other.node).bits())
114    }
115}
116
117impl<T> Copy for OrdResolvedVc<T> where T: ?Sized {}
118
119impl<T> Clone for OrdResolvedVc<T>
120where
121    T: ?Sized,
122{
123    fn clone(&self) -> Self {
124        *self
125    }
126}
127
128impl<T> Debug for OrdResolvedVc<T>
129where
130    T: ?Sized,
131{
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        f.debug_tuple("OrdResolvedVc")
134            .field(&self.node.node.node)
135            .finish()
136    }
137}
138
139impl<T> TraceRawVcs for OrdResolvedVc<T>
140where
141    T: ?Sized,
142{
143    fn trace_raw_vcs(&self, trace_context: &mut TraceRawVcsContext) {
144        TraceRawVcs::trace_raw_vcs(&self.node, trace_context);
145    }
146}
147
148#[cfg(debug_assertions)]
149impl<T> ValueDebugFormat for OrdResolvedVc<T>
150where
151    T: UpcastStrict<Box<dyn ValueDebug>> + Send + Sync + ?Sized,
152{
153    fn value_debug_format(&self, depth: usize) -> ValueDebugFormatString<'_> {
154        self.node.value_debug_format(depth)
155    }
156}
157
158impl<T> Deref for OrdResolvedVc<T>
159where
160    T: ?Sized,
161{
162    type Target = ResolvedVc<T>;
163
164    fn deref(&self) -> &Self::Target {
165        &self.node
166    }
167}
168
169into_future!(OrdResolvedVc<T>, |this| (*this).into_future());
170into_future!(&OrdResolvedVc<T>, |this| (*this).into_future());
171into_future!(&mut OrdResolvedVc<T>, |this| (*this).into_future());