Skip to content

Add XArray abstraction #1019

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 37 commits into
base: rust-dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
520a56a
rust: allocator: Prevents mis-aligned allocation
fbq Jun 13, 2023
3d8d9bc
rust: make `UnsafeCell` the outer type in `Opaque`
Darksonn Jun 14, 2023
7671527
rust: types: make `Opaque` be `!Unpin`
y86-dev Jun 30, 2023
0ad204c
kbuild: rust_is_available: remove -v option
masahir0y Jun 16, 2023
70a61eb
kbuild: rust_is_available: fix version check when CC has multiple arg…
ruscur Jun 16, 2023
a250bde
docs: rust: add paragraph about finding a suitable `libclang`
ojeda Jun 16, 2023
00383f7
kbuild: rust_is_available: print docs reference
ojeda Jun 16, 2023
8b2e73a
kbuild: rust_is_available: add check for `bindgen` invocation
ojeda Jun 16, 2023
eb9199d
kbuild: rust_is_available: check that environment variables are set
ojeda Jun 16, 2023
6bed841
kbuild: rust_is_available: fix confusion when a version appears in th…
ojeda Jun 16, 2023
600eb66
kbuild: rust_is_available: normalize version matching
ojeda Jun 16, 2023
6d4220b
kbuild: rust_is_available: handle failures calling `$RUSTC`/`$BINDGEN`
ojeda Jun 16, 2023
10452fc
kbuild: rust_is_available: check that output looks as expected
ojeda Jun 16, 2023
6a4e6dc
kbuild: rust_is_available: add test suite
ojeda Jun 16, 2023
f2f2787
rust: alloc: Add realloc and alloc_zeroed to the GlobalAlloc impl
fbq Jun 25, 2023
53dd54f
rust: bindgen: upgrade to 0.65.1
Shinyzenith Jun 12, 2023
02ddf5a
rust: init: make doctests compilable/testable
ojeda Jun 14, 2023
276f14d
rust: str: make doctests compilable/testable
ojeda Jun 14, 2023
c30db85
rust: sync: make doctests compilable/testable
ojeda Jun 14, 2023
4009de1
rust: types: make doctests compilable/testable
ojeda Jun 14, 2023
e9e95cd
rust: support running Rust documentation tests as KUnit ones
ojeda Jun 14, 2023
eff7a66
MAINTAINERS: add Rust KUnit files to the KUnit entry
ojeda Jun 14, 2023
72fbe4a
rust: macros: fix redefine const_name in `vtable`
cqs21 Jun 26, 2023
8e87a0d
rust: macros: add `paste!` proc macro
nbdd0121 Jun 28, 2023
7c6e564
arm64: rust: Enable Rust support for AArch64
JamieCunliffe Jun 6, 2023
522ba05
arm64: rust: Enable PAC support for Rust.
JamieCunliffe Jun 6, 2023
b1555e1
arm64: Restrict Rust support to little endian only.
JamieCunliffe Jun 6, 2023
19b33fc
rust: bindgen: update installation instructions
matthewtgilbride Jun 29, 2023
c1c510f
rust: xarray: Add an abstraction for XArray
asahilina Jun 27, 2023
91f4147
rust: xarray: add rudimentary doctest
matthewtgilbride Jun 27, 2023
6c19acb
rust: xarray: add `get_mutable` and `find_mut`
matthewtgilbride Jun 27, 2023
3016eac
rust: xarray: add reservation mechanism
asahilina Jun 27, 2023
90ddba2
Why does this cuase NULL pointer dereference?
matthewtgilbride Jul 2, 2023
702746d
Just me thrashing about - figuring out NPE
matthewtgilbride Jul 4, 2023
976067b
rust: delete `ForeignOwnable::borrow_mut`
Darksonn Jul 6, 2023
ac520c2
rust: add improved version of `ForeignOwnable::borrow_mut`
Darksonn Jul 10, 2023
642ff49
rust: xarray: figure out pin and get_scoped
matthewtgilbride Jul 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
rust: macros: add paste! proc macro
This macro provides a flexible way to concatenated identifiers together
and it allows the resulting identifier to be used to declare new items,
which `concat_idents!` does not allow. It also allows identifiers to be
transformed before concatenated.

