Skip to content

Commit 58aca84

Browse files
committed
rust: kernel: review doctests now that they run in the kernel
Now that doctests run within the kernel, we can perform some changes on them to increase their utility, e.g. now unneeded wrapper functions can be removed, and for other wrapper functions that are still needed, we can add calls to those to actually run the tests (hidden or not depending on whether they add value to readers). In addition, we enable a few more tests and reviewed other bits, such as asserting instead of printing. Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
1 parent 952b5c1 commit 58aca84

File tree

14 files changed

+227
-200
lines changed

14 files changed

+227
-200
lines changed

rust/kernel/build_assert.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
/// fn foo(a: usize) -> usize {
1616
/// a.checked_add(1).unwrap_or_else(|| build_error!("overflow"))
1717
/// }
18+
///
19+
/// assert_eq!(foo(usize::MAX - 1), usize::MAX); // OK.
20+
/// // foo(usize::MAX); // Fails to compile.
1821
/// ```
1922
#[macro_export]
2023
macro_rules! build_error {
@@ -51,7 +54,7 @@ macro_rules! build_error {
5154
///
5255
/// When the condition refers to generic parameters or parameters of an inline function,
5356
/// [`static_assert!`] cannot be used. Use `build_assert!` in this scenario.
54-
/// ```no_run
57+
/// ```
5558
/// # use kernel::prelude::*;
5659
/// fn foo<const N: usize>() {
5760
/// // `static_assert!(N > 1);` is not allowed

rust/kernel/lib.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,7 @@ impl<'a> Drop for KParamGuard<'a> {
196196
/// b: u32,
197197
/// }
198198
///
199-
/// fn test() {
200-
/// // This prints `8`.
201-
/// pr_info!("{}\n", offset_of!(Test, b));
202-
/// }
199+
/// assert_eq!(offset_of!(Test, b), 8);
203200
/// ```
204201
#[macro_export]
205202
macro_rules! offset_of {
@@ -237,13 +234,10 @@ macro_rules! offset_of {
237234
/// b: u32,
238235
/// }
239236
///
240-
/// fn test() {
241-
/// let test = Test { a: 10, b: 20 };
242-
/// let b_ptr = &test.b;
243-
/// let test_alias = container_of!(b_ptr, Test, b);
244-
/// // This prints `true`.
245-
/// pr_info!("{}\n", core::ptr::eq(&test, test_alias));
246-
/// }
237+
/// let test = Test { a: 10, b: 20 };
238+
/// let b_ptr = &test.b;
239+
/// let test_alias = container_of!(b_ptr, Test, b);
240+
/// assert!(core::ptr::eq(&test, test_alias));
247241
/// ```
248242
#[macro_export]
249243
macro_rules! container_of {

rust/kernel/rbtree.rs

Lines changed: 120 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -40,79 +40,81 @@ struct Node<K, V> {
4040
/// # use kernel::prelude::*;
4141
/// use kernel::rbtree::RBTree;
4242
///
43-
/// fn rbtest() -> Result {
44-
/// // Create a new tree.
45-
/// let mut tree = RBTree::new();
46-
///
47-
/// // Insert three elements.
48-
/// tree.try_insert(20, 200)?;
49-
/// tree.try_insert(10, 100)?;
50-
/// tree.try_insert(30, 300)?;
51-
///
52-
/// // Check the nodes we just inserted.
53-
/// {
54-
/// let mut iter = tree.iter();
55-
/// assert_eq!(iter.next().unwrap(), (&10, &100));
56-
/// assert_eq!(iter.next().unwrap(), (&20, &200));
57-
/// assert_eq!(iter.next().unwrap(), (&30, &300));
58-
/// assert!(iter.next().is_none());
59-
/// }
60-
///
61-
/// // Print all elements.
62-
/// for (key, value) in &tree {
63-
/// pr_info!("{} = {}\n", key, value);
64-
/// }
65-
///
66-
/// // Replace one of the elements.
67-
/// tree.try_insert(10, 1000)?;
68-
///
69-
/// // Check that the tree reflects the replacement.
70-
/// {
71-
/// let mut iter = tree.iter();
72-
/// assert_eq!(iter.next().unwrap(), (&10, &1000));
73-
/// assert_eq!(iter.next().unwrap(), (&20, &200));
74-
/// assert_eq!(iter.next().unwrap(), (&30, &300));
75-
/// assert!(iter.next().is_none());
76-
/// }
77-
///
78-
/// // Change the value of one of the elements.
79-
/// *tree.get_mut(&30).unwrap() = 3000;
80-
///
81-
/// // Check that the tree reflects the update.
82-
/// {
83-
/// let mut iter = tree.iter();
84-
/// assert_eq!(iter.next().unwrap(), (&10, &1000));
85-
/// assert_eq!(iter.next().unwrap(), (&20, &200));
86-
/// assert_eq!(iter.next().unwrap(), (&30, &3000));
87-
/// assert!(iter.next().is_none());
88-
/// }
89-
///
90-
/// // Remove an element.
91-
/// tree.remove(&10);
92-
///
93-
/// // Check that the tree reflects the removal.
94-
/// {
95-
/// let mut iter = tree.iter();
96-
/// assert_eq!(iter.next().unwrap(), (&20, &200));
97-
/// assert_eq!(iter.next().unwrap(), (&30, &3000));
98-
/// assert!(iter.next().is_none());
99-
/// }
100-
///
101-
/// // Update all values.
102-
/// for value in tree.values_mut() {
103-
/// *value *= 10;
104-
/// }
105-
///
106-
/// // Check that the tree reflects the changes to values.
107-
/// {
108-
/// let mut iter = tree.iter();
109-
/// assert_eq!(iter.next().unwrap(), (&20, &2000));
110-
/// assert_eq!(iter.next().unwrap(), (&30, &30000));
111-
/// assert!(iter.next().is_none());
112-
/// }
43+
/// # fn test() -> Result {
44+
/// // Create a new tree.
45+
/// let mut tree = RBTree::new();
46+
///
47+
/// // Insert three elements.
48+
/// tree.try_insert(20, 200)?;
49+
/// tree.try_insert(10, 100)?;
50+
/// tree.try_insert(30, 300)?;
51+
///
52+
/// // Check the nodes we just inserted.
53+
/// {
54+
/// let mut iter = tree.iter();
55+
/// assert_eq!(iter.next().unwrap(), (&10, &100));
56+
/// assert_eq!(iter.next().unwrap(), (&20, &200));
57+
/// assert_eq!(iter.next().unwrap(), (&30, &300));
58+
/// assert!(iter.next().is_none());
59+
/// }
11360
///
114-
/// Ok(())
61+
/// // Print all elements.
62+
/// for (key, value) in &tree {
63+
/// pr_info!("{} = {}\n", key, value);
64+
/// }
65+
///
66+
/// // Replace one of the elements.
67+
/// tree.try_insert(10, 1000)?;
68+
///
69+
/// // Check that the tree reflects the replacement.
70+
/// {
71+
/// let mut iter = tree.iter();
72+
/// assert_eq!(iter.next().unwrap(), (&10, &1000));
73+
/// assert_eq!(iter.next().unwrap(), (&20, &200));
74+
/// assert_eq!(iter.next().unwrap(), (&30, &300));
75+
/// assert!(iter.next().is_none());
76+
/// }
77+
///
78+
/// // Change the value of one of the elements.
79+
/// *tree.get_mut(&30).unwrap() = 3000;
80+
///
81+
/// // Check that the tree reflects the update.
82+
/// {
83+
/// let mut iter = tree.iter();
84+
/// assert_eq!(iter.next().unwrap(), (&10, &1000));
85+
/// assert_eq!(iter.next().unwrap(), (&20, &200));
86+
/// assert_eq!(iter.next().unwrap(), (&30, &3000));
87+
/// assert!(iter.next().is_none());
88+
/// }
89+
///
90+
/// // Remove an element.
91+
/// tree.remove(&10);
92+
///
93+
/// // Check that the tree reflects the removal.
94+
/// {
95+
/// let mut iter = tree.iter();
96+
/// assert_eq!(iter.next().unwrap(), (&20, &200));
97+
/// assert_eq!(iter.next().unwrap(), (&30, &3000));
98+
/// assert!(iter.next().is_none());
99+
/// }
100+
///
101+
/// // Update all values.
102+
/// for value in tree.values_mut() {
103+
/// *value *= 10;
104+
/// }
105+
///
106+
/// // Check that the tree reflects the changes to values.
107+
/// {
108+
/// let mut iter = tree.iter();
109+
/// assert_eq!(iter.next().unwrap(), (&20, &2000));
110+
/// assert_eq!(iter.next().unwrap(), (&30, &30000));
111+
/// assert!(iter.next().is_none());
115112
/// }
113+
///
114+
/// # Ok(())
115+
/// # }
116+
/// #
117+
/// # assert_eq!(test(), Ok(()));
116118
/// ```
117119
///
118120
/// In the example below, we first allocate a node, acquire a spinlock, then insert the node into
@@ -141,53 +143,55 @@ struct Node<K, V> {
141143
/// # use kernel::prelude::*;
142144
/// use kernel::rbtree::RBTree;
143145
///
144-
/// fn reuse_test() -> Result {
145-
/// // Create a new tree.
146-
/// let mut tree = RBTree::new();
147-
///
148-
/// // Insert three elements.
149-
/// tree.try_insert(20, 200)?;
150-
/// tree.try_insert(10, 100)?;
151-
/// tree.try_insert(30, 300)?;
152-
///
153-
/// // Check the nodes we just inserted.
154-
/// {
155-
/// let mut iter = tree.iter();
156-
/// assert_eq!(iter.next().unwrap(), (&10, &100));
157-
/// assert_eq!(iter.next().unwrap(), (&20, &200));
158-
/// assert_eq!(iter.next().unwrap(), (&30, &300));
159-
/// assert!(iter.next().is_none());
160-
/// }
161-
///
162-
/// // Remove a node, getting back ownership of it.
163-
/// let existing = tree.remove_node(&30).unwrap();
164-
///
165-
/// // Check that the tree reflects the removal.
166-
/// {
167-
/// let mut iter = tree.iter();
168-
/// assert_eq!(iter.next().unwrap(), (&10, &100));
169-
/// assert_eq!(iter.next().unwrap(), (&20, &200));
170-
/// assert!(iter.next().is_none());
171-
/// }
172-
///
173-
/// // Turn the node into a reservation so that we can reuse it with a different key/value.
174-
/// let reservation = existing.into_reservation();
175-
///
176-
/// // Insert a new node into the tree, reusing the previous allocation. This is guaranteed to
177-
/// // succeed (no memory allocations).
178-
/// tree.insert(reservation.into_node(15, 150));
179-
///
180-
/// // Check that the tree reflect the new insertion.
181-
/// {
182-
/// let mut iter = tree.iter();
183-
/// assert_eq!(iter.next().unwrap(), (&10, &100));
184-
/// assert_eq!(iter.next().unwrap(), (&15, &150));
185-
/// assert_eq!(iter.next().unwrap(), (&20, &200));
186-
/// assert!(iter.next().is_none());
187-
/// }
146+
/// # fn test() -> Result {
147+
/// // Create a new tree.
148+
/// let mut tree = RBTree::new();
149+
///
150+
/// // Insert three elements.
151+
/// tree.try_insert(20, 200)?;
152+
/// tree.try_insert(10, 100)?;
153+
/// tree.try_insert(30, 300)?;
154+
///
155+
/// // Check the nodes we just inserted.
156+
/// {
157+
/// let mut iter = tree.iter();
158+
/// assert_eq!(iter.next().unwrap(), (&10, &100));
159+
/// assert_eq!(iter.next().unwrap(), (&20, &200));
160+
/// assert_eq!(iter.next().unwrap(), (&30, &300));
161+
/// assert!(iter.next().is_none());
162+
/// }
188163
///
189-
/// Ok(())
164+
/// // Remove a node, getting back ownership of it.
165+
/// let existing = tree.remove_node(&30).unwrap();
166+
///
167+
/// // Check that the tree reflects the removal.
168+
/// {
169+
/// let mut iter = tree.iter();
170+
/// assert_eq!(iter.next().unwrap(), (&10, &100));
171+
/// assert_eq!(iter.next().unwrap(), (&20, &200));
172+
/// assert!(iter.next().is_none());
173+
/// }
174+
///
175+
/// // Turn the node into a reservation so that we can reuse it with a different key/value.
176+
/// let reservation = existing.into_reservation();
177+
///
178+
/// // Insert a new node into the tree, reusing the previous allocation. This is guaranteed to
179+
/// // succeed (no memory allocations).
180+
/// tree.insert(reservation.into_node(15, 150));
181+
///
182+
/// // Check that the tree reflect the new insertion.
183+
/// {
184+
/// let mut iter = tree.iter();
185+
/// assert_eq!(iter.next().unwrap(), (&10, &100));
186+
/// assert_eq!(iter.next().unwrap(), (&15, &150));
187+
/// assert_eq!(iter.next().unwrap(), (&20, &200));
188+
/// assert!(iter.next().is_none());
190189
/// }
190+
///
191+
/// # Ok(())
192+
/// # }
193+
/// #
194+
/// # assert_eq!(test(), Ok(()));
191195
/// ```
192196
pub struct RBTree<K, V> {
193197
root: bindings::rb_root,

rust/kernel/revocable.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,10 @@ use core::{
3535
/// Some(guard.a + guard.b)
3636
/// }
3737
///
38-
/// fn example() {
39-
/// let v = Revocable::new(Example { a: 10, b: 20 });
40-
/// assert_eq!(add_two(&v), Some(30));
41-
/// v.revoke();
42-
/// assert_eq!(add_two(&v), None);
43-
/// }
38+
/// let v = Revocable::new(Example { a: 10, b: 20 });
39+
/// assert_eq!(add_two(&v), Some(30));
40+
/// v.revoke();
41+
/// assert_eq!(add_two(&v), None);
4442
/// ```
4543
pub struct Revocable<T: ?Sized> {
4644
is_available: AtomicBool,

rust/kernel/str.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -213,14 +213,18 @@ impl CStr {
213213
impl fmt::Display for CStr {
214214
/// Formats printable ASCII characters, escaping the rest.
215215
///
216-
/// ```ignore
216+
/// ```
217+
/// # use kernel::prelude::*;
217218
/// # use kernel::c_str;
218219
/// # use kernel::str::CStr;
220+
/// # use kernel::str::CString;
219221
/// let penguin = c_str!("🐧");
220-
/// assert_eq!(format!("{}", penguin), "\\xf0\\x9f\\x90\\xa7");
222+
/// let s = CString::try_from_fmt(fmt!("{}", penguin)).unwrap();
223+
/// assert_eq!(s.as_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes());
221224
///
222225
/// let ascii = c_str!("so \"cool\"");
223-
/// assert_eq!(format!("{}", ascii), "so \"cool\"");
226+
/// let s = CString::try_from_fmt(fmt!("{}", ascii)).unwrap();
227+
/// assert_eq!(s.as_bytes_with_nul(), "so \"cool\"\0".as_bytes());
224228
/// ```
225229
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
226230
for &c in self.as_bytes() {
@@ -238,15 +242,19 @@ impl fmt::Display for CStr {
238242
impl fmt::Debug for CStr {
239243
/// Formats printable ASCII characters with a double quote on either end, escaping the rest.
240244
///
241-
/// ```ignore
245+
/// ```
246+
/// # use kernel::prelude::*;
242247
/// # use kernel::c_str;
243248
/// # use kernel::str::CStr;
249+
/// # use kernel::str::CString;
244250
/// let penguin = c_str!("🐧");
245-
/// assert_eq!(format!("{:?}", penguin), "\"\\xf0\\x9f\\x90\\xa7\"");
251+
/// let s = CString::try_from_fmt(fmt!("{:?}", penguin)).unwrap();
252+
/// assert_eq!(s.as_bytes_with_nul(), "\"\\xf0\\x9f\\x90\\xa7\"\0".as_bytes());
246253
///
247254
/// // embedded double quotes are escaped
248255
/// let ascii = c_str!("so \"cool\"");
249-
/// assert_eq!(format!("{:?}", ascii), "\"so \\\"cool\\\"\"");
256+
/// let s = CString::try_from_fmt(fmt!("{:?}", ascii)).unwrap();
257+
/// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes());
250258
/// ```
251259
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
252260
f.write_str("\"")?;

rust/kernel/sync.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,19 @@
77
//!
88
//! # Example
99
//!
10-
//! ```no_run
10+
//! ```
1111
//! # use kernel::prelude::*;
1212
//! # use kernel::mutex_init;
1313
//! # use kernel::sync::Mutex;
1414
//! # use alloc::boxed::Box;
1515
//! # use core::pin::Pin;
1616
//! // SAFETY: `init` is called below.
17-
//! let mut data = Pin::from(Box::try_new(unsafe { Mutex::new(0) }).unwrap());
17+
//! let mut data = Pin::from(Box::try_new(unsafe { Mutex::new(10) }).unwrap());
1818
//! mutex_init!(data.as_mut(), "test::data");
19-
//! *data.lock() = 10;
20-
//! pr_info!("{}\n", *data.lock());
19+
//!
20+
//! assert_eq!(*data.lock(), 10);
21+
//! *data.lock() = 20;
22+
//! assert_eq!(*data.lock(), 20);
2123
//! ```
2224
2325
use crate::{bindings, str::CStr};

0 commit comments

Comments
 (0)