fn_store/
raw.rs

1/*
2 * Created on Thu Jul 06 2023
3 *
4 * Copyright (c) storycraft. Licensed under the MIT Licence.
5 */
6
7use core::{hash::BuildHasherDefault, marker::PhantomData, mem, mem::ManuallyDrop, ptr};
8
9use bumpalo::Bump;
10use hashbrown::HashMap;
11use rustc_hash::FxHasher;
12use type_key::TypeKey;
13
14#[derive(Debug)]
15/// A raw persistent value store
16pub struct RawStore<'a> {
17    map: HashMap<TypeKey, ManuallyDealloc, BuildHasherDefault<FxHasher>>,
18
19    bump: ManuallyDrop<Bump>,
20    _phantom: PhantomData<&'a ()>,
21}
22
23impl<'a> RawStore<'a> {
24    pub fn new() -> Self {
25        Self {
26            map: HashMap::default(),
27
28            bump: ManuallyDrop::new(Bump::new()),
29            _phantom: PhantomData,
30        }
31    }
32
33    pub fn get<T: 'a>(&self, key: &TypeKey) -> Option<*const T> {
34        Some(self.map.get(key)?.ptr().cast::<T>())
35    }
36
37    /// insert value
38    ///
39    /// Returned pointer is covariant to lifetime 'a where &'a mut self
40    pub fn insert<T: 'a>(&mut self, key: TypeKey, value: T) -> *const T {
41        // SAFETY: Exclusively borrowed reference, original value is forgotten by Bump allocator and does not outlive
42        let value =
43            unsafe { ManuallyDealloc(mem::transmute(self.bump.alloc(value) as &mut dyn Erased)) };
44        let ptr = value.ptr();
45
46        self.map.insert(key, value);
47
48        ptr.cast::<T>()
49    }
50
51    pub fn reset(&mut self) {
52        self.map.clear();
53        self.bump.reset();
54    }
55}
56
57impl Default for RawStore<'_> {
58    fn default() -> Self {
59        Self::new()
60    }
61}
62
63impl Drop for RawStore<'_> {
64    fn drop(&mut self) {
65        self.map.clear();
66
67        // SAFETY: Manually dropped to ensure allocated objects to drop first
68        unsafe { ManuallyDrop::drop(&mut self.bump) }
69    }
70}
71
72trait Erased {}
73impl<T> Erased for T {}
74
75#[derive(Debug)]
76#[repr(transparent)]
77/// Manually deallocated pointer.
78/// It's intended to be used with bump allocator.
79///
80/// # Safety
81/// Dereferencing the pointer is only safe when the pointer did not outlive its value
82struct ManuallyDealloc(*mut dyn Erased);
83
84impl ManuallyDealloc {
85    pub const fn ptr(&self) -> *const dyn Erased {
86        self.0.cast_const()
87    }
88}
89
90impl Drop for ManuallyDealloc {
91    fn drop(&mut self) {
92        // SAFETY: Safe to drop since it is the only unique pointer
93        unsafe { ptr::drop_in_place(self.0) }
94    }
95}