turbo_tasks/task/
shared_reference.rs

1use std::{
2    any::Any,
3    fmt::{Debug, Display},
4    hash::Hash,
5    ops::Deref,
6};
7
8use anyhow::Result;
9use bincode::{
10    Decode, Encode,
11    error::{DecodeError, EncodeError},
12    impl_borrow_decode,
13};
14use turbo_bincode::{
15    TurboBincodeDecode, TurboBincodeDecoder, TurboBincodeEncode, TurboBincodeEncoder,
16    impl_decode_for_turbo_bincode_decode, impl_encode_for_turbo_bincode_encode,
17};
18use unsize::CoerceUnsize;
19
20use crate::{
21    ValueType, ValueTypeId, registry,
22    triomphe_utils::{coerce_to_any_send_sync, downcast_triomphe_arc},
23};
24
25/// A reference to a piece of data
26#[derive(Clone)]
27pub struct SharedReference(pub triomphe::Arc<dyn Any + Send + Sync>);
28
29impl SharedReference {
30    pub fn new(data: triomphe::Arc<impl Any + Send + Sync>) -> Self {
31        Self(data.unsize(coerce_to_any_send_sync()))
32    }
33}
34
35/// A reference to a piece of data with type information
36#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
37pub struct TypedSharedReference {
38    pub type_id: ValueTypeId,
39    pub reference: SharedReference,
40}
41
42impl SharedReference {
43    pub fn downcast<T: Any + Send + Sync>(self) -> Result<triomphe::Arc<T>, Self> {
44        match downcast_triomphe_arc(self.0) {
45            Ok(data) => Ok(data),
46            Err(data) => Err(Self(data)),
47        }
48    }
49
50    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
51        self.0.downcast_ref()
52    }
53
54    pub fn into_typed(self, type_id: ValueTypeId) -> TypedSharedReference {
55        TypedSharedReference {
56            type_id,
57            reference: self,
58        }
59    }
60}
61
62impl TypedSharedReference {
63    pub fn into_untyped(self) -> SharedReference {
64        self.reference
65    }
66}
67
68impl TurboBincodeEncode for TypedSharedReference {
69    fn encode(&self, encoder: &mut TurboBincodeEncoder) -> Result<(), EncodeError> {
70        let Self { type_id, reference } = self;
71        let value_type = registry::get_value_type(*type_id);
72        if let Some(bincode) = value_type.bincode {
73            type_id.encode(encoder)?;
74            bincode.0(&*reference.0, encoder)?;
75            Ok(())
76        } else {
77            Err(EncodeError::OtherString(format!(
78                "{} is not encodable",
79                value_type.global_name
80            )))
81        }
82    }
83}
84
85impl<Context> TurboBincodeDecode<Context> for TypedSharedReference {
86    fn decode(decoder: &mut TurboBincodeDecoder) -> Result<Self, DecodeError> {
87        let type_id = ValueTypeId::decode(decoder)?;
88        let value_type = registry::get_value_type(type_id);
89        if let Some(bincode) = value_type.bincode {
90            let reference = bincode.1(decoder)?;
91            Ok(Self { type_id, reference })
92        } else {
93            #[cold]
94            fn not_decodable(value_type: &ValueType) -> DecodeError {
95                DecodeError::OtherString(format!("{} is not decodable", value_type.global_name))
96            }
97            Err(not_decodable(value_type))
98        }
99    }
100}
101
102impl_encode_for_turbo_bincode_encode!(TypedSharedReference);
103impl_decode_for_turbo_bincode_decode!(TypedSharedReference);
104impl_borrow_decode!(TypedSharedReference);
105
106impl Deref for TypedSharedReference {
107    type Target = SharedReference;
108
109    fn deref(&self) -> &Self::Target {
110        &self.reference
111    }
112}
113
114impl Hash for SharedReference {
115    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
116        Hash::hash(&(&*self.0 as *const (dyn Any + Send + Sync)), state)
117    }
118}
119impl PartialEq for SharedReference {
120    // Must compare with PartialEq rather than std::ptr::addr_eq since the latter
121    // only compares their addresses.
122    #[allow(ambiguous_wide_pointer_comparisons)]
123    fn eq(&self, other: &Self) -> bool {
124        triomphe::Arc::ptr_eq(&self.0, &other.0)
125    }
126}
127impl Eq for SharedReference {}
128impl PartialOrd for SharedReference {
129    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
130        Some(self.cmp(other))
131    }
132}
133impl Ord for SharedReference {
134    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
135        Ord::cmp(
136            &(&*self.0 as *const (dyn Any + Send + Sync)).cast::<()>(),
137            &(&*other.0 as *const (dyn Any + Send + Sync)).cast::<()>(),
138        )
139    }
140}
141impl Debug for SharedReference {
142    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143        f.debug_tuple("SharedReference").field(&self.0).finish()
144    }
145}
146
147impl Display for SharedReference {
148    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149        write!(f, "untyped value")
150    }
151}
152
153impl Display for TypedSharedReference {
154    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
155        write!(
156            f,
157            "value of type {}",
158            registry::get_value_type(self.type_id).name
159        )
160    }
161}