mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 04:33:26 +02:00
rust: init: add initialization macros
Add the following initializer macros: - `#[pin_data]` to annotate structurally pinned fields of structs, needed for `pin_init!` and `try_pin_init!` to select the correct initializer of fields. - `pin_init!` create a pin-initializer for a struct with the `Infallible` error type. - `try_pin_init!` create a pin-initializer for a struct with a custom error type (`kernel::error::Error` is the default). - `init!` create an in-place-initializer for a struct with the `Infallible` error type. - `try_init!` create an in-place-initializer for a struct with a custom error type (`kernel::error::Error` is the default). Also add their needed internal helper traits and structs. Co-developed-by: Gary Guo <gary@garyguo.net> Signed-off-by: Gary Guo <gary@garyguo.net> Signed-off-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Andreas Hindborg <a.hindborg@samsung.com> Link: https://lore.kernel.org/r/20230408122429.1103522-8-y86-dev@protonmail.com [ Fixed three typos. ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
committed by
Miguel Ojeda
parent
90e53c5e70
commit
fc6c6baa1f
@@ -7,6 +7,7 @@ mod quote;
|
||||
mod concat_idents;
|
||||
mod helpers;
|
||||
mod module;
|
||||
mod pin_data;
|
||||
mod vtable;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
@@ -168,3 +169,31 @@ pub fn vtable(attr: TokenStream, ts: TokenStream) -> TokenStream {
|
||||
pub fn concat_idents(ts: TokenStream) -> TokenStream {
|
||||
concat_idents::concat_idents(ts)
|
||||
}
|
||||
|
||||
/// Used to specify the pinning information of the fields of a struct.
|
||||
///
|
||||
/// This is somewhat similar in purpose as
|
||||
/// [pin-project-lite](https://crates.io/crates/pin-project-lite).
|
||||
/// Place this macro on a struct definition and then `#[pin]` in front of the attributes of each
|
||||
/// field you want to structurally pin.
|
||||
///
|
||||
/// This macro enables the use of the [`pin_init!`] macro. When pin-initializing a `struct`,
|
||||
/// then `#[pin]` directs the type of initializer that is required.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// #[pin_data]
|
||||
/// struct DriverData {
|
||||
/// #[pin]
|
||||
/// queue: Mutex<Vec<Command>>,
|
||||
/// buf: Box<[u8; 1024 * 1024]>,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [`pin_init!`]: ../kernel/macro.pin_init.html
|
||||
// ^ cannot use direct link, since `kernel` is not a dependency of `macros`.
|
||||
#[proc_macro_attribute]
|
||||
pub fn pin_data(inner: TokenStream, item: TokenStream) -> TokenStream {
|
||||
pin_data::pin_data(inner, item)
|
||||
}
|
||||
|
79
rust/macros/pin_data.rs
Normal file
79
rust/macros/pin_data.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
use proc_macro::{Punct, Spacing, TokenStream, TokenTree};
|
||||
|
||||
pub(crate) fn pin_data(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
// This proc-macro only does some pre-parsing and then delegates the actual parsing to
|
||||
// `kernel::__pin_data!`.
|
||||
//
|
||||
// In here we only collect the generics, since parsing them in declarative macros is very
|
||||
// elaborate. We also do not need to analyse their structure, we only need to collect them.
|
||||
|
||||
// `impl_generics`, the declared generics with their bounds.
|
||||
let mut impl_generics = vec![];
|
||||
// Only the names of the generics, without any bounds.
|
||||
let mut ty_generics = vec![];
|
||||
// Tokens not related to the generics e.g. the `impl` token.
|
||||
let mut rest = vec![];
|
||||
// The current level of `<`.
|
||||
let mut nesting = 0;
|
||||
let mut toks = input.into_iter();
|
||||
// If we are at the beginning of a generic parameter.
|
||||
let mut at_start = true;
|
||||
for tt in &mut toks {
|
||||
match tt.clone() {
|
||||
TokenTree::Punct(p) if p.as_char() == '<' => {
|
||||
if nesting >= 1 {
|
||||
impl_generics.push(tt);
|
||||
}
|
||||
nesting += 1;
|
||||
}
|
||||
TokenTree::Punct(p) if p.as_char() == '>' => {
|
||||
if nesting == 0 {
|
||||
break;
|
||||
} else {
|
||||
nesting -= 1;
|
||||
if nesting >= 1 {
|
||||
impl_generics.push(tt);
|
||||
}
|
||||
if nesting == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
tt => {
|
||||
if nesting == 1 {
|
||||
match &tt {
|
||||
TokenTree::Ident(i) if i.to_string() == "const" => {}
|
||||
TokenTree::Ident(_) if at_start => {
|
||||
ty_generics.push(tt.clone());
|
||||
ty_generics.push(TokenTree::Punct(Punct::new(',', Spacing::Alone)));
|
||||
at_start = false;
|
||||
}
|
||||
TokenTree::Punct(p) if p.as_char() == ',' => at_start = true,
|
||||
TokenTree::Punct(p) if p.as_char() == '\'' && at_start => {
|
||||
ty_generics.push(tt.clone());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if nesting >= 1 {
|
||||
impl_generics.push(tt);
|
||||
} else if nesting == 0 {
|
||||
rest.push(tt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rest.extend(toks);
|
||||
// This should be the body of the struct `{...}`.
|
||||
let last = rest.pop();
|
||||
quote!(::kernel::__pin_data! {
|
||||
parse_input:
|
||||
@args(#args),
|
||||
@sig(#(#rest)*),
|
||||
@impl_generics(#(#impl_generics)*),
|
||||
@ty_generics(#(#ty_generics)*),
|
||||
@body(#last),
|
||||
})
|
||||
}
|
@@ -38,7 +38,6 @@ impl ToTokens for TokenStream {
|
||||
/// This is a similar to the
|
||||
/// [`quote_spanned!`](https://docs.rs/quote/latest/quote/macro.quote_spanned.html) macro from the
|
||||
/// `quote` crate but provides only just enough functionality needed by the current `macros` crate.
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! quote_spanned {
|
||||
($span:expr => $($tt:tt)*) => {
|
||||
#[allow(clippy::vec_init_then_push)]
|
||||
@@ -137,7 +136,6 @@ macro_rules! quote_spanned {
|
||||
/// `macros` crate.
|
||||
///
|
||||
/// [`Span::mixed_site()`]: https://doc.rust-lang.org/proc_macro/struct.Span.html#method.mixed_site
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! quote {
|
||||
($($tt:tt)*) => {
|
||||
quote_spanned!(::proc_macro::Span::mixed_site() => $($tt)*)
|
||||
|
Reference in New Issue
Block a user