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}