evering_ipc/shm/
boxed.rs

1#![allow(dead_code)]
2
3use std::cell::Cell;
4use std::fmt;
5use std::mem::MaybeUninit;
6use std::ptr::NonNull;
7
8use super::{Allocator, ShmHeader, ShmToken};
9
10pub struct ShmBox<T: ?Sized>(NonNull<T>);
11
12impl<T: ?Sized> ShmBox<T> {
13    pub fn as_shm(this: &Self) -> ShmToken<T> {
14        ShmHandle::get().get_shm(this.0)
15    }
16
17    pub fn into_raw(self) -> NonNull<T> {
18        let ptr = self.0;
19        std::mem::forget(self);
20        ptr
21    }
22
23    /// # Safety
24    ///
25    /// The given `ptr` must be a valid pointer managed by [`Allocator`].
26    pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
27        ShmBox(ptr)
28    }
29}
30
31impl<T> ShmBox<T> {
32    pub fn new(val: T) -> Self {
33        unsafe { Self::from_raw(AloHandle::get().alloc(val)) }
34    }
35
36    pub fn into_uninit(self) -> ShmBox<MaybeUninit<T>> {
37        unsafe { ShmBox::from_raw(self.into_raw().cast()) }
38    }
39}
40
41impl<T> ShmBox<MaybeUninit<T>> {
42    pub fn new_uninit() -> Self {
43        unsafe { Self::from_raw(AloHandle::get().alloc_uninit()) }
44    }
45
46    /// # Safety
47    ///
48    /// The underlying value must be initialized properly. See
49    /// [`MaybeUninit::assume_init`] for more information.
50    pub unsafe fn assume_init(self) -> ShmBox<T> {
51        unsafe { ShmBox::from_raw(self.into_raw().cast()) }
52    }
53}
54
55impl<T> ShmBox<[T]> {
56    pub fn new_slice_copied(src: &[T]) -> Self
57    where
58        T: Copy,
59    {
60        unsafe { Self::from_raw(AloHandle::get().alloc_slice_copied(src)) }
61    }
62
63    pub fn new_slice_filled(val: T, n: usize) -> Self
64    where
65        T: Copy,
66    {
67        unsafe { Self::from_raw(AloHandle::get().alloc_slice_filled(val, n)) }
68    }
69
70    pub fn into_uninit(self) -> ShmBox<[MaybeUninit<T>]> {
71        unsafe {
72            let ptr = self.into_raw().as_ptr();
73            ShmBox::from_raw(NonNull::new_unchecked(ptr as *mut [MaybeUninit<T>]))
74        }
75    }
76}
77
78impl<T> ShmBox<[MaybeUninit<T>]> {
79    pub fn new_slice_uninit(n: usize) -> Self {
80        unsafe { Self::from_raw(AloHandle::get().alloc_slice_uninit(n)) }
81    }
82
83    /// # Safety
84    ///
85    /// Each element in the underlying slice must be initialized properly. See
86    /// [`MaybeUninit::assume_init`] for more information.
87    pub unsafe fn assume_init(self) -> ShmBox<[T]> {
88        unsafe {
89            let ptr = self.into_raw().as_ptr();
90            ShmBox::from_raw(NonNull::new_unchecked(ptr as *mut [T]))
91        }
92    }
93}
94
95impl<T: ?Sized> Drop for ShmBox<T> {
96    fn drop(&mut self) {
97        unsafe {
98            let ptr = self.0;
99            ptr.drop_in_place();
100            AloHandle::get().dealloc(ptr);
101        }
102    }
103}
104
105impl<T: ?Sized + fmt::Debug> fmt::Debug for ShmBox<T> {
106    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107        T::fmt(self, f)
108    }
109}
110
111impl<T: ?Sized> std::ops::Deref for ShmBox<T> {
112    type Target = T;
113    fn deref(&self) -> &Self::Target {
114        unsafe { self.0.as_ref() }
115    }
116}
117
118impl<T: ?Sized> std::ops::DerefMut for ShmBox<T> {
119    fn deref_mut(&mut self) -> &mut Self::Target {
120        unsafe { self.0.as_mut() }
121    }
122}
123
124thread_local! {
125    static SHM: Cell<Option<&'static ShmHeader>> = const { Cell::new(None) };
126    static ALO: Cell<Option<&'static Allocator>> = const { Cell::new(None) };
127}
128
129pub struct ShmHandle;
130
131impl ShmHandle {
132    pub fn init(shm: &'static ShmHeader) {
133        if SHM.get().is_some() {
134            panic!("shm has been initialized");
135        }
136        SHM.set(Some(shm))
137    }
138
139    pub fn get() -> &'static ShmHeader {
140        SHM.get().expect("shm is not initialized")
141    }
142}
143
144pub struct AloHandle;
145
146impl AloHandle {
147    pub fn init(shm: &'static ShmHeader) {
148        if ALO.get().is_some() {
149            panic!("allocator has been initialized");
150        }
151        ALO.set(Some(shm.get_allocator()))
152    }
153
154    pub fn get() -> &'static Allocator {
155        ALO.get().expect("allocator is not initialized")
156    }
157}
158
159pub fn init_client(shm: &'static ShmHeader) {
160    ShmHandle::init(shm);
161    AloHandle::init(shm);
162}
163
164pub fn init_server(shm: &'static ShmHeader) {
165    ShmHandle::init(shm);
166}