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}