The `concat_idents!` example

    let x_1 = 42;
    let x_2 = concat_idents!(x, _1);
    assert!(x_1 == x_2);

can be written with `paste!` macro like this:

    let x_1 = 42;
    let x_2 = paste!([<x _1>]);
    assert!(x_1 == x_2);

However `paste!` macro is more flexible because it can be used to create
a new variable:

    let x_1 = 42;
    paste!(let [<x _2>] = [<x _1>];);
    assert!(x_1 == x_2);

While this is not possible with `concat_idents!`.

This macro is similar to the `paste!` crate [1], but this is a fresh
implementation to avoid vendoring large amount of code directly. Also, I
have augmented it to provide a way to specify span of the resulting
token, allowing precise control.

For example, this code is broken because the variable is declared inside
the macro, so Rust macro hygiene rules prevents access from the outside:

    macro_rules! m {
        ($id: ident) => {
            // The resulting token has hygiene of the macro.
            paste!(let [<$id>] = 1;)
        }
    }

    m!(a);
    let _ = a;

In this versionn of `paste!` macro I added a `span` modifier to allow
this:

    macro_rules! m {
        ($id: ident) => {
            // The resulting token has hygiene of `$id`.
            paste!(let [<$id:span>] = 1;)
        }
    }

    m!(a);
    let _ = a;

Link: http://docs.rs/paste/ [1]
Signed-off-by: Gary Guo <[email protected]>
Reviewed-by: Björn Roy Baron <[email protected]>
Reviewed-by: Benno Lossin <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
  • Loading branch information
nbdd0121 authored and fbq committed Jun 30, 2023
commit 8e87a0dffe01b5d15ef37496ea3191a0b8eeb4d7
97 changes: 97 additions & 0 deletions rust/macros/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mod quote;
mod concat_idents;
mod helpers;
mod module;
mod paste;
mod pin_data;
mod pinned_drop;
mod vtable;
Expand Down Expand Up @@ -246,3 +247,99 @@ pub fn pin_data(inner: TokenStream, item: TokenStream) -> TokenStream {
pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
pinned_drop::pinned_drop(args, input)
}

/// Paste identifiers together.
///
/// Within the `paste!` macro, identifiers inside `[<` and `>]` are concatenated together to form a
/// single identifier.
///
/// This is similar to the [`paste`] crate, but with pasting feature limited to identifiers
/// (literals, lifetimes and documentation strings are not supported). There is a difference in
/// supported modifiers as well.
///
/// # Example
///
/// ```ignore
/// use kernel::macro::paste;
///
/// macro_rules! pub_no_prefix {
/// ($prefix:ident, $($newname:ident),+) => {
/// paste! {
/// $(pub(crate) const $newname: u32 = [<$prefix $newname>];)+
/// }
/// };
/// }
///
/// pub_no_prefix!(
/// binder_driver_return_protocol_,
/// BR_OK,
/// BR_ERROR,
/// BR_TRANSACTION,
/// BR_REPLY,
/// BR_DEAD_REPLY,
/// BR_TRANSACTION_COMPLETE,
/// BR_INCREFS,
/// BR_ACQUIRE,
/// BR_RELEASE,
/// BR_DECREFS,
/// BR_NOOP,
/// BR_SPAWN_LOOPER,
/// BR_DEAD_BINDER,
/// BR_CLEAR_DEATH_NOTIFICATION_DONE,
/// BR_FAILED_REPLY
/// );
///
/// assert_eq!(BR_OK, binder_driver_return_protocol_BR_OK);
/// ```
///
/// # Modifiers
///
/// For each identifier, it is possible to attach one or multiple modifiers to
/// it.
///
/// Currently supported modifiers are:
/// * `span`: change the span of concatenated identifier to the span of the specified token. By
/// default the span of the `[< >]` group is used.
/// * `lower`: change the identifier to lower case.
/// * `upper`: change the identifier to upper case.
///
/// ```ignore
/// use kernel::macro::paste;
///
/// macro_rules! pub_no_prefix {
/// ($prefix:ident, $($newname:ident),+) => {
/// kernel::macros::paste! {
/// $(pub(crate) const fn [<$newname:lower:span>]: u32 = [<$prefix $newname:span>];)+
/// }
/// };
/// }
///
/// pub_no_prefix!(
/// binder_driver_return_protocol_,
/// BR_OK,
/// BR_ERROR,
/// BR_TRANSACTION,
/// BR_REPLY,
/// BR_DEAD_REPLY,
/// BR_TRANSACTION_COMPLETE,
/// BR_INCREFS,
/// BR_ACQUIRE,
/// BR_RELEASE,
/// BR_DECREFS,
/// BR_NOOP,
/// BR_SPAWN_LOOPER,
/// BR_DEAD_BINDER,
/// BR_CLEAR_DEATH_NOTIFICATION_DONE,
/// BR_FAILED_REPLY
/// );
///
/// assert_eq!(br_ok(), binder_driver_return_protocol_BR_OK);
/// ```
///
/// [`paste`]: https://docs.rs/paste/
#[proc_macro]
pub fn paste(input: TokenStream) -> TokenStream {
let mut tokens = input.into_iter().collect();
paste::expand(&mut tokens);
tokens.into_iter().collect()
}
94 changes: 94 additions & 0 deletions rust/macros/paste.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use proc_macro::{Delimiter, Group, Ident, Spacing, Span, TokenTree};

