Skip to main content

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::{LockDepGuard, LockDepReadGuard, LockDepWriteGuard, MutexGuard};
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 structs for the read and write guards using the methods defined inside the macro.
177macro_rules! state_implementation {
178    (impl $mutable_name:ident<Base=$base_name:ident> {
179        $(
180            $tt:tt
181        )*
182    }) => {
183        state_implementation! {
184            impl $mutable_name<Base = $base_name, BaseType = $base_name> {
185                $($tt)*
186            }
187        }
188    };
189    (impl $mutable_name:ident<Base=$base_name:ident, BaseType = $base_type:ty> {
190        $(
191            $tt:tt
192        )*
193    }) => {
194        paste::paste! {
195        #[allow(dead_code)]
196        pub type [<$base_name ReadGuard>]<'guard_lifetime> = $crate::mutable_state::ReadGuard<'guard_lifetime, $base_type,  $mutable_name>;
197        #[allow(dead_code)]
198        pub type [<$base_name WriteGuard>]<'guard_lifetime> = $crate::mutable_state::WriteGuard<'guard_lifetime, $base_type, $mutable_name>;
199        #[allow(dead_code)]
200        pub type [<$base_name StateRef>]<'ref_lifetime> = $crate::mutable_state::StateRef<'ref_lifetime, $base_type, $mutable_name>;
201        #[allow(dead_code)]
202        pub type [<$base_name StateMutRef>]<'ref_lifetime> = $crate::mutable_state::StateMutRef<'ref_lifetime, $base_type, $mutable_name>;
203
204        impl<'guard, G: 'guard + std::ops::Deref<Target=$mutable_name>> $crate::mutable_state::Guard<'guard, $base_type, G> {
205            filter_methods_macro::filter_methods!(RoMethod, $($tt)*);
206        }
207
208        impl<'guard, G: 'guard + std::ops::DerefMut<Target=$mutable_name>> $crate::mutable_state::Guard<'guard, $base_type, G> {
209            filter_methods_macro::filter_methods!(RwMethod, $($tt)*);
210        }
211        }
212    };
213}
214
215pub struct Guard<'a, B, G> {
216    pub base: &'a B,
217    guard: G,
218}
219pub type ReadGuard<'a, B, S> = Guard<'a, B, LockDepReadGuard<'a, S>>;
220pub type WriteGuard<'a, B, S> = Guard<'a, B, LockDepWriteGuard<'a, S>>;
221pub type StateRef<'a, B, S> = Guard<'a, B, &'a S>;
222pub type StateMutRef<'a, B, S> = Guard<'a, B, &'a mut S>;
223
224impl<'a, B, S> Guard<'a, B, MutexGuard<'a, S>> {
225    /// Executes the given closure while temporarily dropping the lock.
226    ///
227    /// The lock is dropped before the closure executes and re-acquired
228    /// after it finishes.
229    pub fn unlocked<F, U>(s: &mut Self, f: F) -> U
230    where
231        F: FnOnce() -> U,
232    {
233        MutexGuard::unlocked(&mut s.guard, f)
234    }
235}
236
237impl<'a, B, S> Guard<'a, B, LockDepGuard<'a, S>> {
238    /// Executes the given closure while temporarily dropping the lock.
239    ///
240    /// The lock is dropped before the closure executes and re-acquired
241    /// after it finishes.
242    pub fn unlocked<F, U>(s: &mut Self, f: F) -> U
243    where
244        F: FnOnce() -> U,
245    {
246        LockDepGuard::unlocked(&mut s.guard, f)
247    }
248}
249
250impl<'guard, B, S, G: 'guard + Deref<Target = S>> Guard<'guard, B, G> {
251    pub fn new(base: &'guard B, guard: G) -> Self {
252        Self { base, guard }
253    }
254    pub fn as_ref(&self) -> StateRef<'_, B, S> {
255        Guard { base: self.base, guard: self.guard.deref() }
256    }
257}
258
259impl<'guard, B, S, G: 'guard + DerefMut<Target = S>> Guard<'guard, B, G> {
260    pub fn as_mut(&mut self) -> StateMutRef<'_, B, S> {
261        Guard { base: self.base, guard: self.guard.deref_mut() }
262    }
263}
264
265impl<'a, B, S, G: Deref<Target = S>> Deref for Guard<'a, B, G> {
266    type Target = S;
267    fn deref(&self) -> &Self::Target {
268        self.guard.deref()
269    }
270}
271
272impl<'a, B, S, G: DerefMut<Target = S>> DerefMut for Guard<'a, B, G> {
273    fn deref_mut(&mut self) -> &mut Self::Target {
274        self.guard.deref_mut()
275    }
276}
277
278// Public re-export of macros allows them to be used like regular rust items.
279pub(crate) use state_accessor;
280pub(crate) use state_implementation;
281
282#[cfg(test)]
283mod test {
284    use macro_rules_attribute::apply;
285    use starnix_sync::{LockDepRwLock, lock_ordering};
286    lock_ordering! {
287        Terminal(FooLock),
288    }
289
290    pub struct FooMutableState {
291        y: i32,
292    }
293
294    pub struct Foo {
295        x: i32,
296        mutable_state: LockDepRwLock<FooMutableState, FooLock>,
297    }
298
299    impl Foo {
300        fn new() -> Self {
301            Self { x: 2, mutable_state: FooMutableState { y: 3 }.into() }
302        }
303
304        state_accessor!(Foo, mutable_state);
305    }
306
307    #[apply(state_implementation!)]
308    impl FooMutableState<Base = Foo> {
309        // Some comment
310        fn x_and_y(&self) -> i32 {
311            self.base.x + self.y
312        }
313        /// Some rustdoc.
314        pub fn pub_x_and_y(&self) -> i32 {
315            self.x_and_y()
316        }
317        fn do_something(&self) {}
318        fn set_y(&mut self, other_y: i32) {
319            self.y = other_y;
320        }
321        pub fn pub_set_y(&mut self, other_y: i32) {
322            self.set_y(other_y)
323        }
324        fn do_something_mutable(&mut self) {
325            self.do_something();
326        }
327
328        #[allow(dead_code, clippy::needless_lifetimes)]
329        pub fn with_lifecycle<'a>(&self, _n: &'a u32) {}
330        #[allow(dead_code)]
331        pub fn with_type<T>(&self, _n: &T) {}
332        #[allow(dead_code)]
333        pub fn with_type_and_where<T>(&self, _n: &T)
334        where
335            T: Copy,
336        {
337        }
338        #[allow(dead_code)]
339        pub fn with_type_and_bound<T: Copy>(&self, _n: &T) {}
340        #[allow(dead_code)]
341        pub fn with_multiple_types_and_bound_and_where<T: Copy, U>(&self, _n: &T)
342        where
343            U: Copy,
344        {
345        }
346        #[allow(dead_code, clippy::needless_lifetimes)]
347        pub fn with_lifecycle_and_type<'a, T>(&self, _n: &'a T) {}
348        #[allow(dead_code, clippy::needless_lifetimes)]
349        pub fn with_lifecycle_on_self<'a, T>(&'a self, _n: &'a T) {}
350    }
351
352    fn take_foo_state(foo_state: &FooStateRef<'_>) -> i32 {
353        foo_state.pub_x_and_y()
354    }
355
356    #[::fuchsia::test]
357    fn test_generation() {
358        let foo = Foo::new();
359
360        assert_eq!(foo.read().x_and_y(), 5);
361        assert_eq!(foo.read().pub_x_and_y(), 5);
362        assert_eq!(foo.write().pub_x_and_y(), 5);
363        foo.write().set_y(22);
364        assert_eq!(foo.read().pub_x_and_y(), 24);
365        assert_eq!(foo.write().pub_x_and_y(), 24);
366        foo.write().pub_set_y(20);
367        assert_eq!(take_foo_state(&foo.read().as_ref()), 22);
368        assert_eq!(take_foo_state(&foo.write().as_ref()), 22);
369
370        foo.read().do_something();
371        foo.write().do_something();
372        foo.write().do_something_mutable();
373    }
374}