compact/
compact.rs

1use std::mem;
2
3/// A trait for objects with a statically-sized part and a potential dynamically-sized part
4/// that can be stored both compactly in consecutive memory or freely on the heap
5pub trait Compact: Sized + Clone {
6    // TODO: add a move_compact function to handle moving within a parent container
7    // (so relative to own dynamic part) more efficiently than decompacting
8
9    /// Is the object's dynamic part stored compactly?
10    fn is_still_compact(&self) -> bool;
11
12    /// Size of the dynamic part in bytes
13    fn dynamic_size_bytes(&self) -> usize;
14
15    /// Total size of the object (static part + dynamic part)
16    fn total_size_bytes(&self) -> usize {
17        self.dynamic_size_bytes() + mem::size_of::<Self>()
18    }
19
20    /// Copy the static part of `source` to `dest` and compactly store
21    /// the dynamic part of `source` as the new dynamic part of `dest` at `new_dynamic_part`.
22    /// This semantically moves source into dest.
23    unsafe fn compact(source: *mut Self, dest: *mut Self, new_dynamic_part: *mut u8);
24
25    /// Get a pointer to behind the static part of `self` (commonly used place for the dynamic part)
26    unsafe fn behind(ptr: *mut Self) -> *mut u8 {
27        ptr.offset(1) as *mut u8
28    }
29
30    /// Like `compact` with `new_dynamic_part` set to `dest.behind()`
31    unsafe fn compact_behind(source: *mut Self, dest: *mut Self) {
32        let behind_dest = Self::behind(dest);
33        Self::compact(source, dest, behind_dest)
34    }
35
36    /// Creates a clone of self with the dynamic part guaranteed to be stored freely.
37    ///
38    /// *Note:* if the dynamic part was already stored freely, the calling environment
39    /// has to make sure that old self will not be dropped, as this might lead to a double free!
40    ///
41    /// This is mostly used internally to correctly implement
42    /// `Compact` datastructures that contain `Compact` elements.
43    unsafe fn decompact(source: *const Self) -> Self;
44}
45
46/// Trivial implementation for fixed-sized, `Copy` types (no dynamic part)
47impl<T: Copy> Compact for T {
48    default fn is_still_compact(&self) -> bool {
49        true
50    }
51    default fn dynamic_size_bytes(&self) -> usize {
52        0
53    }
54    default unsafe fn compact(source: *mut Self, dest: *mut Self, _new_dynamic_part: *mut u8) {
55        *dest = *source
56    }
57
58    default unsafe fn decompact(source: *const Self) -> Self {
59        *source
60    }
61}