use std::{
ffi::{CString, c_char},
ptr::null,
slice::Iter
};
use crate::error::{CStringArrayError, CStringArrayError::EmptyArray};
#[derive(Debug)]
pub struct CStringArray {
strings: Vec<CString>,
pointers: Vec<*const c_char>
}
impl CStringArray {
pub fn new(strings: Vec<String>) -> Result<Self, CStringArrayError> {
if strings.is_empty() {
return Err(EmptyArray);
}
let cstrings: Vec<CString> = strings
.into_iter()
.map(CString::new)
.collect::<Result<_, _>>()?;
let mut pointers: Vec<*const c_char> = Vec::with_capacity(cstrings.len() + 1);
pointers.extend(cstrings.iter().map(|s| s.as_ptr()));
pointers.push(null());
Ok(Self {
strings: cstrings,
pointers
})
}
pub fn from_cstrings(strings: Vec<CString>) -> Result<Self, CStringArrayError> {
if strings.is_empty() {
return Err(EmptyArray);
}
let mut pointers: Vec<*const c_char> = Vec::with_capacity(strings.len() + 1);
pointers.extend(strings.iter().map(|s| s.as_ptr()));
pointers.push(null());
Ok(Self {
strings,
pointers
})
}
#[inline]
#[must_use]
pub fn as_ptr(&self) -> *const *const c_char {
self.pointers.as_ptr()
}
#[inline]
#[must_use]
pub fn as_mut_ptr(&mut self) -> *mut *const c_char {
self.pointers.as_mut_ptr()
}
#[inline]
#[must_use]
pub fn len(&self) -> usize {
self.strings.len()
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.strings.is_empty()
}
#[inline]
#[must_use]
pub fn get(&self, index: usize) -> Option<&CString> {
self.strings.get(index)
}
#[inline]
pub fn iter(&self) -> Iter<'_, CString> {
self.strings.iter()
}
#[inline]
#[must_use]
pub fn as_slice(&self) -> &[CString] {
&self.strings
}
#[inline]
#[must_use]
pub fn into_strings(mut self) -> Vec<CString> {
std::mem::take(&mut self.strings)
}
}
impl Drop for CStringArray {
fn drop(&mut self) {
self.pointers.clear();
}
}
unsafe impl Send for CStringArray {}
unsafe impl Sync for CStringArray {}