From 3d248b55fdbd0349f3861294fd339c606af1d676 Mon Sep 17 00:00:00 2001 From: "Dustin J. Mitchell" Date: Sun, 6 Feb 2022 16:38:31 +0000 Subject: [PATCH] factor out some utilities for pointer arrays --- lib/src/arrays.rs | 28 ++++++---------------------- lib/src/util.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/lib/src/arrays.rs b/lib/src/arrays.rs index a9d5dde49..301d273d3 100644 --- a/lib/src/arrays.rs +++ b/lib/src/arrays.rs @@ -1,5 +1,6 @@ use crate::string::TCString; use crate::traits::*; +use crate::util::{drop_pointer_array, vec_into_raw_parts}; use std::ptr::NonNull; /// TCTags represents a list of tags associated with a task. @@ -10,8 +11,6 @@ use std::ptr::NonNull; /// will remain valid even if the task is freed. #[repr(C)] pub struct TCTags { - // WARNING: this struct must match CPointerArray exactly, in size and order - // of fields. Names can differ, as can the pointer type. /// number of tags in items len: libc::size_t, @@ -37,11 +36,11 @@ impl PassByValue for Vec>> { // emulate Vec::into_raw_parts(): // - disable dropping the Vec with ManuallyDrop // - extract ptr, len, and capacity using those methods - let mut vec = std::mem::ManuallyDrop::new(self); + let (items, len, _capacity) = vec_into_raw_parts(self); TCTags { - len: vec.len(), - _capacity: vec.capacity(), - items: vec.as_mut_ptr(), + len, + _capacity, + items, } } } @@ -64,20 +63,5 @@ pub extern "C" fn tc_tags_free<'a>(tctags: *mut TCTags) { // SAFETY: // - *tctags is a valid TCTags (caller promises to treat it as read-only) let tags = unsafe { Vec::take_from_arg(tctags, TCTags::default()) }; - - // tags is a Vec>, so we convert it to a Vec that - // will properly drop those strings when dropped. - let tags: Vec = tags - .iter() - .map(|p| { - // SAFETY: - // *p is a pointer delivered to us from a Vec>, so - // - *p is not NULL - // - *p was generated by Rust - // - *p was not modified (promised by caller) - // - the caller will not use this pointer again (promised by caller) - unsafe { TCString::take_from_arg(p.as_ptr()) } - }) - .collect(); - drop(tags); + drop_pointer_array(tags); } diff --git a/lib/src/util.rs b/lib/src/util.rs index 0709d2640..00676424a 100644 --- a/lib/src/util.rs +++ b/lib/src/util.rs @@ -1,5 +1,34 @@ use crate::string::TCString; +use crate::traits::*; +use std::ptr::NonNull; pub(crate) fn err_to_tcstring(e: impl std::string::ToString) -> TCString<'static> { TCString::from(e.to_string()) } + +/// A version of Vec::into_raw_parts, which is still unstable. Returns ptr, len, cap. +pub(crate) fn vec_into_raw_parts(vec: Vec) -> (*mut T, usize, usize) { + // emulate Vec::into_raw_parts(): + // - disable dropping the Vec with ManuallyDrop + // - extract ptr, len, and capacity using those methods + let mut vec = std::mem::ManuallyDrop::new(vec); + return (vec.as_mut_ptr(), vec.len(), vec.capacity()); +} + +/// Drop an array of PassByPointer values +pub(crate) fn drop_pointer_array(mut array: Vec>) +where + T: 'static + PassByPointer, +{ + // first, drop each of the elements in turn + for p in array.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(array); +}