dync/
traits.rs

1//! This module defines the function pointers for supported traits from the standard library.
2//!
3//! `CloneFromFn` and `DropFn` enable the use of `VecClone`.
4//!
5//! The remaining traits improve compatibility with the rest of the standard library.
6
7use crate::bytes::*;
8use crate::vtable::VTable;
9use dync_derive::dync_trait_method;
10use std::fmt;
11use std::hash::{Hash, Hasher};
12use std::mem::{ManuallyDrop, MaybeUninit};
13
14pub trait DropBytes {
15    #[doc(hidden)]
16    unsafe fn drop_bytes(bytes: &mut [MaybeUninit<u8>]);
17}
18
19pub trait CloneBytes: Clone {
20    #[dync_trait_method]
21    fn clone(&self) -> Self;
22    //unsafe fn clone_bytes(src: &[MaybeUninit<u8>]) -> Box<[MaybeUninit<u8>]>;
23    #[dync_trait_method]
24    fn clone_from(&mut self, src: &Self);
25    //unsafe fn clone_from_bytes(dst: &mut [MaybeUninit<u8>], src: &[MaybeUninit<u8>]);
26
27    #[doc(hidden)]
28    unsafe fn clone_into_raw_bytes(src: &[MaybeUninit<u8>], dst: &mut [MaybeUninit<u8>]);
29}
30
31pub trait PartialEqBytes: PartialEq {
32    #[dync_trait_method]
33    fn eq(&self, other: &Self) -> bool;
34    //unsafe fn eq_bytes(a: &[MaybeUninit<u8>], b: &[MaybeUninit<u8>]) -> bool;
35}
36
37pub trait HashBytes: Hash {
38    #[dync_trait_method]
39    fn hash<H: Hasher>(&self, state: &mut H);
40    //unsafe fn hash_bytes(bytes: &[MaybeUninit<u8>], state: &mut dyn Hasher);
41}
42
43pub trait DebugBytes: fmt::Debug {
44    #[dync_trait_method]
45    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>;
46    //unsafe fn fmt_bytes(bytes: &[MaybeUninit<u8>], f: &mut fmt::Formatter) -> Result<(), fmt::Error>;
47}
48
49impl<T: 'static> DropBytes for T {
50    #[inline]
51    unsafe fn drop_bytes(bytes: &mut [MaybeUninit<u8>]) {
52        let md: &mut ManuallyDrop<T> = Bytes::from_bytes_mut(bytes);
53        ManuallyDrop::drop(md);
54    }
55}
56
57impl<T: Clone + 'static> CloneBytes for T {
58    #[inline]
59    unsafe fn clone_bytes(src: &[MaybeUninit<u8>]) -> Box<[MaybeUninit<u8>]> {
60        let typed_src: &T = Bytes::from_bytes(src);
61        Bytes::box_into_box_bytes(Box::new(typed_src.clone()))
62    }
63    #[inline]
64    unsafe fn clone_from_bytes(dst: &mut [MaybeUninit<u8>], src: &[MaybeUninit<u8>]) {
65        let typed_src: &T = Bytes::from_bytes(src);
66        let typed_dst: &mut T = Bytes::from_bytes_mut(dst);
67        typed_dst.clone_from(typed_src);
68    }
69    #[inline]
70    unsafe fn clone_into_raw_bytes(src: &[MaybeUninit<u8>], dst: &mut [MaybeUninit<u8>]) {
71        let typed_src: &T = Bytes::from_bytes(src);
72        let cloned = T::clone(typed_src);
73        let cloned_bytes = Bytes::as_bytes(&cloned);
74        dst.copy_from_slice(cloned_bytes);
75        let _ = ManuallyDrop::new(cloned);
76    }
77}
78
79impl<T: PartialEq + 'static> PartialEqBytes for T {
80    #[inline]
81    unsafe fn eq_bytes(a: &[MaybeUninit<u8>], b: &[MaybeUninit<u8>]) -> bool {
82        let (a, b): (&T, &T) = (Bytes::from_bytes(a), Bytes::from_bytes(b));
83        a.eq(b)
84    }
85}
86
87impl<T: Hash + 'static> HashBytes for T {
88    #[inline]
89    unsafe fn hash_bytes(bytes: &[MaybeUninit<u8>], mut state: &mut dyn Hasher) {
90        let typed_data: &T = Bytes::from_bytes(bytes);
91        typed_data.hash(&mut state)
92    }
93}
94
95impl<T: fmt::Debug + 'static> DebugBytes for T {
96    #[inline]
97    unsafe fn fmt_bytes(
98        bytes: &[MaybeUninit<u8>],
99        f: &mut fmt::Formatter,
100    ) -> Result<(), fmt::Error> {
101        let typed_data: &T = Bytes::from_bytes(bytes);
102        typed_data.fmt(f)
103    }
104}
105
106pub type CloneFn = unsafe fn(&[MaybeUninit<u8>]) -> Box<[MaybeUninit<u8>]>;
107pub type CloneFromFn = unsafe fn(&mut [MaybeUninit<u8>], &[MaybeUninit<u8>]);
108pub type CloneIntoRawFn = unsafe fn(&[MaybeUninit<u8>], &mut [MaybeUninit<u8>]);
109pub type EqFn = unsafe fn(&[MaybeUninit<u8>], &[MaybeUninit<u8>]) -> bool;
110pub type HashFn = unsafe fn(&[MaybeUninit<u8>], &mut dyn Hasher);
111pub type FmtFn = unsafe fn(&[MaybeUninit<u8>], &mut fmt::Formatter) -> Result<(), fmt::Error>;
112pub type DropFn = unsafe fn(&mut [MaybeUninit<u8>]);
113
114use downcast_rs::{impl_downcast, Downcast};
115
116pub trait HasDrop: Downcast {
117    fn drop_fn(&self) -> &DropFn;
118}
119
120impl_downcast!(HasDrop);
121
122pub trait HasClone {
123    fn clone_fn(&self) -> &CloneFn;
124    fn clone_from_fn(&self) -> &CloneFromFn;
125    fn clone_into_raw_fn(&self) -> &CloneIntoRawFn;
126}
127
128pub trait HasHash {
129    fn hash_fn(&self) -> &HashFn;
130}
131
132pub trait HasPartialEq {
133    fn eq_fn(&self) -> &EqFn;
134}
135
136pub trait HasEq: HasPartialEq {}
137
138pub trait HasDebug {
139    fn fmt_fn(&self) -> &FmtFn;
140}
141
142/// # Safety
143///
144/// Implementing containers must contain types that implement `Send`.
145pub unsafe trait HasSend {}
146
147/// # Safety
148///
149/// Implementing containers must contain types that implement `Sync`.
150pub unsafe trait HasSync {}
151
152#[derive(Clone)]
153pub struct DropVTable(pub DropFn);
154#[derive(Clone)]
155pub struct CloneVTable(pub DropFn, pub CloneFn, pub CloneFromFn, pub CloneIntoRawFn);
156#[derive(Clone)]
157pub struct PartialEqVTable(pub DropFn, pub EqFn);
158#[derive(Clone)]
159pub struct EqVTable(pub DropFn, pub EqFn);
160#[derive(Clone)]
161pub struct HashVTable(pub DropFn, pub HashFn);
162#[derive(Clone)]
163pub struct DebugVTable(pub DropFn, pub FmtFn);
164#[derive(Clone)]
165pub struct SendVTable(pub DropFn);
166#[derive(Clone)]
167pub struct SyncVTable(pub DropFn);
168
169// VTable implementations are needed for builtin types to work with builtin vtables
170impl<T: DropBytes> VTable<T> for DropVTable {
171    fn build_vtable() -> Self {
172        DropVTable(T::drop_bytes)
173    }
174}
175
176impl<T: DropBytes + CloneBytes> VTable<T> for CloneVTable {
177    fn build_vtable() -> Self {
178        CloneVTable(
179            T::drop_bytes,
180            T::clone_bytes,
181            T::clone_from_bytes,
182            T::clone_into_raw_bytes,
183        )
184    }
185}
186
187impl<T: DropBytes + PartialEqBytes> VTable<T> for PartialEqVTable {
188    fn build_vtable() -> Self {
189        PartialEqVTable(T::drop_bytes, T::eq_bytes)
190    }
191}
192
193impl<T: DropBytes + PartialEqBytes> VTable<T> for EqVTable {
194    fn build_vtable() -> Self {
195        EqVTable(T::drop_bytes, T::eq_bytes)
196    }
197}
198
199impl<T: DropBytes + HashBytes> VTable<T> for HashVTable {
200    fn build_vtable() -> Self {
201        HashVTable(T::drop_bytes, T::hash_bytes)
202    }
203}
204
205impl<T: DropBytes> VTable<T> for SendVTable {
206    fn build_vtable() -> Self {
207        SendVTable(T::drop_bytes)
208    }
209}
210
211impl<T: DropBytes> VTable<T> for SyncVTable {
212    fn build_vtable() -> Self {
213        SyncVTable(T::drop_bytes)
214    }
215}
216
217impl<T: DropBytes + DebugBytes> VTable<T> for DebugVTable {
218    fn build_vtable() -> Self {
219        DebugVTable(T::drop_bytes, T::fmt_bytes)
220    }
221}
222
223macro_rules! impl_has_drop {
224    ($($trait:ident),*) => {
225        $(
226            impl HasDrop for $trait {
227                fn drop_fn(&self) -> &DropFn {
228                    &self.0
229                }
230            }
231        )*
232    }
233}
234
235impl_has_drop!(
236    DropVTable,
237    CloneVTable,
238    PartialEqVTable,
239    EqVTable,
240    HashVTable,
241    DebugVTable,
242    SendVTable,
243    SyncVTable
244);
245
246impl HasClone for CloneVTable {
247    fn clone_fn(&self) -> &CloneFn {
248        &self.1
249    }
250    fn clone_from_fn(&self) -> &CloneFromFn {
251        &self.2
252    }
253    fn clone_into_raw_fn(&self) -> &CloneIntoRawFn {
254        &self.3
255    }
256}
257
258impl HasHash for HashVTable {
259    fn hash_fn(&self) -> &HashFn {
260        &self.1
261    }
262}
263
264impl HasPartialEq for PartialEqVTable {
265    fn eq_fn(&self) -> &EqFn {
266        &self.1
267    }
268}
269
270impl HasPartialEq for EqVTable {
271    fn eq_fn(&self) -> &EqFn {
272        &self.1
273    }
274}
275
276impl HasEq for EqVTable {}
277
278impl HasDebug for DebugVTable {
279    fn fmt_fn(&self) -> &FmtFn {
280        &self.1
281    }
282}
283
284#[cfg(test)]
285mod tests {
286    use super::*;
287    use crate::vec_dyn::VecDyn;
288
289    #[test]
290    fn drop() {
291        // Empty vec dropped
292        let vd = VecDyn::<DropVTable>::with_type::<u32>();
293        let v = vd.into_vec::<u32>().unwrap();
294        assert_eq!(v, Vec::new());
295
296        // Non-empty vec dropped
297        let vd = VecDyn::<DropVTable>::from(vec![1u32, 2]);
298        let v = vd.into_vec::<u32>().unwrap();
299        assert_eq!(v, vec![1u32, 2]);
300    }
301
302    #[test]
303    fn clone() {
304        let v = VecDyn::<CloneVTable>::from(vec![1u32, 2]);
305        let v_clone = v.clone();
306        assert_eq!(
307            v.into_vec::<u32>().unwrap(),
308            v_clone.into_vec::<u32>().unwrap()
309        );
310    }
311
312    #[test]
313    fn partial_eq() {
314        let a = VecDyn::<PartialEqVTable>::from(vec![1, 2]);
315        let b = VecDyn::<PartialEqVTable>::from(vec![1, 2]);
316        assert!(a == b);
317
318        let a = VecDyn::<EqVTable>::from(vec![1, 2]);
319        let b = VecDyn::<EqVTable>::from(vec![1, 2]);
320        assert!(a == b);
321    }
322
323    #[test]
324    fn hash() {
325        use std::collections::hash_map::DefaultHasher;
326        let a = VecDyn::<HashVTable>::from(vec![1, 2]);
327        let b = VecDyn::<HashVTable>::from(vec![1, 2]);
328
329        let mut s = DefaultHasher::new();
330        a.hash(&mut s);
331        let a_hash = s.finish();
332
333        let mut s = DefaultHasher::new();
334        b.hash(&mut s);
335        let b_hash = s.finish();
336        assert_eq!(a_hash, b_hash);
337    }
338
339    #[test]
340    fn debug() {
341        let a = VecDyn::<DebugVTable>::from(vec![1, 2]);
342        eprintln!("{:?}", a);
343    }
344}