-
Notifications
You must be signed in to change notification settings - Fork 464
rust: enhance PointerWrapper
.
#386
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,13 +4,12 @@ | |
//! | ||
//! C header: [`include/linux/types.h`](../../../../include/linux/types.h) | ||
|
||
use core::{ops::Deref, pin::Pin}; | ||
|
||
use crate::{ | ||
bindings, c_types, | ||
sync::{Ref, RefCounted}, | ||
}; | ||
use alloc::{boxed::Box, sync::Arc}; | ||
|
||
use crate::bindings; | ||
use crate::c_types; | ||
use crate::sync::{Ref, RefCounted}; | ||
use core::{ops::Deref, pin::Pin, ptr::NonNull}; | ||
|
||
/// Permissions. | ||
/// | ||
|
@@ -37,9 +36,22 @@ impl Mode { | |
/// in kernel data structures, for example, an implementation of [`FileOperations`] in `struct | ||
/// file::private_data`. | ||
pub trait PointerWrapper { | ||
/// Type of values borrowed between calls to [`PointerWrapper::into_pointer`] and | ||
/// [`PointerWrapper::from_pointer`]. | ||
type Borrowed: Deref; | ||
wedsonaf marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/// Returns the raw pointer. | ||
fn into_pointer(self) -> *const c_types::c_void; | ||
|
||
/// Returns a borrowed value. | ||
/// | ||
/// # Safety | ||
/// | ||
/// `ptr` must have been returned by a previous call to [`PointerWrapper::into_pointer`]. | ||
/// Additionally, [`PointerWrapper::from_pointer`] can only be called after *all* values | ||
/// returned by [`PointerWrapper::borrow`] have been dropped. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are there a couple of safety constraints we've omitted here?
If so, does this merit a follow-up PR? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this should be clarified. I'll prepare a follow-up PR. |
||
unsafe fn borrow(ptr: *const c_types::c_void) -> Self::Borrowed; | ||
wedsonaf marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/// Returns the instance back from the raw pointer. | ||
/// | ||
/// # Safety | ||
|
@@ -49,46 +61,121 @@ pub trait PointerWrapper { | |
} | ||
|
||
impl<T> PointerWrapper for Box<T> { | ||
type Borrowed = UnsafeReference<T>; | ||
|
||
fn into_pointer(self) -> *const c_types::c_void { | ||
Box::into_raw(self) as _ | ||
} | ||
|
||
unsafe fn borrow(ptr: *const c_types::c_void) -> Self::Borrowed { | ||
// 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 also ensure that the object remains alive for the lifetime of | ||
// the returned value. | ||
unsafe { UnsafeReference::new(&*ptr.cast()) } | ||
} | ||
|
||
unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self { | ||
// SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`]. | ||
unsafe { Box::from_raw(ptr as _) } | ||
} | ||
} | ||
|
||
impl<T: RefCounted> PointerWrapper for Ref<T> { | ||
type Borrowed = UnsafeReference<T>; | ||
|
||
fn into_pointer(self) -> *const c_types::c_void { | ||
Ref::into_raw(self) as _ | ||
} | ||
|
||
unsafe fn borrow(ptr: *const c_types::c_void) -> Self::Borrowed { | ||
// 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 also ensure that the object remains alive for the lifetime of | ||
// the returned value. | ||
unsafe { UnsafeReference::new(&*ptr.cast()) } | ||
} | ||
|
||
unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self { | ||
// SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`]. | ||
unsafe { Ref::from_raw(ptr as _) } | ||
} | ||
} | ||
|
||
impl<T> PointerWrapper for Arc<T> { | ||
type Borrowed = UnsafeReference<T>; | ||
|
||
fn into_pointer(self) -> *const c_types::c_void { | ||
Arc::into_raw(self) as _ | ||
} | ||
|
||
unsafe fn borrow(ptr: *const c_types::c_void) -> Self::Borrowed { | ||
// 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 also ensure that the object remains alive for the lifetime of | ||
// the returned value. | ||
unsafe { UnsafeReference::new(&*ptr.cast()) } | ||
} | ||
|
||
unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self { | ||
// SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`]. | ||
unsafe { Arc::from_raw(ptr as _) } | ||
} | ||
} | ||
|
||
/// A reference with manually-managed lifetime. | ||
/// | ||
/// # Invariants | ||
/// | ||
/// There are no mutable references to the underlying object, and it remains valid for the lifetime | ||
/// of the [`UnsafeReference`] instance. | ||
pub struct UnsafeReference<T: ?Sized> { | ||
ptr: NonNull<T>, | ||
} | ||
|
||
impl<T: ?Sized> UnsafeReference<T> { | ||
/// Creates a new [`UnsafeReference`] instance. | ||
/// | ||
/// # Safety | ||
/// | ||
/// Callers must ensure the following for the lifetime of the returned [`UnsafeReference`] | ||
/// instance: | ||
/// 1. That `obj` remains valid; | ||
/// 2. That no mutable references to `obj` are created. | ||
unsafe fn new(obj: &T) -> Self { | ||
// INVARIANT: The safety requirements of this function ensure that the invariants hold. | ||
Self { | ||
ptr: NonNull::from(obj), | ||
} | ||
} | ||
} | ||
|
||
impl<T: ?Sized> Deref for UnsafeReference<T> { | ||
type Target = T; | ||
|
||
fn deref(&self) -> &Self::Target { | ||
// SAFETY: By the type invariant, the object is still valid and alive, and there are no | ||
// mutable references to it. | ||
unsafe { self.ptr.as_ref() } | ||
} | ||
} | ||
|
||
impl<T: PointerWrapper + Deref> PointerWrapper for Pin<T> { | ||
type Borrowed = T::Borrowed; | ||
|
||
fn into_pointer(self) -> *const c_types::c_void { | ||
// SAFETY: We continue to treat the pointer as pinned by returning just a pointer to it to | ||
// the caller. | ||
let inner = unsafe { Pin::into_inner_unchecked(self) }; | ||
inner.into_pointer() | ||
} | ||
|
||
unsafe fn borrow(ptr: *const c_types::c_void) -> Self::Borrowed { | ||
// SAFETY: The safety requirements for this function are the same as the ones for | ||
// `T::borrow`. | ||
unsafe { T::borrow(ptr) } | ||
} | ||
|
||
unsafe fn from_pointer(p: *const c_types::c_void) -> Self { | ||
// SAFETY: The object was originally pinned. | ||
// The passed pointer comes from a previous call to `inner::into_pointer()`. | ||
|
Uh oh!
There was an error while loading. Please reload this page.