1use starnix_sync::{MutexGuard, RwLockReadGuard, RwLockWriteGuard};
152use std::ops::{Deref, DerefMut};
153
154macro_rules! state_accessor {
159 ($base_name:ident, $field_name:ident, $base_type:ty) => {
160 paste::paste! {
161 #[allow(dead_code)]
162 pub fn read<'a>(self: &'a $base_type) -> [<$base_name ReadGuard>]<'a> {
163 $crate::mutable_state::ReadGuard::new(self, self.$field_name.read())
164 }
165 #[allow(dead_code)]
166 pub fn write<'a>(self: &'a $base_type) -> [<$base_name WriteGuard>]<'a> {
167 $crate::mutable_state::WriteGuard::new(self, self.$field_name.write())
168 }
169 }
170 };
171 ($base_name:ident, $field_name:ident) => {
172 state_accessor!($base_name, $field_name, $base_name);
173 };
174}
175
176macro_rules! ordered_state_accessor {
182 ($base_name:ident, $field_name:ident, $base_type:ty, $lock_level:ident, $mutable_type:ty) => {
183 paste::paste! {
184 #[allow(dead_code)]
185 pub fn read<'a, L>(self: &'a $base_type, locked: &'a mut starnix_sync::Locked<L>) -> $crate::mutable_state::Guard<'a, $base_type, starnix_sync::LockDepReadGuard<'a, $mutable_type>>
186 where
187 L: starnix_sync::LockBefore<$lock_level>
188 {
189 $crate::mutable_state::Guard::new(self, self.$field_name.read(locked))
190 }
191 #[allow(dead_code)]
192 pub fn write<'a, L>(self: &'a $base_type, locked: &'a mut starnix_sync::Locked<L>) -> $crate::mutable_state::Guard<'a, $base_type, starnix_sync::LockDepWriteGuard<'a, $mutable_type>>
193 where
194 L: starnix_sync::LockBefore<$lock_level>
195 {
196 $crate::mutable_state::Guard::new(self, self.$field_name.write(locked))
197 }
198 }
199 };
200 ($base_name:ident, $field_name:ident, $lock_level:ident, $mutable_type:ty) => {
201 ordered_state_accessor!($base_name, $field_name, $base_name, $lock_level, $mutable_type);
202 };
203}
204
205macro_rules! state_implementation {
207 (impl $mutable_name:ident<Base=$base_name:ident> {
208 $(
209 $tt:tt
210 )*
211 }) => {
212 state_implementation! {
213 impl $mutable_name<Base = $base_name, BaseType = $base_name> {
214 $($tt)*
215 }
216 }
217 };
218 (impl $mutable_name:ident<Base=$base_name:ident, BaseType = $base_type:ty> {
219 $(
220 $tt:tt
221 )*
222 }) => {
223 paste::paste! {
224 #[allow(dead_code)]
225 pub type [<$base_name ReadGuard>]<'guard_lifetime> = $crate::mutable_state::ReadGuard<'guard_lifetime, $base_type, $mutable_name>;
226 #[allow(dead_code)]
227 pub type [<$base_name WriteGuard>]<'guard_lifetime> = $crate::mutable_state::WriteGuard<'guard_lifetime, $base_type, $mutable_name>;
228 #[allow(dead_code)]
229 pub type [<$base_name StateRef>]<'ref_lifetime> = $crate::mutable_state::StateRef<'ref_lifetime, $base_type, $mutable_name>;
230 #[allow(dead_code)]
231 pub type [<$base_name StateMutRef>]<'ref_lifetime> = $crate::mutable_state::StateMutRef<'ref_lifetime, $base_type, $mutable_name>;
232
233 impl<'guard, G: 'guard + std::ops::Deref<Target=$mutable_name>> $crate::mutable_state::Guard<'guard, $base_type, G> {
234 filter_methods_macro::filter_methods!(RoMethod, $($tt)*);
235 }
236
237 impl<'guard, G: 'guard + std::ops::DerefMut<Target=$mutable_name>> $crate::mutable_state::Guard<'guard, $base_type, G> {
238 filter_methods_macro::filter_methods!(RwMethod, $($tt)*);
239 }
240 }
241 };
242}
243
244pub struct Guard<'a, B, G> {
245 pub base: &'a B,
246 guard: G,
247}
248pub type ReadGuard<'a, B, S> = Guard<'a, B, RwLockReadGuard<'a, S>>;
249pub type WriteGuard<'a, B, S> = Guard<'a, B, RwLockWriteGuard<'a, S>>;
250pub type StateRef<'a, B, S> = Guard<'a, B, &'a S>;
251pub type StateMutRef<'a, B, S> = Guard<'a, B, &'a mut S>;
252
253impl<'a, B, S> Guard<'a, B, MutexGuard<'a, S>> {
254 pub fn unlocked<F, U>(s: &mut Self, f: F) -> U
255 where
256 F: FnOnce() -> U,
257 {
258 MutexGuard::unlocked(&mut s.guard, f)
259 }
260}
261
262impl<'guard, B, S, G: 'guard + Deref<Target = S>> Guard<'guard, B, G> {
263 pub fn new(base: &'guard B, guard: G) -> Self {
264 Self { base, guard }
265 }
266 pub fn as_ref(&self) -> StateRef<'_, B, S> {
267 Guard { base: self.base, guard: self.guard.deref() }
268 }
269}
270
271impl<'guard, B, S, G: 'guard + DerefMut<Target = S>> Guard<'guard, B, G> {
272 pub fn as_mut(&mut self) -> StateMutRef<'_, B, S> {
273 Guard { base: self.base, guard: self.guard.deref_mut() }
274 }
275}
276
277impl<'a, B, S, G: Deref<Target = S>> Deref for Guard<'a, B, G> {
278 type Target = S;
279 fn deref(&self) -> &Self::Target {
280 self.guard.deref()
281 }
282}
283
284impl<'a, B, S, G: DerefMut<Target = S>> DerefMut for Guard<'a, B, G> {
285 fn deref_mut(&mut self) -> &mut Self::Target {
286 self.guard.deref_mut()
287 }
288}
289
290pub(crate) use ordered_state_accessor;
292pub(crate) use state_accessor;
293pub(crate) use state_implementation;
294
295#[cfg(test)]
296mod test {
297 use macro_rules_attribute::apply;
298 use starnix_sync::RwLock;
299
300 pub struct FooMutableState {
301 y: i32,
302 }
303
304 pub struct Foo {
305 x: i32,
306 mutable_state: RwLock<FooMutableState>,
307 }
308
309 impl Foo {
310 fn new() -> Self {
311 Self { x: 2, mutable_state: RwLock::new(FooMutableState { y: 3 }) }
312 }
313
314 state_accessor!(Foo, mutable_state);
315 }
316
317 #[apply(state_implementation!)]
318 impl FooMutableState<Base = Foo> {
319 fn x_and_y(&self) -> i32 {
321 self.base.x + self.y
322 }
323 pub fn pub_x_and_y(&self) -> i32 {
325 self.x_and_y()
326 }
327 fn do_something(&self) {}
328 fn set_y(&mut self, other_y: i32) {
329 self.y = other_y;
330 }
331 pub fn pub_set_y(&mut self, other_y: i32) {
332 self.set_y(other_y)
333 }
334 fn do_something_mutable(&mut self) {
335 self.do_something();
336 }
337
338 #[allow(dead_code, clippy::needless_lifetimes)]
339 pub fn with_lifecycle<'a>(&self, _n: &'a u32) {}
340 #[allow(dead_code)]
341 pub fn with_type<T>(&self, _n: &T) {}
342 #[allow(dead_code)]
343 pub fn with_type_and_where<T>(&self, _n: &T)
344 where
345 T: Copy,
346 {
347 }
348 #[allow(dead_code)]
349 pub fn with_type_and_bound<T: Copy>(&self, _n: &T) {}
350 #[allow(dead_code)]
351 pub fn with_multiple_types_and_bound_and_where<T: Copy, U>(&self, _n: &T)
352 where
353 U: Copy,
354 {
355 }
356 #[allow(dead_code, clippy::needless_lifetimes)]
357 pub fn with_lifecycle_and_type<'a, T>(&self, _n: &'a T) {}
358 #[allow(dead_code, clippy::needless_lifetimes)]
359 pub fn with_lifecycle_on_self<'a, T>(&'a self, _n: &'a T) {}
360 }
361
362 fn take_foo_state(foo_state: &FooStateRef<'_>) -> i32 {
363 foo_state.pub_x_and_y()
364 }
365
366 #[::fuchsia::test]
367 fn test_generation() {
368 let foo = Foo::new();
369
370 assert_eq!(foo.read().x_and_y(), 5);
371 assert_eq!(foo.read().pub_x_and_y(), 5);
372 assert_eq!(foo.write().pub_x_and_y(), 5);
373 foo.write().set_y(22);
374 assert_eq!(foo.read().pub_x_and_y(), 24);
375 assert_eq!(foo.write().pub_x_and_y(), 24);
376 foo.write().pub_set_y(20);
377 assert_eq!(take_foo_state(&foo.read().as_ref()), 22);
378 assert_eq!(take_foo_state(&foo.write().as_ref()), 22);
379
380 foo.read().do_something();
381 foo.write().do_something();
382 foo.write().do_something_mutable();
383 }
384}