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]
38 pub unsafe fn get<'b>(&self, _token: &'b LockToken<'_, Class>) -> &'b T {
39 unsafe { &*self.value.get() }
43 }
44
45 #[inline]
54 pub unsafe fn get_mut<'b>(&self, _token: &'b mut LockToken<'_, Class>) -> &'b mut T {
55 unsafe { &mut *self.value.get() }
61 }
62
63 #[inline]
70 pub unsafe fn as_mut_ptr(&self, _token: &mut LockToken<'_, Class>) -> *mut T {
71 self.value.get()
72 }
73
74 #[inline]
77 pub fn get_inner_mut(&mut self) -> &mut T {
78 self.value.get_mut()
79 }
80
81 #[inline]
83 pub fn get_pinned_mut(self: core::pin::Pin<&mut Self>) -> core::pin::Pin<&mut T> {
84 unsafe { self.map_unchecked_mut(|s| s.get_inner_mut()) }
87 }
88
89 #[inline]
91 pub fn into_inner(self) -> T {
92 self.value.into_inner()
93 }
94}
95
96impl<T: Default, Class> Default for KCell<T, Class> {
97 #[inline]
98 fn default() -> Self {
99 Self::new(T::default())
100 }
101}
102
103impl<T, Class> From<T> for KCell<T, Class> {
104 #[inline]
105 fn from(value: T) -> Self {
106 Self::new(value)
107 }
108}
109
110impl<T, Class> AsMut<T> for KCell<T, Class> {
111 #[inline]
112 fn as_mut(&mut self) -> &mut T {
113 self.get_inner_mut()
114 }
115}
116
117impl<T, Class> core::fmt::Debug for KCell<T, Class> {
118 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
119 f.debug_struct("KCell")
120 .field("value", &"<locked>")
121 .field("class", &core::any::type_name::<Class>())
122 .finish()
123 }
124}
125
126#[inline]
128pub fn kcell_init<I, Class>(init: I) -> KCellInit<I, Class> {
129 KCellInit(init, PhantomData)
130}
131
132pub struct KCellInit<I, Class>(I, PhantomData<Class>);
134
135unsafe impl<T, Class, I, E> pin_init::PinInit<KCell<T, Class>, E> for KCellInit<I, Class>
138where
139 I: pin_init::PinInit<T, E>,
140{
141 unsafe fn __pinned_init(self, slot: *mut KCell<T, Class>) -> Result<(), E> {
142 unsafe { self.0.__pinned_init(slot as *mut T) }
145 }
146}
147
148#[cfg(not(feature = "kernel"))]
149#[cfg(test)]
150mod tests {
151 use super::*;
152 use lockdep::LockClass;
153
154 struct MyClass;
155 impl LockClass for MyClass {
156 const ID: *mut core::ffi::c_void = core::ptr::null_mut();
157 }
158
159 #[test]
160 fn test_kcell_default() {
161 let cell: KCell<u32, MyClass> = KCell::default();
162 unsafe {
163 let token = LockToken::new();
164 assert_eq!(*cell.get(&token), 0);
165 }
166 }
167
168 #[test]
169 fn test_kcell_exclusive_access() {
170 let mut cell: KCell<u32, MyClass> = KCell::new(10);
171 *cell.get_inner_mut() = 20;
172 let reference: &mut u32 = cell.as_mut();
173 *reference = 30;
174 let value = cell.into_inner();
175 assert_eq!(value, 30);
176 }
177
178 #[test]
179 fn test_kcell_as_mut_ptr() {
180 let cell: KCell<u32, MyClass> = KCell::new(100u32);
181 unsafe {
182 let mut token = LockToken::new();
183 let ptr = cell.as_mut_ptr(&mut token);
184 assert_eq!(*ptr, 100);
185 }
186 }
187
188 #[test]
189 fn test_kcell_debug() {
190 extern crate std;
191 let cell: KCell<u32, MyClass> = KCell::new(5);
192 let debug_str = std::format!("{:?}", cell);
193 assert!(debug_str.contains("KCell"));
194 assert!(debug_str.contains("<locked>"));
195 assert!(debug_str.contains("MyClass"));
196 }
197
198 #[test]
199 fn test_kcell_init() {
200 let init = unsafe {
201 pin_init::pin_init_from_closure(|slot: *mut u32| {
202 slot.write(42);
203 Ok::<(), core::convert::Infallible>(())
204 })
205 };
206 let cell_init = kcell_init::<_, MyClass>(init);
207
208 pin_init::stack_pin_init!(let cell = cell_init);
209 let cell: core::pin::Pin<&mut KCell<u32, MyClass>> = cell;
210
211 unsafe {
212 let token = LockToken::<MyClass>::new();
213 let val = cell.as_ref().get_ref().get(&token);
214 assert_eq!(*val, 42);
215 }
216 }
217}