//! 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};
}

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

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

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

      Ok(v)
   }

   /// Pushes a new `CString`.
   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.
   pub fn as_ptr(&self) -> *const NT
   {
      self.cv.as_ptr()
   }

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

/// 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
