1use crate::lock_token::LockToken;
6use core::marker::PhantomData;
7
8#[repr(transparent)]
14pub struct KCell<T, Class> {
15 value: core::cell::UnsafeCell<T>,
16 _marker: PhantomData<Class>,
17}
18
19unsafe impl<T: Send, Class> Sync for KCell<T, Class> {}
20unsafe impl<T: Send, Class> Send for KCell<T, Class> {}
21
22impl<T, Class> KCell<T, Class> {
23 #[inline]
25 pub const fn new(value: T) -> Self {
26 Self { value: core::cell::UnsafeCell::new(value), _marker: PhantomData }
27 }
28
29 #[inline]
36 pub unsafe fn get<'b>(&self, _token: &'b LockToken<'_, Class>) -> &'b T {
37 unsafe { &*self.value.get() }
40 }
41
42 #[inline]
49 pub unsafe fn get_mut<'b>(&self, _token: &'b mut LockToken<'_, Class>) -> &'b mut T {
50 unsafe { &mut *self.value.get() }
54 }
55
56 #[inline]
63 pub unsafe fn as_mut_ptr(&self, _token: &mut LockToken<'_, Class>) -> *mut T {
64 self.value.get()
65 }
66
67 #[inline]
70 pub fn get_inner_mut(&mut self) -> &mut T {
71 self.value.get_mut()
72 }
73
74 #[inline]
76 pub fn get_pinned_mut(self: core::pin::Pin<&mut Self>) -> core::pin::Pin<&mut T> {
77 unsafe { self.map_unchecked_mut(|s| s.get_inner_mut()) }
80 }
81
82 pub fn pin_init<E>(init: impl pin_init::PinInit<T, E>) -> impl pin_init::PinInit<Self, E> {
84 unsafe {
86 pin_init::pin_init_from_closure(move |slot: *mut Self| {
87 init.__pinned_init(slot.cast::<T>())
88 })
89 }
90 }
91
92 #[inline]
94 pub fn into_inner(self) -> T {
95 self.value.into_inner()
96 }
97}
98
99impl<T: Default, Class> Default for KCell<T, Class> {
100 #[inline]
101 fn default() -> Self {
102 Self::new(T::default())
103 }
104}
105
106impl<T, Class> From<T> for KCell<T, Class> {
107 #[inline]
108 fn from(value: T) -> Self {
109 Self::new(value)
110 }
111}
112
113impl<T, Class> AsMut<T> for KCell<T, Class> {
114 #[inline]
115 fn as_mut(&mut self) -> &mut T {
116 self.get_inner_mut()
117 }
118}
119
120impl<T, Class> core::fmt::Debug for KCell<T, Class> {
121 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
122 f.debug_struct("KCell")
123 .field("value", &"<locked>")
124 .field("class", &core::any::type_name::<Class>())
125 .finish()
126 }
127}
128
129#[inline]
131pub fn kcell_init<I, Class>(init: I) -> KCellInit<I, Class> {
132 KCellInit(init, PhantomData)
133}
134
135pub struct KCellInit<I, Class>(I, PhantomData<Class>);
137
138unsafe impl<T, Class, I, E> pin_init::PinInit<KCell<T, Class>, E> for KCellInit<I, Class>
141where
142 I: pin_init::PinInit<T, E>,
143{
144 unsafe fn __pinned_init(self, slot: *mut KCell<T, Class>) -> Result<(), E> {
145 unsafe { self.0.__pinned_init(slot as *mut T) }
148 }
149}
150
151#[cfg(not(feature = "kernel"))]
152#[cfg(test)]
153mod tests {
154 use super::*;
155 use lockdep::LockClass;
156
157 struct MyClass;
158 impl LockClass for MyClass {
159 const ID: *mut core::ffi::c_void = core::ptr::null_mut();
160 }
161
162 #[test]
163 fn test_kcell_default() {
164 let cell: KCell<u32, MyClass> = KCell::default();
165 unsafe {
166 let token = LockToken::new();
167 assert_eq!(*cell.get(&token), 0);
168 }
169 }
170
171 #[test]
172 fn test_kcell_exclusive_access() {
173 let mut cell: KCell<u32, MyClass> = KCell::new(10);
174 *cell.get_inner_mut() = 20;
175 let reference: &mut u32 = cell.as_mut();
176 *reference = 30;
177 let value = cell.into_inner();
178 assert_eq!(value, 30);
179 }
180
181 #[test]
182 fn test_kcell_as_mut_ptr() {
183 let cell: KCell<u32, MyClass> = KCell::new(100u32);
184 unsafe {
185 let mut token = LockToken::new();
186 let ptr = cell.as_mut_ptr(&mut token);
187 assert_eq!(*ptr, 100);
188 }
189 }
190
191 #[test]
192 fn test_kcell_debug() {
193 extern crate std;
194 let cell: KCell<u32, MyClass> = KCell::new(5);
195 let debug_str = std::format!("{:?}", cell);
196 assert!(debug_str.contains("KCell"));
197 assert!(debug_str.contains("<locked>"));
198 assert!(debug_str.contains("MyClass"));
199 }
200
201 #[test]
202 fn test_kcell_init() {
203 let init = unsafe {
204 pin_init::pin_init_from_closure(|slot: *mut u32| {
205 slot.write(42);
206 Ok::<(), core::convert::Infallible>(())
207 })
208 };
209 let cell_init = kcell_init::<_, MyClass>(init);
210
211 pin_init::stack_pin_init!(let cell = cell_init);
212 let cell: core::pin::Pin<&mut KCell<u32, MyClass>> = cell;
213
214 unsafe {
215 let token = LockToken::<MyClass>::new();
216 let val = cell.as_ref().get_ref().get(&token);
217 assert_eq!(*val, 42);
218 }
219 }
220}