mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
Simplify implementation of arrays
This commit is contained in:
parent
e11506ee6a
commit
a270b6c254
5 changed files with 130 additions and 54 deletions
|
@ -1,3 +1,6 @@
|
|||
use crate::util::vec_into_raw_parts;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
/// Support for values passed to Rust by value. These are represented as full structs in C. Such
|
||||
/// values are implicitly copyable, via C's struct assignment.
|
||||
///
|
||||
|
@ -142,3 +145,86 @@ pub(crate) trait PassByPointer: Sized {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Support for arrays of objects referenced by pointer.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// # 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;
|
||||
|
||||
/// Create a new PointerArray 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;
|
||||
|
||||
/// 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);
|
||||
|
||||
/// Generate a NULL value. By default this is a NULL items pointer with zero length and
|
||||
/// capacity.
|
||||
fn null_value() -> Self {
|
||||
// SAFETY:
|
||||
// - satisfies the first case in from_raw_parts' safety documentation
|
||||
unsafe { Self::from_raw_parts(std::ptr::null(), 0, 0) }
|
||||
}
|
||||
|
||||
/// Drop a vector of element pointers. This is a convenience function for implementing
|
||||
/// tc_.._free functions.
|
||||
fn drop_pointer_vector(mut vec: Vec<NonNull<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()) });
|
||||
}
|
||||
drop(vec);
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> PassByValue for A
|
||||
where
|
||||
A: PointerArray,
|
||||
{
|
||||
type RustType = Vec<NonNull<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
|
||||
// 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.
|
||||
// - those parts are passed to Vec::from_raw_parts here.
|
||||
unsafe { Vec::from_raw_parts(items as *mut _, len, cap) }
|
||||
}
|
||||
|
||||
fn as_ctype(arg: Self::RustType) -> Self {
|
||||
let (items, len, cap) = vec_into_raw_parts(arg);
|
||||
// SAFETY:
|
||||
// - satisfies the second case in from_raw_parts' safety documentation
|
||||
unsafe { Self::from_raw_parts(items, len, cap) }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue