You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

139 lines
2.4 KiB

2 years ago
use std::{
ffi::{CStr, CString},
os::raw,
2 years ago
ptr::null,
};
3 years ago
/// Creates a C string from a literal.
#[macro_export]
macro_rules! c_str {
($s:expr) => {{
const S: &'static str = std::concat!($s, "\0");
1 year ago
S.as_ptr() as $crate::types::ffi::Nts
}};
}
#[macro_export]
macro_rules! opaque_struct {
($v:vis $s:ident) => {
#[repr(C)]
$v struct $s {
_private: [u8; 0],
}
};
($s:ident) => {
#[repr(C)]
struct $s {
_private: [u8; 0],
}
};
}
#[repr(C)]
pub enum Bool {
False = 0,
True,
}
pub type Nts = *const raw::c_char;
pub type NtsMut = *mut raw::c_char;
/// An owned null-terminated string vector.
#[derive(Debug)]
pub struct CStringVec {
sv: Vec<CString>,
cv: Vec<Nts>,
}
2 years ago
#[inline]
pub fn cstr_from_slice(s: &[u8]) -> Option<&str> {
let e = end_of_cstr(s);
let s = s.get(..e)?;
std::str::from_utf8(s).ok()
}
/// Converts a C string to a `&'static str`.
///
/// # Safety
///
/// This function is unsafe because it reads from a pointer. This
/// should not cause any undefined behaviour in any case.
#[inline]
pub unsafe fn cstr_from_ptr(s: Nts) -> Option<&'static str> {
unsafe { CStr::from_ptr(s).to_str().ok() }
}
2 years ago
#[inline]
pub fn end_of_cstr(s: &[u8]) -> usize {
if let Some(n) = s.iter().position(|&b| b == b'\0') {
2 years ago
n
2 years ago
} else {
0
}
}
impl Bool {
#[inline]
pub const fn is_true(&self) -> bool {
matches!(self, Self::True)
}
3 years ago
}
impl Default for CStringVec {
/// Creates a new empty CStringVec.
#[inline]
fn default() -> Self {
3 years ago
Self { sv: Vec::new(), cv: vec![null()] }
3 years ago
}
}
impl CStringVec {
/// Creates a new `CStringVec` from an iterator.
#[inline]
pub fn new_from_iter<'a, I>(it: I) -> Result<Self, std::ffi::NulError>
3 years ago
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]
2 years ago
pub fn as_ptr(&self) -> *const Nts {
3 years ago
self.cv.as_ptr()
}
/// Returns the FFI pointer mutably.
#[inline]
2 years ago
pub fn as_mut_ptr(&mut self) -> *mut Nts {
3 years ago
self.cv.as_mut_ptr()
}
/// Returns the length of the vector.
#[inline]
pub fn len(&self) -> usize {
self.sv.len()
}
2 years ago
/// Returns `true` if the vector is empty.
#[inline]
pub fn is_empty(&self) -> bool {
self.sv.is_empty()
}
3 years ago
}
// EOF