// SPDX-License-Identifier: GPL-2.0 //! Kernel types. use alloc::boxed::Box; use core::{ cell::UnsafeCell, mem::MaybeUninit, ops::{Deref, DerefMut}, }; /// Used to transfer ownership to and from foreign (non-Rust) languages. /// /// Ownership is transferred from Rust to a foreign language by calling [`Self::into_foreign`] and /// later may be transferred back to Rust by calling [`Self::from_foreign`]. /// /// This trait is meant to be used in cases when Rust objects are stored in C objects and /// eventually "freed" back to Rust. pub trait ForeignOwnable: Sized { /// Type of values borrowed between calls to [`ForeignOwnable::into_foreign`] and /// [`ForeignOwnable::from_foreign`]. type Borrowed<'a>; /// Converts a Rust-owned object to a foreign-owned one. /// /// The foreign representation is a pointer to void. fn into_foreign(self) -> *const core::ffi::c_void; /// Borrows a foreign-owned object. /// /// # Safety /// /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow_mut`] /// for this object must have been dropped. unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a>; /// Mutably borrows a foreign-owned object. /// /// # Safety /// /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. unsafe fn borrow_mut(ptr: *const core::ffi::c_void) -> ScopeGuard { // SAFETY: The safety requirements ensure that `ptr` came from a previous call to // `into_foreign`. ScopeGuard::new_with_data(unsafe { Self::from_foreign(ptr) }, |d| { d.into_foreign(); }) } /// Converts a foreign-owned object back to a Rust-owned one. /// /// # Safety /// /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] and /// [`ForeignOwnable::borrow_mut`] for this object must have been dropped. unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self; } impl ForeignOwnable for Box { type Borrowed<'a> = &'a T; fn into_foreign(self) -> *const core::ffi::c_void { Box::into_raw(self) as _ } unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> &'a T { // SAFETY: The safety requirements for this function ensure that the object is still alive, // so it is safe to dereference the raw pointer. // The safety requirements of `from_foreign` also ensure that the object remains alive for // the lifetime of the returned value. unsafe { &*ptr.cast() } } unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. unsafe { Box::from_raw(ptr as _) } } } impl ForeignOwnable for () { type Borrowed<'a> = (); fn into_foreign(self) -> *const core::ffi::c_void { core::ptr::NonNull::dangling().as_ptr() } unsafe fn borrow<'a>(_: *const core::ffi::c_void) -> Self::Borrowed<'a> {} unsafe fn from_foreign(_: *const core::ffi::c_void) -> Self {} } /// Runs a cleanup function/closure when dropped. /// /// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running. /// /// # Examples /// /// In the example below, we have multiple exit paths and we want to log regardless of which one is /// taken: /// ``` /// # use kernel::ScopeGuard; /// fn example1(arg: bool) { /// let _log = ScopeGuard::new(|| pr_info!("example1 completed\n")); /// /// if arg { /// return; /// } /// /// pr_info!("Do something...\n"); /// } /// /// # example1(false); /// # example1(true); /// ``` /// /// In the example below, we want to log the same message on all early exits but a different one on /// the main exit path: /// ``` /// # use kernel::ScopeGuard; /// fn example2(arg: bool) { /// let log = ScopeGuard::new(|| pr_info!("example2 returned early\n")); /// /// if arg { /// return; /// } /// /// // (Other early returns...) /// /// log.dismiss(); /// pr_info!("example2 no early return\n"); /// } /// /// # example2(false); /// # example2(true); /// ``` /// /// In the example below, we need a mutable object (the vector) to be accessible within the log /// function, so we wrap it in the [`ScopeGuard`]: /// ``` /// # use kernel::ScopeGuard; /// fn example3(arg: bool) -> Result { /// let mut vec = /// ScopeGuard::new_with_data(Vec::new(), |v| pr_info!("vec had {} elements\n", v.len())); /// /// vec.try_push(10u8)?; /// if arg { /// return Ok(()); /// } /// vec.try_push(20u8)?; /// Ok(()) /// } /// /// # assert_eq!(example3(false), Ok(())); /// # assert_eq!(example3(true), Ok(())); /// ``` /// /// # Invariants /// /// The value stored in the struct is nearly always `Some(_)`, except between /// [`ScopeGuard::dismiss`] and [`ScopeGuard::drop`]: in this case, it will be `None` as the value /// will have been returned to the caller. Since [`ScopeGuard::dismiss`] consumes the guard, /// callers won't be able to use it anymore. pub struct ScopeGuard(Option<(T, F)>); impl ScopeGuard { /// Creates a new guarded object wrapping the given data and with the given cleanup function. pub fn new_with_data(data: T, cleanup_func: F) -> Self { // INVARIANT: The struct is being initialised with `Some(_)`. Self(Some((data, cleanup_func))) } /// Prevents the cleanup function from running and returns the guarded data. pub fn dismiss(mut self) -> T { // INVARIANT: This is the exception case in the invariant; it is not visible to callers // because this function consumes `self`. self.0.take().unwrap().0 } } impl ScopeGuard<(), fn(())> { /// Creates a new guarded object with the given cleanup function. pub fn new(cleanup: impl FnOnce()) -> ScopeGuard<(), impl FnOnce(())> { ScopeGuard::new_with_data((), move |_| cleanup()) } } impl Deref for ScopeGuard { type Target = T; fn deref(&self) -> &T { // The type invariants guarantee that `unwrap` will succeed. &self.0.as_ref().unwrap().0 } } impl DerefMut for ScopeGuard { fn deref_mut(&mut self) -> &mut T { // The type invariants guarantee that `unwrap` will succeed. &mut self.0.as_mut().unwrap().0 } } impl Drop for ScopeGuard { fn drop(&mut self) { // Run the cleanup function if one is still present. if let Some((data, cleanup)) = self.0.take() { cleanup(data) } } } /// Stores an opaque value. /// /// This is meant to be used with FFI objects that are never interpreted by Rust code. #[repr(transparent)] pub struct Opaque(MaybeUninit>); impl Opaque { /// Creates a new opaque value. pub const fn new(value: T) -> Self { Self(MaybeUninit::new(UnsafeCell::new(value))) } /// Creates an uninitialised value. pub const fn uninit() -> Self { Self(MaybeUninit::uninit()) } /// Returns a raw pointer to the opaque data. pub fn get(&self) -> *mut T { UnsafeCell::raw_get(self.0.as_ptr()) } } /// A sum type that always holds either a value of type `L` or `R`. pub enum Either { /// Constructs an instance of [`Either`] containing a value of type `L`. Left(L), /// Constructs an instance of [`Either`] containing a value of type `R`. Right(R), }