fn concat(tokens: &[TokenTree], group_span: Span) -> TokenTree {
let mut tokens = tokens.iter();
let mut segments = Vec::new();
let mut span = None;
loop {
match tokens.next() {
None => break,
Some(TokenTree::Literal(lit)) => segments.push((lit.to_string(), lit.span())),
Some(TokenTree::Ident(ident)) => {
let mut value = ident.to_string();
if value.starts_with("r#") {
value.replace_range(0..2, "");
}
segments.push((value, ident.span()));
}
Some(TokenTree::Punct(p)) if p.as_char() == ':' => {
let Some(TokenTree::Ident(ident)) = tokens.next() else {
panic!("expected identifier as modifier");
};

let (mut value, sp) = segments.pop().expect("expected identifier before modifier");
match ident.to_string().as_str() {
// Set the overall span of concatenated token as current span
"span" => {
assert!(
span.is_none(),
"span modifier should only appear at most once"
);
span = Some(sp);
}
"lower" => value = value.to_lowercase(),
"upper" => value = value.to_uppercase(),
v => panic!("unknown modifier `{v}`"),
};
segments.push((value, sp));
}
_ => panic!("unexpected token in paste segments"),
};
}

let pasted: String = segments.into_iter().map(|x| x.0).collect();
TokenTree::Ident(Ident::new(&pasted, span.unwrap_or(group_span)))
}

pub(crate) fn expand(tokens: &mut Vec<TokenTree>) {
for token in tokens.iter_mut() {
if let TokenTree::Group(group) = token {
let delimiter = group.delimiter();
let span = group.span();
let mut stream: Vec<_> = group.stream().into_iter().collect();
// Find groups that looks like `[< A B C D >]`
if delimiter == Delimiter::Bracket
&& stream.len() >= 3
&& matches!(&stream[0], TokenTree::Punct(p) if p.as_char() == '<')
&& matches!(&stream[stream.len() - 1], TokenTree::Punct(p) if p.as_char() == '>')
{
// Replace the group with concatenated token
*token = concat(&stream[1..stream.len() - 1], span);
} else {
// Recursively expand tokens inside the group
expand(&mut stream);
let mut group = Group::new(delimiter, stream.into_iter().collect());
group.set_span(span);
*token = TokenTree::Group(group);
}
}
}

// Path segments cannot contain invisible delimiter group, so remove them if any.
for i in (0..tokens.len().saturating_sub(3)).rev() {
// Looking for a double colon
if matches!(
(&tokens[i + 1], &tokens[i + 2]),
(TokenTree::Punct(a), TokenTree::Punct(b))
if a.as_char() == ':' && a.spacing() == Spacing::Joint && b.as_char() == ':'
) {
match &tokens[i + 3] {
TokenTree::Group(group) if group.delimiter() == Delimiter::None => {
tokens.splice(i + 3..i + 4, group.stream());
}
_ => (),
}

match &tokens[i] {
TokenTree::Group(group) if group.delimiter() == Delimiter::None => {
tokens.splice(i..i + 1, group.stream());
}
_ => (),
}
}
}
}