Skip to content

Commit 1fbde52

Browse files
committed
rust: add macros crate
This crate contains all the procedural macros ("proc macros") shared by all the kernel. Procedural macros allow to create syntax extensions. They run at compile-time and can consume as well as produce Rust syntax. For instance, the `module!` macro that is used by Rust modules is implemented here. It allows to easily declare the equivalent information to the `MODULE_*` macros in C modules, e.g.: module! { type: RustMinimal, name: b"rust_minimal", author: b"Rust for Linux Contributors", description: b"Rust minimal sample", license: b"GPL", } Co-developed-by: Alex Gaynor <[email protected]> Signed-off-by: Alex Gaynor <[email protected]> Co-developed-by: Finn Behrens <[email protected]> Signed-off-by: Finn Behrens <[email protected]> Co-developed-by: Adam Bratschi-Kaye <[email protected]> Signed-off-by: Adam Bratschi-Kaye <[email protected]> Co-developed-by: Wedson Almeida Filho <[email protected]> Signed-off-by: Wedson Almeida Filho <[email protected]> Co-developed-by: Sumera Priyadarsini <[email protected]> Signed-off-by: Sumera Priyadarsini <[email protected]> Co-developed-by: Gary Guo <[email protected]> Signed-off-by: Gary Guo <[email protected]> Co-developed-by: Matthew Bakhtiari <[email protected]> Signed-off-by: Matthew Bakhtiari <[email protected]> Co-developed-by: Björn Roy Baron <[email protected]> Signed-off-by: Björn Roy Baron <[email protected]> Signed-off-by: Miguel Ojeda <[email protected]>
1 parent db958dc commit 1fbde52

File tree

3 files changed

+405
-0
lines changed

3 files changed

+405
-0
lines changed

rust/macros/helpers.rs

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
use proc_macro::{token_stream, TokenTree};
4+
5+
pub(crate) fn try_ident(it: &mut token_stream::IntoIter) -> Option<String> {
6+
if let Some(TokenTree::Ident(ident)) = it.next() {
7+
Some(ident.to_string())
8+
} else {
9+
None
10+
}
11+
}
12+
13+
pub(crate) fn try_literal(it: &mut token_stream::IntoIter) -> Option<String> {
14+
if let Some(TokenTree::Literal(literal)) = it.next() {
15+
Some(literal.to_string())
16+
} else {
17+
None
18+
}
19+
}
20+
21+
pub(crate) fn try_byte_string(it: &mut token_stream::IntoIter) -> Option<String> {
22+
try_literal(it).and_then(|byte_string| {
23+
if byte_string.starts_with("b\"") && byte_string.ends_with('\"') {
24+
Some(byte_string[2..byte_string.len() - 1].to_string())
25+
} else {
26+
None
27+
}
28+
})
29+
}
30+
31+
pub(crate) fn expect_ident(it: &mut token_stream::IntoIter) -> String {
32+
try_ident(it).expect("Expected Ident")
33+
}
34+
35+
pub(crate) fn expect_punct(it: &mut token_stream::IntoIter) -> char {
36+
if let TokenTree::Punct(punct) = it.next().expect("Reached end of token stream for Punct") {
37+
punct.as_char()
38+
} else {
39+
panic!("Expected Punct");
40+
}
41+
}
42+
43+
pub(crate) fn expect_byte_string(it: &mut token_stream::IntoIter) -> String {
44+
try_byte_string(it).expect("Expected byte string")
45+
}
46+
47+
pub(crate) fn expect_end(it: &mut token_stream::IntoIter) {
48+
if it.next().is_some() {
49+
panic!("Expected end");
50+
}
51+
}

rust/macros/lib.rs

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Crate for all kernel procedural macros.
4+
5+
mod helpers;
6+
mod module;
7+
8+
use proc_macro::TokenStream;
9+
10+
/// Declares a kernel module.
11+
///
12+
/// The `type` argument should be a type which implements the [`Module`]
13+
/// trait. Also accepts various forms of kernel metadata.
14+
///
15+
/// C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h)
16+
///
17+
/// [`Module`]: ../kernel/trait.Module.html
18+
///
19+
/// # Examples
20+
///
21+
/// ```ignore
22+
/// use kernel::prelude::*;
23+
///
24+
/// module!{
25+
/// type: MyModule,
26+
/// name: b"my_kernel_module",
27+
/// author: b"Rust for Linux Contributors",
28+
/// description: b"My very own kernel module!",
29+
/// license: b"GPL",
30+
/// params: {
31+
/// my_i32: i32 {
32+
/// default: 42,
33+
/// permissions: 0o000,
34+
/// description: b"Example of i32",
35+
/// },
36+
/// writeable_i32: i32 {
37+
/// default: 42,
38+
/// permissions: 0o644,
39+
/// description: b"Example of i32",
40+
/// },
41+
/// },
42+
/// }
43+
///
44+
/// struct MyModule;
45+
///
46+
/// impl kernel::Module for MyModule {
47+
/// fn init() -> Result<Self> {
48+
/// // If the parameter is writeable, then the kparam lock must be
49+
/// // taken to read the parameter:
50+
/// {
51+
/// let lock = THIS_MODULE.kernel_param_lock();
52+
/// pr_info!("i32 param is: {}\n", writeable_i32.read(&lock));
53+
/// }
54+
/// // If the parameter is read only, it can be read without locking
55+
/// // the kernel parameters:
56+
/// pr_info!("i32 param is: {}\n", my_i32.read());
57+
/// Ok(Self)
58+
/// }
59+
/// }
60+
/// ```
61+
///
62+
/// # Supported argument types
63+
/// - `type`: type which implements the [`Module`] trait (required).
64+
/// - `name`: byte array of the name of the kernel module (required).
65+
/// - `author`: byte array of the author of the kernel module.
66+
/// - `description`: byte array of the description of the kernel module.
67+
/// - `license`: byte array of the license of the kernel module (required).
68+
/// - `alias`: byte array of alias name of the kernel module.
69+
#[proc_macro]
70+
pub fn module(ts: TokenStream) -> TokenStream {
71+
module::module(ts)
72+
}

0 commit comments

Comments
 (0)