department/statics/
multi.rs1use core::alloc::Layout;
2#[cfg(feature = "unsize")]
3use core::marker::Unsize;
4use core::mem;
5use core::ptr::{NonNull, Pointee};
6
7use super::StorageCell;
8use crate::base::{ExactSizeStorage, MultiItemStorage, Storage, StorageSafe};
9use crate::error::{Result, StorageError};
10use crate::handles::{Handle, OffsetMetaHandle};
11use crate::statics::traits::StaticStorage;
12use crate::utils;
13
14pub struct MultiStatic<S: 'static, const N: usize> {
16 used: [bool; N],
17 storage: &'static StorageCell<[S; N]>,
18}
19
20impl<S: 'static, const N: usize> StaticStorage<[S; N]> for MultiStatic<S, N> {
21 fn take_cell(storage: &'static StorageCell<[S; N]>) -> MultiStatic<S, N> {
22 MultiStatic {
23 used: [false; N],
24 storage,
25 }
26 }
27}
28
29unsafe impl<S, const N: usize> Storage for MultiStatic<S, N>
31where
32 S: StorageSafe,
33{
34 type Handle<T: ?Sized> = OffsetMetaHandle<T>;
35
36 unsafe fn get<T: ?Sized>(&self, handle: Self::Handle<T>) -> NonNull<T> {
37 let store_ptr = unsafe { self.storage.as_ptr() };
39 let idx = unsafe { core::ptr::addr_of_mut!((*store_ptr.as_ptr())[handle.offset()]) };
41 let ptr: NonNull<()> = NonNull::new(idx).unwrap().cast();
42 NonNull::from_raw_parts(ptr, handle.metadata())
43 }
44
45 fn from_raw_parts<T: ?Sized + Pointee>(
46 handle: Self::Handle<()>,
47 meta: T::Metadata,
48 ) -> Self::Handle<T> {
49 <Self::Handle<T>>::from_raw_parts(handle, meta)
50 }
51
52 fn cast<T: ?Sized + Pointee, U>(handle: Self::Handle<T>) -> Self::Handle<U> {
53 handle.cast()
54 }
55
56 fn cast_unsized<T: ?Sized + Pointee, U: ?Sized + Pointee<Metadata = T::Metadata>>(
57 handle: Self::Handle<T>,
58 ) -> Self::Handle<U> {
59 handle.cast_unsized()
60 }
61
62 #[cfg(feature = "unsize")]
63 fn coerce<T: ?Sized + Pointee + Unsize<U>, U: ?Sized + Pointee>(
64 handle: Self::Handle<T>,
65 ) -> Self::Handle<U> {
66 handle.coerce()
67 }
68
69 fn allocate_single<T: ?Sized + Pointee>(
70 &mut self,
71 meta: T::Metadata,
72 ) -> Result<Self::Handle<T>> {
73 self.allocate(meta)
74 }
75
76 unsafe fn deallocate_single<T: ?Sized>(&mut self, handle: Self::Handle<T>) {
77 unsafe { self.deallocate(handle) }
79 }
80
81 unsafe fn try_grow<T>(
82 &mut self,
83 handle: Self::Handle<[T]>,
84 capacity: usize,
85 ) -> Result<Self::Handle<[T]>> {
86 debug_assert!(capacity >= handle.metadata());
87 let new_layout = Layout::array::<T>(capacity).map_err(|_| StorageError::exceeds_max())?;
88
89 if self.will_fit::<[T]>(capacity) {
90 Ok(OffsetMetaHandle::from_offset_meta(
91 handle.offset(),
92 capacity,
93 ))
94 } else {
95 Err(StorageError::InsufficientSpace {
96 expected: new_layout.size(),
97 available: Some(self.max_range::<T>()),
98 })
99 }
100 }
101
102 unsafe fn try_shrink<T>(
103 &mut self,
104 handle: Self::Handle<[T]>,
105 capacity: usize,
106 ) -> Result<Self::Handle<[T]>> {
107 debug_assert!(capacity <= handle.metadata());
108 Ok(OffsetMetaHandle::from_offset_meta(
109 handle.offset(),
110 capacity,
111 ))
112 }
113}
114
115unsafe impl<S, const N: usize> MultiItemStorage for MultiStatic<S, N>
117where
118 S: StorageSafe,
119{
120 fn allocate<T: ?Sized + Pointee>(&mut self, meta: T::Metadata) -> Result<Self::Handle<T>> {
121 utils::validate_layout::<T, S>(meta)?;
122
123 let pos = self
124 .used
125 .iter()
126 .position(|i| !*i)
127 .ok_or(StorageError::NoSlots)?;
128
129 self.used[pos] = true;
130
131 Ok(OffsetMetaHandle::from_offset_meta(pos, meta))
132 }
133
134 unsafe fn deallocate<T: ?Sized + Pointee>(&mut self, handle: Self::Handle<T>) {
135 self.used[handle.offset()] = false;
136 }
137}
138
139impl<S, const N: usize> ExactSizeStorage for MultiStatic<S, N>
140where
141 S: StorageSafe,
142{
143 fn will_fit<T: ?Sized + Pointee>(&self, meta: T::Metadata) -> bool {
144 let layout = utils::layout_of::<T>(meta);
145 mem::size_of::<S>() >= layout.size()
146 }
147
148 fn max_range<T>(&self) -> usize {
149 let layout = Layout::new::<T>();
150 mem::size_of::<S>() / layout.size()
151 }
152}
153
154impl<S, const N: usize> Drop for MultiStatic<S, N> {
155 fn drop(&mut self) {
156 self.storage.release();
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163 use crate::backing::{Align8, Backing};
164 use crate::collections::LinkedList;
165
166 #[test]
167 fn test_linked_list() {
168 static FOO: StorageCell<[Backing<24, Align8>; 4]> = StorageCell::new([Backing::new(); 4]);
169
170 let mut list = LinkedList::<u8, MultiStatic<Backing<24, Align8>, 4>>::new_in(FOO.claim());
171 list.push(1);
172 list.push(2);
173
174 assert_eq!(list.get(0), Some(&1));
175 assert_eq!(list.get(1), Some(&2));
176 assert_eq!(list.get(3), None);
177 }
178}