Commit 5d840b4c authored by Tamir Duberstein's avatar Tamir Duberstein Committed by Miguel Ojeda
Browse files

rust: list: add `impl_list_item!` examples



There's a comprehensive example in `rust/kernel/list.rs` but it doesn't
exercise the `using ListLinksSelfPtr` variant nor the generic cases. Add
that here. Generalize `impl_has_list_links_self_ptr` to handle nested
fields in the same manner as `impl_has_list_links`.

Tested-by: default avatarAlice Ryhl <aliceryhl@google.com>
Reviewed-by: default avatarAlice Ryhl <aliceryhl@google.com>
Signed-off-by: default avatarTamir Duberstein <tamird@gmail.com>
Link: https://lore.kernel.org/r/20250709-list-no-offset-v4-5-a429e75840a9@gmail.com


[ Fixed Rust < 1.82 build by enabling the `offset_of_nested`
  feature. - Miguel ]
Signed-off-by: default avatarMiguel Ojeda <ojeda@kernel.org>
parent 6a13057d
Loading
Loading
Loading
Loading
+93 −3
Original line number Diff line number Diff line
@@ -82,20 +82,20 @@ macro_rules! impl_has_list_links_self_ptr {
    ($(impl$({$($generics:tt)*})?
       HasSelfPtr<$item_type:ty $(, $id:tt)?>
       for $self:ty
       { self.$field:ident }
       { self$(.$field:ident)* }
    )*) => {$(
        // SAFETY: The implementation of `raw_get_list_links` only compiles if the field has the
        // right type.
        unsafe impl$(<$($generics)*>)? $crate::list::HasSelfPtr<$item_type $(, $id)?> for $self {}

        unsafe impl$(<$($generics)*>)? $crate::list::HasListLinks$(<$id>)? for $self {
            const OFFSET: usize = ::core::mem::offset_of!(Self, $field) as usize;
            const OFFSET: usize = ::core::mem::offset_of!(Self, $($field).*) as usize;

            #[inline]
            unsafe fn raw_get_list_links(ptr: *mut Self) -> *mut $crate::list::ListLinks$(<$id>)? {
                // SAFETY: The caller promises that the pointer is not dangling.
                let ptr: *mut $crate::list::ListLinksSelfPtr<$item_type $(, $id)?> =
                    unsafe { ::core::ptr::addr_of_mut!((*ptr).$field) };
                    unsafe { ::core::ptr::addr_of_mut!((*ptr)$(.$field)*) };
                ptr.cast()
            }
        }
@@ -109,6 +109,96 @@ unsafe fn raw_get_list_links(ptr: *mut Self) -> *mut $crate::list::ListLinks$(<$
/// implement that trait.
///
/// [`ListItem`]: crate::list::ListItem
///
/// # Examples
///
/// ```
/// #[pin_data]
/// struct SimpleListItem {
///     value: u32,
///     #[pin]
///     links: kernel::list::ListLinks,
/// }
///
/// kernel::list::impl_has_list_links! {
///     impl HasListLinks<0> for SimpleListItem { self.links }
/// }
///
/// kernel::list::impl_list_arc_safe! {
///     impl ListArcSafe<0> for SimpleListItem { untracked; }
/// }
///
/// kernel::list::impl_list_item! {
///     impl ListItem<0> for SimpleListItem { using ListLinks; }
/// }
///
/// struct ListLinksHolder {
///     inner: kernel::list::ListLinks,
/// }
///
/// #[pin_data]
/// struct ComplexListItem<T, U> {
///     value: Result<T, U>,
///     #[pin]
///     links: ListLinksHolder,
/// }
///
/// kernel::list::impl_has_list_links! {
///     impl{T, U} HasListLinks<0> for ComplexListItem<T, U> { self.links.inner }
/// }
///
/// kernel::list::impl_list_arc_safe! {
///     impl{T, U} ListArcSafe<0> for ComplexListItem<T, U> { untracked; }
/// }
///
/// kernel::list::impl_list_item! {
///     impl{T, U} ListItem<0> for ComplexListItem<T, U> { using ListLinks; }
/// }
/// ```
///
/// ```
/// #[pin_data]
/// struct SimpleListItem {
///     value: u32,
///     #[pin]
///     links: kernel::list::ListLinksSelfPtr<SimpleListItem>,
/// }
///
/// kernel::list::impl_list_arc_safe! {
///     impl ListArcSafe<0> for SimpleListItem { untracked; }
/// }
///
/// kernel::list::impl_has_list_links_self_ptr! {
///     impl HasSelfPtr<SimpleListItem> for SimpleListItem { self.links }
/// }
///
/// kernel::list::impl_list_item! {
///     impl ListItem<0> for SimpleListItem { using ListLinksSelfPtr; }
/// }
///
/// struct ListLinksSelfPtrHolder<T, U> {
///     inner: kernel::list::ListLinksSelfPtr<ComplexListItem<T, U>>,
/// }
///
/// #[pin_data]
/// struct ComplexListItem<T, U> {
///     value: Result<T, U>,
///     #[pin]
///     links: ListLinksSelfPtrHolder<T, U>,
/// }
///
/// kernel::list::impl_list_arc_safe! {
///     impl{T, U} ListArcSafe<0> for ComplexListItem<T, U> { untracked; }
/// }
///
/// kernel::list::impl_has_list_links_self_ptr! {
///     impl{T, U} HasSelfPtr<ComplexListItem<T, U>> for ComplexListItem<T, U> { self.links.inner }
/// }
///
/// kernel::list::impl_list_item! {
///     impl{T, U} ListItem<0> for ComplexListItem<T, U> { using ListLinksSelfPtr; }
/// }
/// ```
#[macro_export]
macro_rules! impl_list_item {
    (
+3 −2
Original line number Diff line number Diff line
@@ -309,13 +309,14 @@ $(obj)/%.lst: $(obj)/%.c FORCE
# The features in this list are the ones allowed for non-`rust/` code.
#
#   - Stable since Rust 1.81.0: `feature(lint_reasons)`.
#   - Stable since Rust 1.82.0: `feature(asm_const)`, `feature(raw_ref_op)`.
#   - Stable since Rust 1.82.0: `feature(asm_const)`,
#     `feature(offset_of_nested)`, `feature(raw_ref_op)`.
#   - Stable since Rust 1.87.0: `feature(asm_goto)`.
#   - Expected to become stable: `feature(arbitrary_self_types)`.
#
# Please see https://github.com/Rust-for-Linux/linux/issues/2 for details on
# the unstable features in use.
rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,lint_reasons,raw_ref_op
rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,lint_reasons,offset_of_nested,raw_ref_op

# `--out-dir` is required to avoid temporaries being created by `rustc` in the
# current working directory, which may be not accessible in the out-of-tree