mirror of
https://github.com/torvalds/linux.git
synced 2024-11-15 00:21:59 +00:00
fc6c6baa1f
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>
80 lines
2.9 KiB
Rust
80 lines
2.9 KiB
Rust
// 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),
|
|
})
|
|
}
|