late_struct/
std_ops.rs

1use std::{any::Any, hash};
2
3use crate::{LateInstance, LateStruct};
4
5mod sealed {
6    pub trait DynCloneSealed {}
7
8    pub trait DynEqSealed {}
9
10    pub trait DynPartialEqSealed {}
11
12    pub trait DynHashSealed {}
13}
14
15// === DynClone === //
16
17/// A bound for the [`LateStruct::EraseTo`] associated type which asserts that fields must have an
18/// implementation of [`Clone`]. If `LateStruct::EraseTo` implements this trait, the
19/// [`LateInstance`] instantiating that structure will implement `Clone`.
20///
21/// This trait is implemented for all types which implement `Clone`. Unlike `Clone`, however, it is
22/// [`dyn` compatible].
23///
24/// ## Safety
25///
26/// This trait is sealed and no downstream crates can implement it.
27///
28/// [`dyn` compatible]: https://doc.rust-lang.org/1.87.0/reference/items/traits.html#r-items.traits.dyn-compatible
29pub unsafe trait DynClone: sealed::DynCloneSealed {
30    #[doc(hidden)]
31    unsafe fn dyn_clone_into(&self, other: *mut u8);
32}
33
34impl<T: Clone> sealed::DynCloneSealed for T {}
35
36unsafe impl<T: Clone> DynClone for T {
37    unsafe fn dyn_clone_into(&self, other: *mut u8) {
38        unsafe { other.cast::<T>().write(self.clone()) };
39    }
40}
41
42impl<S: LateStruct> Clone for LateInstance<S>
43where
44    S::EraseTo: DynClone,
45{
46    fn clone(&self) -> Self {
47        unsafe {
48            Self::new_custom(|field, init| {
49                self.get_erased(field).dyn_clone_into(init);
50            })
51        }
52    }
53}
54
55// === DynEq === //
56
57/// A bound for the [`LateStruct::EraseTo`] associated type which asserts that fields must have an
58/// implementation of [`Eq`] against itself. If `LateStruct::EraseTo` implements this trait, the
59/// [`LateInstance`] instantiating that structure will implement `Eq`.
60///
61/// This trait is implemented for all types which implement `Eq<Self>`. Unlike `Eq<Self>`, however,
62/// it is [`dyn` compatible].
63///
64/// This trait is sealed and no downstream crates can implement it.
65///
66/// [`dyn` compatible]: https://doc.rust-lang.org/1.87.0/reference/items/traits.html#r-items.traits.dyn-compatible
67pub trait DynEq: DynPartialEq + sealed::DynEqSealed {}
68
69/// A bound for the [`LateStruct::EraseTo`] associated type which asserts that fields must have an
70/// implementation of [`PartialEq`] against itself. If `LateStruct::EraseTo` implements this trait,
71/// the [`LateInstance`] instantiating that structure will implement `PartialEq`.
72///
73/// This trait is implemented for all types which implement `PartialEq<Self>`. Unlike
74/// `PartialEq<Self>`, however, it is [`dyn` compatible].
75///
76/// This trait is sealed and no downstream crates can implement it.
77///
78/// [`dyn` compatible]: https://doc.rust-lang.org/1.87.0/reference/items/traits.html#r-items.traits.dyn-compatible
79pub trait DynPartialEq: Any + sealed::DynPartialEqSealed {
80    #[doc(hidden)]
81    fn dyn_eq(&self, other: &dyn Any) -> bool;
82
83    #[doc(hidden)]
84    fn as_any(&self) -> &dyn Any;
85}
86
87impl<T: 'static + Eq> sealed::DynEqSealed for T {}
88
89impl<T: 'static + Eq> DynEq for T {}
90
91impl<T: 'static + PartialEq> sealed::DynPartialEqSealed for T {}
92
93impl<T: 'static + PartialEq> DynPartialEq for T {
94    fn dyn_eq(&self, other: &dyn Any) -> bool {
95        other.downcast_ref::<T>().is_some_and(|rhs| self == rhs)
96    }
97
98    fn as_any(&self) -> &dyn Any {
99        self
100    }
101}
102
103impl<S: LateStruct> Eq for LateInstance<S> where S::EraseTo: DynEq {}
104
105impl<S: LateStruct> PartialEq for LateInstance<S>
106where
107    S::EraseTo: DynEq,
108{
109    fn eq(&self, other: &Self) -> bool {
110        self.fields().iter().all(|&field| {
111            self.get_erased(field)
112                .dyn_eq(other.get_erased(field).as_any())
113        })
114    }
115}
116
117// === DynHash === //
118
119/// A bound for the [`LateStruct::EraseTo`] associated type which asserts that fields must have an
120/// implementation of [`Hash`]. If `LateStruct::EraseTo` implements this trait, the [`LateInstance`]
121/// instantiating that structure will implement `Hash`.
122///
123/// This trait is implemented for all types which implement `Hash`. Unlike `Hash`, however,
124/// it is [`dyn` compatible].
125///
126/// This trait is sealed and no downstream crates can implement it.
127///
128/// [`dyn` compatible]: https://doc.rust-lang.org/1.87.0/reference/items/traits.html#r-items.traits.dyn-compatible
129pub trait DynHash: sealed::DynHashSealed {
130    #[doc(hidden)]
131    fn dyn_hash(&self, hasher: &mut dyn hash::Hasher);
132}
133
134impl<T: hash::Hash> sealed::DynHashSealed for T {}
135
136impl<T: hash::Hash> DynHash for T {
137    fn dyn_hash(&self, mut hasher: &mut dyn hash::Hasher) {
138        self.hash(&mut hasher);
139    }
140}
141
142impl<S: LateStruct> hash::Hash for LateInstance<S>
143where
144    S::EraseTo: DynHash,
145{
146    fn hash<H: hash::Hasher>(&self, state: &mut H) {
147        for field in self.fields() {
148            self.get_erased(field).dyn_hash(state);
149        }
150    }
151}