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}