starnix_core/
mutable_state.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Macros used with struct containing an immutable state and a RwLock to a mutable state.
6//!
7//! These macros define a new type of read and write guards that allow access to both the
8//! mutable and immutable state. To use it, one must:
9//! - Define the main struct (e.g. `Foo`) for the object with the immutable state.
10//! - Define a struct for the mutable state (e.g. `FooMutableState`).
11//! - Have a RwLock<> in the main struct for the mutable state (e.g. `mutable_state:
12//! RwLock<FooMutableState>`).
13//! - In the implementation of the main struct, add a call to the `state_accessor` macros:
14//! ```
15//! impl Foo {
16//!   state_accessor!(Foo, mutable_state);
17//! }
18//! ```
19//! - Write the method on the guards using the state_implementation macro:
20//! ```
21//! #[apply(state_implementation!)]
22//! impl FooMutableState<Base=Foo> {
23//!     // Some comment
24//!     fn do_something(&self) -> i32 {
25//!         0
26//!     }
27//! }
28//! ```
29//!
30//! # Complete example:
31//!
32//! ```
33//! pub struct FooMutableState {
34//!     y: i32,
35//! }
36//!
37//! pub struct Foo {
38//!     x: i32,
39//!     mutable_state: RwLock<FooMutableState>,
40//! }
41//!
42//! impl Foo {
43//!     fn new() -> Self {
44//!         Self { x: 2, mutable_state: RwLock::new(FooMutableState { y: 3 }) }
45//!     }
46//!
47//!     state_accessor!(Foo, mutable_state);
48//! }
49//!
50//! #[attr(state_implementation!)]
51//! impl FooMutableState<Base=Foo> {
52//!     // Some comment
53//!     fn x_and_y(&self) -> i32 {
54//!         self.base.x + self.y
55//!     }
56//!     /// Some rustdoc.
57//!     pub fn pub_x_and_y(&self) -> i32 {
58//!         self.x_and_y()
59//!     }
60//!     fn do_something(&self) {}
61//!     fn set_y(&mut self, other_y: i32) {
62//!         self.y = other_y;
63//!     }
64//!     pub fn pub_set_y(&mut self, other_y: i32) {
65//!         self.set_y(other_y)
66//!     }
67//!     fn do_something_mutable(&mut self) {
68//!         self.do_something();
69//!     }
70//!
71//!     #[allow(dead_code)]
72//!     pub fn with_lifecycle<'a>(&self, _n: &'a u32) {}
73//!     #[allow(dead_code)]
74//!     pub fn with_type<T>(&self, _n: &T) {}
75//!     #[allow(dead_code)]
76//!     pub fn with_lifecycle_and_type<'a, T>(&self, _n: &'a T) {}
77//!     #[allow(dead_code)]
78//!     pub fn with_lifecycle_on_self<'a, T>(&'a self, _n: &'a T) {}
79//! }
80//! ```
81//!
82//! # Generated code
83//!
84//! ```
85//! pub struct FooMutableState {
86//!     y: i32,
87//! }
88//! pub struct Foo {
89//!     x: i32,
90//!     mutable_state: RwLock<FooMutableState>,
91//! }
92//! impl Foo {
93//!     fn new() -> Self {
94//!         Self {
95//!             x: 2,
96//!             mutable_state: RwLock::new(FooMutableState { y: 3 }),
97//!         }
98//!     }
99//!
100//!     #[allow(dead_code)]
101//!     pub fn read<'a>(self: &'a Foo) -> FooReadGuard<'a> {
102//!         ReadGuard::new(self, self.mutable_state.read())
103//!     }
104//!     #[allow(dead_code)]
105//!     pub fn write<'a>(self: &'a Foo) -> FooWriteGuard<'a> {
106//!         WriteGuard::new(self, self.mutable_state.write())
107//!     }
108//! }
109//!
110//! #[allow(dead_code)]
111//! pub type FooReadGuard<'guard_lifetime> = ReadGuard<'guard_lifetime, Foo, FooMutableState>;
112//! #[allow(dead_code)]
113//! pub type FooWriteGuard<'guard_lifetime> = WriteGuard<'guard_lifetime, Foo, FooMutableState>;
114//! #[allow(dead_code)]
115//! pub type FooStateRef<'ref_lifetime> = StateRef<'ref_lifetime, Foo, FooMutableState>;
116//! #[allow(dead_code)]
117//! pub type FooStateMutRef<'ref_lifetime> = StateMutRef<'ref_lifetime, Foo, FooMutableState>;
118//!
119//! impl<'guard, G: 'guard + std::ops::Deref<Target = FooMutableState>> Guard<'guard, Foo, G> {
120//!     fn x_and_y(&self) -> i32 {
121//!         self.base.x + self.y
122//!     }
123//!     /// Some rustdoc.
124//!     pub fn pub_x_and_y(&self) -> i32 {
125//!         self.x_and_y()
126//!     }
127//!     fn do_something(&self) {}
128//!     #[allow(dead_code)]
129//!     pub fn with_lifecycle<'a>(&self, _n: &'a u32) {}
130//!     #[allow(dead_code)]
131//!     pub fn with_type<T>(&self, _n: &T) {}
132//!     #[allow(dead_code)]
133//!     pub fn with_lifecycle_and_type<'a, T>(&self, _n: &'a T) {}
134//!     #[allow(dead_code)]
135//!     pub fn with_lifecycle_on_self<'a, T>(&'a self, _n: &'a T) {}
136//! }
137//!
138//! impl<'guard, G: 'guard + std::ops::DerefMut<Target = FooMutableState>> Guard<'guard, Foo, G> {
139//!     fn set_y(&mut self, other_y: i32) {
140//!         self.y = other_y;
141//!     }
142//!     pub fn pub_set_y(&mut self, other_y: i32) {
143//!         self.set_y(other_y)
144//!     }
145//!     fn do_something_mutable(&mut self) {
146//!         self.do_something();
147//!     }
148//! }
149//! ```
150
151use starnix_sync::{MutexGuard, RwLockReadGuard, RwLockWriteGuard};
152use std::ops::{Deref, DerefMut};
153
154/// Create the read() and write() accessor to respectively access the read guard and write guard.
155///
156/// For a base struct named `Foo`, the read guard will be a struct named `FooReadGuard` and the
157/// write guard a struct named `FooWriteGuard`.
158macro_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
176/// Create the read() and write() accessor to respectively access the read guard and write guard
177/// of an OrderedRwLock using a Locked context.
178///
179/// For a base struct named `Foo`, the read guard will be a struct named `FooReadGuard` and the
180/// write guard a struct named `FooWriteGuard`.
181macro_rules! ordered_state_accessor {
182    ($base_name:ident, $field_name:ident, $base_type:ty, $lock_level:ident) => {
183        paste::paste! {
184        #[allow(dead_code)]
185        pub fn read<'a, L>(self: &'a $base_type, locked: &'a mut starnix_sync::Locked<L>) -> [<$base_name ReadGuard>]<'a>
186        where
187            L: starnix_sync::LockBefore<$lock_level>
188        {
189            $crate::mutable_state::ReadGuard::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>) -> [<$base_name WriteGuard>]<'a>
193        where
194            L: starnix_sync::LockBefore<$lock_level>
195        {
196            $crate::mutable_state::WriteGuard::new(self, self.$field_name.write(locked))
197        }
198        }
199    };
200    ($base_name:ident, $field_name:ident, $lock_level:ident) => {
201        ordered_state_accessor!($base_name, $field_name, $base_name, $lock_level);
202    };
203}
204
205/// Create the structs for the read and write guards using the methods defined inside the macro.
206macro_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
290// Public re-export of macros allows them to be used like regular rust items.
291pub(crate) use {ordered_state_accessor, state_accessor, state_implementation};
292
293#[cfg(test)]
294mod test {
295    use macro_rules_attribute::apply;
296    use starnix_sync::RwLock;
297
298    pub struct FooMutableState {
299        y: i32,
300    }
301
302    pub struct Foo {
303        x: i32,
304        mutable_state: RwLock<FooMutableState>,
305    }
306
307    impl Foo {
308        fn new() -> Self {
309            Self { x: 2, mutable_state: RwLock::new(FooMutableState { y: 3 }) }
310        }
311
312        state_accessor!(Foo, mutable_state);
313    }
314
315    #[apply(state_implementation!)]
316    impl FooMutableState<Base = Foo> {
317        // Some comment
318        fn x_and_y(&self) -> i32 {
319            self.base.x + self.y
320        }
321        /// Some rustdoc.
322        pub fn pub_x_and_y(&self) -> i32 {
323            self.x_and_y()
324        }
325        fn do_something(&self) {}
326        fn set_y(&mut self, other_y: i32) {
327            self.y = other_y;
328        }
329        pub fn pub_set_y(&mut self, other_y: i32) {
330            self.set_y(other_y)
331        }
332        fn do_something_mutable(&mut self) {
333            self.do_something();
334        }
335
336        #[allow(dead_code, clippy::needless_lifetimes)]
337        pub fn with_lifecycle<'a>(&self, _n: &'a u32) {}
338        #[allow(dead_code)]
339        pub fn with_type<T>(&self, _n: &T) {}
340        #[allow(dead_code)]
341        pub fn with_type_and_where<T>(&self, _n: &T)
342        where
343            T: Copy,
344        {
345        }
346        #[allow(dead_code)]
347        pub fn with_type_and_bound<T: Copy>(&self, _n: &T) {}
348        #[allow(dead_code)]
349        pub fn with_multiple_types_and_bound_and_where<T: Copy, U>(&self, _n: &T)
350        where
351            U: Copy,
352        {
353        }
354        #[allow(dead_code, clippy::needless_lifetimes)]
355        pub fn with_lifecycle_and_type<'a, T>(&self, _n: &'a T) {}
356        #[allow(dead_code, clippy::needless_lifetimes)]
357        pub fn with_lifecycle_on_self<'a, T>(&'a self, _n: &'a T) {}
358    }
359
360    fn take_foo_state(foo_state: &FooStateRef<'_>) -> i32 {
361        foo_state.pub_x_and_y()
362    }
363
364    #[::fuchsia::test]
365    fn test_generation() {
366        let foo = Foo::new();
367
368        assert_eq!(foo.read().x_and_y(), 5);
369        assert_eq!(foo.read().pub_x_and_y(), 5);
370        assert_eq!(foo.write().pub_x_and_y(), 5);
371        foo.write().set_y(22);
372        assert_eq!(foo.read().pub_x_and_y(), 24);
373        assert_eq!(foo.write().pub_x_and_y(), 24);
374        foo.write().pub_set_y(20);
375        assert_eq!(take_foo_state(&foo.read().as_ref()), 22);
376        assert_eq!(take_foo_state(&foo.write().as_ref()), 22);
377
378        foo.read().do_something();
379        foo.write().do_something();
380        foo.write().do_something_mutable();
381    }
382}