1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
use std::mem;

/// A trait for objects with a statically-sized part and a potential dynamically-sized part
/// that can be stored both compactly in consecutive memory or freely on the heap
pub trait Compact: Sized + Clone {
    /// Is the object's dynamic part stored compactly?
    fn is_still_compact(&self) -> bool;

    /// Size of the dynamic part in bytes
    fn dynamic_size_bytes(&self) -> usize;

    /// Total size of the object (static part + dynamic part)
    fn total_size_bytes(&self) -> usize {
        self.dynamic_size_bytes() + mem::size_of::<Self>()
    }

    /// Copy the static part of `source` to `dest` and compactly store
    /// the dynamic part of `source` as the new dynamic part of `dest` at `new_dynamic_part`.
    /// This semantically moves source into dest.
    unsafe fn compact(source: *mut Self, dest: *mut Self, new_dynamic_part: *mut u8);

    /// Get a pointer to behind the static part of `self` (commonly used place for the dynamic part)
    unsafe fn behind(ptr: *mut Self) -> *mut u8 {
        ptr.offset(1) as *mut u8
    }

    /// Like `compact` with `new_dynamic_part` set to `dest.behind()`
    unsafe fn compact_behind(source: *mut Self, dest: *mut Self) {
        let behind_dest = Self::behind(dest);
        Self::compact(source, dest, behind_dest)
    }

    /// Creates a clone of self with the dynamic part guaranteed to be stored freely.
    ///
    /// *Note:* if the dynamic part was already stored freely, the calling environment
    /// has to make sure that old self will not be dropped, as this might lead to a double free!
    ///
    /// This is mostly used internally to correctly implement
    /// `Compact` datastructures that contain `Compact` elements.
    unsafe fn decompact(source: *const Self) -> Self;
}

/// Trivial implementation for fixed-sized, `Copy` types (no dynamic part)
impl<T: Copy> Compact for T {
    default fn is_still_compact(&self) -> bool {
        true
    }
    default fn dynamic_size_bytes(&self) -> usize {
        0
    }
    default unsafe fn compact(source: *mut Self, dest: *mut Self, _new_dynamic_part: *mut u8) {
        *dest = *source
    }

    default unsafe fn decompact(source: *const Self) -> Self {
        *source
    }
}