1use std::{fmt::Debug, marker::PhantomData};
2
3use crate::{
4 Vc, VcValueTrait, registry::get_value_type, task::shared_reference::TypedSharedReference,
5 vc::UpcastStrict,
6};
7
8pub struct TraitRef<T>
16where
17 T: ?Sized,
18{
19 shared_reference: TypedSharedReference,
20 _t: PhantomData<T>,
21}
22
23impl<T> Debug for TraitRef<T> {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 f.debug_struct("TraitRef")
26 .field("shared_reference", &self.shared_reference)
27 .finish()
28 }
29}
30
31impl<T> Clone for TraitRef<T> {
32 fn clone(&self) -> Self {
33 Self {
34 shared_reference: self.shared_reference.clone(),
35 _t: PhantomData,
36 }
37 }
38}
39
40impl<T> PartialEq for TraitRef<T> {
41 fn eq(&self, other: &Self) -> bool {
42 self.shared_reference == other.shared_reference
43 }
44}
45
46impl<T> Eq for TraitRef<T> {}
47
48impl<T> std::hash::Hash for TraitRef<T> {
49 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
50 self.shared_reference.hash(state)
51 }
52}
53
54impl<U> std::ops::Deref for TraitRef<Box<U>>
55where
56 Box<U>: VcValueTrait<ValueTrait = U>,
57 U: std::ptr::Pointee<Metadata = std::ptr::DynMetadata<U>> + ?Sized,
58{
59 type Target = U;
60
61 fn deref(&self) -> &Self::Target {
62 let downcast_ptr = <Box<U> as VcValueTrait>::IMPL_VTABLES.cast(
65 self.shared_reference.type_id,
66 self.shared_reference.reference.0.as_ptr() as *const (),
67 );
68 unsafe { &*downcast_ptr }
70 }
71}
72
73unsafe impl<T> Sync for TraitRef<T> where T: ?Sized {}
76
77unsafe impl<T> Send for TraitRef<T> where T: ?Sized {}
80
81impl<T> Unpin for TraitRef<T> where T: ?Sized {}
82
83impl<T> TraitRef<T>
84where
85 T: ?Sized,
86{
87 pub(crate) fn new(shared_reference: TypedSharedReference) -> Self {
88 Self {
89 shared_reference,
90 _t: PhantomData,
91 }
92 }
93
94 pub fn ptr_eq(this: &Self, other: &Self) -> bool {
95 triomphe::Arc::ptr_eq(
96 &this.shared_reference.reference.0,
97 &other.shared_reference.reference.0,
98 )
99 }
100}
101
102impl<T> TraitRef<T>
103where
104 T: VcValueTrait + ?Sized,
105{
106 pub fn cell(trait_ref: TraitRef<T>) -> Vc<T> {
109 let TraitRef {
110 shared_reference, ..
111 } = trait_ref;
112 let value_type = get_value_type(shared_reference.type_id);
113 (value_type.raw_cell)(shared_reference).into()
114 }
115
116 pub fn try_downcast<K>(this: TraitRef<T>) -> Option<TraitRef<K>>
122 where
123 K: UpcastStrict<T> + VcValueTrait + ?Sized,
124 {
125 get_value_type(this.shared_reference.type_id)
126 .has_trait(&<K as VcValueTrait>::get_trait_type_id())
127 .then(|| TraitRef::new(this.shared_reference))
128 }
129}