//! Foreign function interface utilities.

use crate::durandal::err::*;
pub use std::{ffi::*,
              os::raw::*,
              ptr::{null, null_mut}};

/// Creates a C string from a literal.
#[macro_export]
macro_rules! c_str {
   ($s:expr) => {
      concat!($s, "\0").as_ptr() as $crate::durandal::ffi::NT
   };
}

#[inline]
pub const fn null_void() -> *const c_void {null()}

#[inline]
pub const fn null_mut_void() -> *mut c_void {null_mut()}

impl CStringVec
{
   /// Creates a new `CStringVec` from an iterator.
   #[inline]
   pub fn new_from_iter<'a, I>(it: I) -> ResultS<Self>
      where I: Iterator<Item = &'a str>
   {
      let mut v = Self::default();

      for st in it {
         v.push(CString::new(st)?);
      }

      Ok(v)
   }

   /// Pushes a new `CString`.
   #[inline]
   pub fn push(&mut self, st: CString)
   {
      self.cv.insert(self.cv.len() - 1, st.as_ptr());
      self.sv.push(st);
   }

   /// Returns the FFI pointer.
   #[inline]
   pub fn as_ptr(&self) -> *const NT {self.cv.as_ptr()}

   /// Returns the FFI pointer mutably.
   #[inline]
   pub fn as_mut_ptr(&mut self) -> *mut NT {self.cv.as_mut_ptr()}
}

impl Default for CStringVec
{
   /// Creates a new empty CStringVec.
   #[inline]
   fn default() -> Self {Self{sv: Vec::new(), cv: vec![null()]}}
}

/// An owned null-terminated string vector.
#[derive(Debug)]
pub struct CStringVec
{
   sv: Vec<CString>,
   cv: Vec<NT>,
}

/// A null-terminated byte string pointer.
pub type NT = *const c_char;

// EOF
