TCUuidList, refactor traits

This commit is contained in:
Dustin J. Mitchell
2022-02-10 00:55:34 +00:00
parent 8cbd44544c
commit a4d992012e
8 changed files with 271 additions and 63 deletions

View File

@@ -146,38 +146,100 @@ pub(crate) trait PassByPointer: Sized {
}
}
/// Support for arrays of objects referenced by pointer.
/// *mut P can be passed by value
impl<P> PassByValue for *mut P
where
P: PassByPointer + 'static,
{
type RustType = &'static mut P;
unsafe fn from_ctype(self) -> Self::RustType {
// SAFETY:
// - self must be a valid *mut P (promised by caller)
// - TODO for 'static
unsafe { &mut *self }
}
/// Convert a Rust value to a C value.
fn as_ctype(arg: Self::RustType) -> Self {
arg
}
}
/// *const P can be passed by value
impl<P> PassByValue for *const P
where
P: PassByPointer + 'static,
{
type RustType = &'static P;
unsafe fn from_ctype(self) -> Self::RustType {
// SAFETY:
// - self must be a valid *mut P (promised by caller)
// - TODO for 'static
unsafe { &*self }
}
/// Convert a Rust value to a C value.
fn as_ctype(arg: Self::RustType) -> Self {
arg
}
}
/// NonNull<P> can be passed by value
impl<P> PassByValue for NonNull<P>
where
P: PassByPointer + 'static,
{
type RustType = &'static mut P;
unsafe fn from_ctype(mut self) -> Self::RustType {
// SAFETY:
// - self must be a valid *mut P (promised by caller)
// - TODO for 'static
unsafe { self.as_mut() }
}
/// Convert a Rust value to a C value.
fn as_ctype(arg: Self::RustType) -> Self {
NonNull::new(arg).expect("value must not be NULL")
}
}
/// Support for arrays of objects referenced by value.
///
/// The underlying C type should have three fields, containing items, length, and capacity. The
/// required trait functions just fetch and set these fields. The PassByValue trait will be
/// implemented automatically, converting between the C type and `Vec<NonNull<Element>>`. For most
/// cases, it is only necessary to implement `tc_.._free` that first calls
/// `PassByValue::take_from_arg(arg, PointerArray::null_value())` to take the existing value and
/// replace it with the null value; then `PointerArray::drop_pointer_vector(..)` to drop the
/// resulting vector and all of the objects it points to.
/// implemented automatically, converting between the C type and `Vec<Element>`. For most cases,
/// it is only necessary to implement `tc_.._free` that first calls
/// `PassByValue::take_from_arg(arg, ValueArray::null_value())` to take the existing value and
/// replace it with the null value; then `ValueArray::drop_value_vector(..)` to drop the resulting
/// vector and all of the objects it points to.
///
/// This can be used for objects referenced by pointer, too, with an Element type of `*const T`
///
/// # Safety
///
/// The C type must be documented as read-only. None of the fields may be modified, nor anything
/// in the `items` array.
///
/// This class guarantees that the items pointer is non-NULL for any valid array (even when len=0),
/// and that all pointers at indexes 0..len-1 are non-NULL.
pub(crate) trait PointerArray: Sized {
type Element: 'static + PassByPointer;
/// This class guarantees that the items pointer is non-NULL for any valid array (even when len=0).
// TODO: rename Array
pub(crate) trait ValueArray: Sized {
type Element: PassByValue;
/// Create a new PointerArray from the given items, len, and capacity.
/// Create a new ValueArray from the given items, len, and capacity.
///
/// # Safety
///
/// The arguments must either:
/// - be NULL, 0, and 0, respectively; or
/// - be valid for Vec::from_raw_parts
unsafe fn from_raw_parts(items: *const NonNull<Self::Element>, len: usize, cap: usize) -> Self;
unsafe fn from_raw_parts(items: *const Self::Element, len: usize, cap: usize) -> Self;
/// Get the items, len, and capacity (in that order) for this instance. These must be
/// precisely the same values passed tearlier to `from_raw_parts`.
fn into_raw_parts(self) -> (*const NonNull<Self::Element>, usize, usize);
fn into_raw_parts(self) -> (*const Self::Element, usize, usize);
/// Generate a NULL value. By default this is a NULL items pointer with zero length and
/// capacity.
@@ -187,36 +249,32 @@ pub(crate) trait PointerArray: Sized {
unsafe { Self::from_raw_parts(std::ptr::null(), 0, 0) }
}
/// Drop a vector of element pointers. This is a convenience function for implementing
/// Drop a vector of elements. This is a convenience function for implementing
/// tc_.._free functions.
fn drop_pointer_vector(mut vec: Vec<NonNull<Self::Element>>) {
fn drop_vector(mut vec: Vec<Self::Element>) {
// first, drop each of the elements in turn
for p in vec.drain(..) {
// SAFETY:
// - p is not NULL (NonNull)
// - p was generated by Rust (true for all arrays)
// - p was not modified (all arrays are immutable from C)
// - caller will not use this pointer again (promised by caller; p has been drain'd from
// the vector)
drop(unsafe { PassByPointer::take_from_arg(p.as_ptr()) });
for e in vec.drain(..) {
// SAFETY: e is a valid Element (caller promisd not to change it)
drop(unsafe { PassByValue::from_arg(e) });
}
// then drop the vector
drop(vec);
}
}
impl<A> PassByValue for A
where
A: PointerArray,
A: ValueArray,
{
type RustType = Vec<NonNull<A::Element>>;
type RustType = Vec<A::Element>;
unsafe fn from_ctype(self) -> Self::RustType {
let (items, len, cap) = self.into_raw_parts();
debug_assert!(!items.is_null());
// SAFETY:
// - PointerArray::from_raw_parts requires that items, len, and cap be valid for
// - ValueArray::from_raw_parts requires that items, len, and cap be valid for
// Vec::from_raw_parts if not NULL, and they are not NULL (as promised by caller)
// - PointerArray::into_raw_parts returns precisely the values passed to from_raw_parts.
// - ValueArray::into_raw_parts returns precisely the values passed to from_raw_parts.
// - those parts are passed to Vec::from_raw_parts here.
unsafe { Vec::from_raw_parts(items as *mut _, len, cap) }
}