mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
factor out some utilities for pointer arrays
This commit is contained in:
parent
b0f7850711
commit
3d248b55fd
2 changed files with 35 additions and 22 deletions
|
@ -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<NonNull<TCString<'static>>> {
|
|||
// 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<NonNull<TCString>>, so we convert it to a Vec<TCString> that
|
||||
// will properly drop those strings when dropped.
|
||||
let tags: Vec<TCString> = tags
|
||||
.iter()
|
||||
.map(|p| {
|
||||
// SAFETY:
|
||||
// *p is a pointer delivered to us from a Vec<NonNull<TCString>>, 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);
|
||||
}
|
||||
|
|
|
@ -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<T>(vec: Vec<T>) -> (*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<T>(mut array: Vec<NonNull<T>>)
|
||||
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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue