xref: /openbmc/linux/rust/kernel/types.rs (revision 4d4692a2)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 //! Kernel types.
4 
5 use core::{
6     cell::UnsafeCell,
7     mem::MaybeUninit,
8     ops::{Deref, DerefMut},
9 };
10 
11 /// Runs a cleanup function/closure when dropped.
12 ///
13 /// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running.
14 ///
15 /// # Examples
16 ///
17 /// In the example below, we have multiple exit paths and we want to log regardless of which one is
18 /// taken:
19 /// ```
20 /// # use kernel::ScopeGuard;
21 /// fn example1(arg: bool) {
22 ///     let _log = ScopeGuard::new(|| pr_info!("example1 completed\n"));
23 ///
24 ///     if arg {
25 ///         return;
26 ///     }
27 ///
28 ///     pr_info!("Do something...\n");
29 /// }
30 ///
31 /// # example1(false);
32 /// # example1(true);
33 /// ```
34 ///
35 /// In the example below, we want to log the same message on all early exits but a different one on
36 /// the main exit path:
37 /// ```
38 /// # use kernel::ScopeGuard;
39 /// fn example2(arg: bool) {
40 ///     let log = ScopeGuard::new(|| pr_info!("example2 returned early\n"));
41 ///
42 ///     if arg {
43 ///         return;
44 ///     }
45 ///
46 ///     // (Other early returns...)
47 ///
48 ///     log.dismiss();
49 ///     pr_info!("example2 no early return\n");
50 /// }
51 ///
52 /// # example2(false);
53 /// # example2(true);
54 /// ```
55 ///
56 /// In the example below, we need a mutable object (the vector) to be accessible within the log
57 /// function, so we wrap it in the [`ScopeGuard`]:
58 /// ```
59 /// # use kernel::ScopeGuard;
60 /// fn example3(arg: bool) -> Result {
61 ///     let mut vec =
62 ///         ScopeGuard::new_with_data(Vec::new(), |v| pr_info!("vec had {} elements\n", v.len()));
63 ///
64 ///     vec.try_push(10u8)?;
65 ///     if arg {
66 ///         return Ok(());
67 ///     }
68 ///     vec.try_push(20u8)?;
69 ///     Ok(())
70 /// }
71 ///
72 /// # assert_eq!(example3(false), Ok(()));
73 /// # assert_eq!(example3(true), Ok(()));
74 /// ```
75 ///
76 /// # Invariants
77 ///
78 /// The value stored in the struct is nearly always `Some(_)`, except between
79 /// [`ScopeGuard::dismiss`] and [`ScopeGuard::drop`]: in this case, it will be `None` as the value
80 /// will have been returned to the caller. Since  [`ScopeGuard::dismiss`] consumes the guard,
81 /// callers won't be able to use it anymore.
82 pub struct ScopeGuard<T, F: FnOnce(T)>(Option<(T, F)>);
83 
84 impl<T, F: FnOnce(T)> ScopeGuard<T, F> {
85     /// Creates a new guarded object wrapping the given data and with the given cleanup function.
86     pub fn new_with_data(data: T, cleanup_func: F) -> Self {
87         // INVARIANT: The struct is being initialised with `Some(_)`.
88         Self(Some((data, cleanup_func)))
89     }
90 
91     /// Prevents the cleanup function from running and returns the guarded data.
92     pub fn dismiss(mut self) -> T {
93         // INVARIANT: This is the exception case in the invariant; it is not visible to callers
94         // because this function consumes `self`.
95         self.0.take().unwrap().0
96     }
97 }
98 
99 impl ScopeGuard<(), fn(())> {
100     /// Creates a new guarded object with the given cleanup function.
101     pub fn new(cleanup: impl FnOnce()) -> ScopeGuard<(), impl FnOnce(())> {
102         ScopeGuard::new_with_data((), move |_| cleanup())
103     }
104 }
105 
106 impl<T, F: FnOnce(T)> Deref for ScopeGuard<T, F> {
107     type Target = T;
108 
109     fn deref(&self) -> &T {
110         // The type invariants guarantee that `unwrap` will succeed.
111         &self.0.as_ref().unwrap().0
112     }
113 }
114 
115 impl<T, F: FnOnce(T)> DerefMut for ScopeGuard<T, F> {
116     fn deref_mut(&mut self) -> &mut T {
117         // The type invariants guarantee that `unwrap` will succeed.
118         &mut self.0.as_mut().unwrap().0
119     }
120 }
121 
122 impl<T, F: FnOnce(T)> Drop for ScopeGuard<T, F> {
123     fn drop(&mut self) {
124         // Run the cleanup function if one is still present.
125         if let Some((data, cleanup)) = self.0.take() {
126             cleanup(data)
127         }
128     }
129 }
130 
131 /// Stores an opaque value.
132 ///
133 /// This is meant to be used with FFI objects that are never interpreted by Rust code.
134 #[repr(transparent)]
135 pub struct Opaque<T>(MaybeUninit<UnsafeCell<T>>);
136 
137 impl<T> Opaque<T> {
138     /// Creates a new opaque value.
139     pub const fn new(value: T) -> Self {
140         Self(MaybeUninit::new(UnsafeCell::new(value)))
141     }
142 
143     /// Creates an uninitialised value.
144     pub const fn uninit() -> Self {
145         Self(MaybeUninit::uninit())
146     }
147 
148     /// Returns a raw pointer to the opaque data.
149     pub fn get(&self) -> *mut T {
150         UnsafeCell::raw_get(self.0.as_ptr())
151     }
152 }
153 
154 /// A sum type that always holds either a value of type `L` or `R`.
155 pub enum Either<L, R> {
156     /// Constructs an instance of [`Either`] containing a value of type `L`.
157     Left(L),
158 
159     /// Constructs an instance of [`Either`] containing a value of type `R`.
160     Right(R),
161 }
162