2024-08-14 08:05:29 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
|
|
|
|
// Copyright (C) 2024 Google LLC.
|
|
|
|
|
|
|
|
//! A field that is exclusively owned by a [`ListArc`].
|
|
|
|
//!
|
|
|
|
//! This can be used to have reference counted struct where one of the reference counted pointers
|
|
|
|
//! has exclusive access to a field of the struct.
|
|
|
|
//!
|
|
|
|
//! [`ListArc`]: crate::list::ListArc
|
|
|
|
|
|
|
|
use core::cell::UnsafeCell;
|
|
|
|
|
|
|
|
/// A field owned by a specific [`ListArc`].
|
|
|
|
///
|
|
|
|
/// [`ListArc`]: crate::list::ListArc
|
|
|
|
pub struct ListArcField<T, const ID: u64 = 0> {
|
|
|
|
value: UnsafeCell<T>,
|
|
|
|
}
|
|
|
|
|
|
|
|
// SAFETY: If the inner type is thread-safe, then it's also okay for `ListArc` to be thread-safe.
|
|
|
|
unsafe impl<T: Send + Sync, const ID: u64> Send for ListArcField<T, ID> {}
|
|
|
|
// SAFETY: If the inner type is thread-safe, then it's also okay for `ListArc` to be thread-safe.
|
|
|
|
unsafe impl<T: Send + Sync, const ID: u64> Sync for ListArcField<T, ID> {}
|
|
|
|
|
|
|
|
impl<T, const ID: u64> ListArcField<T, ID> {
|
|
|
|
/// Creates a new `ListArcField`.
|
|
|
|
pub fn new(value: T) -> Self {
|
|
|
|
Self {
|
|
|
|
value: UnsafeCell::new(value),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Access the value when we have exclusive access to the `ListArcField`.
|
|
|
|
///
|
|
|
|
/// This allows access to the field using an `UniqueArc` instead of a `ListArc`.
|
|
|
|
pub fn get_mut(&mut self) -> &mut T {
|
|
|
|
self.value.get_mut()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Unsafely assert that you have shared access to the `ListArc` for this field.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// The caller must have shared access to the `ListArc<ID>` containing the struct with this
|
|
|
|
/// field for the duration of the returned reference.
|
|
|
|
pub unsafe fn assert_ref(&self) -> &T {
|
|
|
|
// SAFETY: The caller has shared access to the `ListArc`, so they also have shared access
|
|
|
|
// to this field.
|
|
|
|
unsafe { &*self.value.get() }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Unsafely assert that you have mutable access to the `ListArc` for this field.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// The caller must have mutable access to the `ListArc<ID>` containing the struct with this
|
|
|
|
/// field for the duration of the returned reference.
|
rust: start using the `#[expect(...)]` attribute
In Rust, it is possible to `allow` particular warnings (diagnostics,
lints) locally, making the compiler ignore instances of a given warning
within a given function, module, block, etc.
It is similar to `#pragma GCC diagnostic push` + `ignored` + `pop` in C:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
static void f(void) {}
#pragma GCC diagnostic pop
But way less verbose:
#[allow(dead_code)]
fn f() {}
By that virtue, it makes it possible to comfortably enable more
diagnostics by default (i.e. outside `W=` levels) that may have some
false positives but that are otherwise quite useful to keep enabled to
catch potential mistakes.
The `#[expect(...)]` attribute [1] takes this further, and makes the
compiler warn if the diagnostic was _not_ produced. For instance, the
following will ensure that, when `f()` is called somewhere, we will have
to remove the attribute:
#[expect(dead_code)]
fn f() {}
If we do not, we get a warning from the compiler:
warning: this lint expectation is unfulfilled
--> x.rs:3:10
|
3 | #[expect(dead_code)]
| ^^^^^^^^^
|
= note: `#[warn(unfulfilled_lint_expectations)]` on by default
This means that `expect`s do not get forgotten when they are not needed.
See the next commit for more details, nuances on its usage and
documentation on the feature.
The attribute requires the `lint_reasons` [2] unstable feature, but it
is becoming stable in 1.81.0 (to be released on 2024-09-05) and it has
already been useful to clean things up in this patch series, finding
cases where the `allow`s should not have been there.
Thus, enable `lint_reasons` and convert some of our `allow`s to `expect`s
where possible.
This feature was also an example of the ongoing collaboration between
Rust and the kernel -- we tested it in the kernel early on and found an
issue that was quickly resolved [3].
Cc: Fridtjof Stoldt <xfrednet@gmail.com>
Cc: Urgau <urgau@numericable.fr>
Link: https://rust-lang.github.io/rfcs/2383-lint-reasons.html#expect-lint-attribute [1]
Link: https://github.com/rust-lang/rust/issues/54503 [2]
Link: https://github.com/rust-lang/rust/issues/114557 [3]
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Trevor Gross <tmgross@umich.edu>
Tested-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Gary Guo <gary@garyguo.net>
Link: https://lore.kernel.org/r/20240904204347.168520-18-ojeda@kernel.org
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-09-04 22:43:45 +02:00
|
|
|
#[expect(clippy::mut_from_ref)]
|
2024-08-14 08:05:29 +00:00
|
|
|
pub unsafe fn assert_mut(&self) -> &mut T {
|
|
|
|
// SAFETY: The caller has exclusive access to the `ListArc`, so they also have exclusive
|
|
|
|
// access to this field.
|
|
|
|
unsafe { &mut *self.value.get() }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Defines getters for a [`ListArcField`].
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! define_list_arc_field_getter {
|
|
|
|
($pub:vis fn $name:ident(&self $(<$id:tt>)?) -> &$typ:ty { $field:ident }
|
|
|
|
$($rest:tt)*
|
|
|
|
) => {
|
|
|
|
$pub fn $name<'a>(self: &'a $crate::list::ListArc<Self $(, $id)?>) -> &'a $typ {
|
|
|
|
let field = &(&**self).$field;
|
|
|
|
// SAFETY: We have a shared reference to the `ListArc`.
|
|
|
|
unsafe { $crate::list::ListArcField::<$typ $(, $id)?>::assert_ref(field) }
|
|
|
|
}
|
|
|
|
|
|
|
|
$crate::list::define_list_arc_field_getter!($($rest)*);
|
|
|
|
};
|
|
|
|
|
|
|
|
($pub:vis fn $name:ident(&mut self $(<$id:tt>)?) -> &mut $typ:ty { $field:ident }
|
|
|
|
$($rest:tt)*
|
|
|
|
) => {
|
|
|
|
$pub fn $name<'a>(self: &'a mut $crate::list::ListArc<Self $(, $id)?>) -> &'a mut $typ {
|
|
|
|
let field = &(&**self).$field;
|
|
|
|
// SAFETY: We have a mutable reference to the `ListArc`.
|
|
|
|
unsafe { $crate::list::ListArcField::<$typ $(, $id)?>::assert_mut(field) }
|
|
|
|
}
|
|
|
|
|
|
|
|
$crate::list::define_list_arc_field_getter!($($rest)*);
|
|
|
|
};
|
|
|
|
|
|
|
|
() => {};
|
|
|
|
}
|
|
|
|
pub use define_list_arc_field_getter;
|