use std::ffi::{CStr, CString};
use ffi_convert::{
AsRust, AsRustError, CDrop, CDropError, CReprOf, CReprOfError, RawBorrow, RawPointerConverter,
};
#[repr(C)]
#[derive(Debug, RawPointerConverter)]
pub struct CStringArray {
pub data: *const *const std::ffi::c_char,
pub size: usize,
}
unsafe impl Sync for CStringArray {}
impl AsRust<Vec<String>> for CStringArray {
fn as_rust(&self) -> Result<Vec<String>, AsRustError> {
let mut result = vec![];
let strings = unsafe {
std::slice::from_raw_parts_mut(self.data as *mut *mut std::ffi::c_char, self.size)
};
for s in strings {
result.push(unsafe { CStr::raw_borrow(*s) }?.as_rust()?)
}
Ok(result)
}
}
impl CReprOf<Vec<String>> for CStringArray {
fn c_repr_of(input: Vec<String>) -> Result<Self, CReprOfError> {
Ok(Self {
size: input.len(),
data: Box::into_raw(
input
.into_iter()
.map::<Result<*const std::ffi::c_char, CReprOfError>, _>(|s| {
Ok(CString::c_repr_of(s)?.into_raw_pointer())
})
.collect::<Result<Vec<_>, _>>()?
.into_boxed_slice(),
) as *const *const std::ffi::c_char,
})
}
}
impl CDrop for CStringArray {
fn do_drop(&mut self) -> Result<(), CDropError> {
if !self.data.is_null() {
let data = std::mem::replace(&mut self.data, std::ptr::null());
let size = std::mem::replace(&mut self.size, 0);
unsafe {
let y = Box::from_raw(std::ptr::slice_from_raw_parts_mut(
data as *mut *mut std::ffi::c_char,
size,
));
for p in y.iter() {
let _ = CString::from_raw_pointer(*p)?; }
}
}
Ok(())
}
}
impl Drop for CStringArray {
fn drop(&mut self) {
let _ = self.do_drop();
}
}