use std::{
ffi::{CStr, CString},
mem::ManuallyDrop,
os::raw::c_char,
};
use crate::ffi::uint_least16_t;
use crate::traits::{FFIFromRust, FFIToRust, ZeroInit};
#[repr(C)]
#[derive(Debug)]
pub struct FFIString {
data: *mut c_char,
size: usize,
capacity: usize,
}
impl FFIString {
pub const fn len(&self) -> usize {
self.size
}
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl ZeroInit for FFIString {
fn zero_init() -> Self {
Self {
data: std::ptr::null_mut(),
size: 0,
capacity: 0,
}
}
}
impl FFIToRust for FFIString {
type Target = String;
fn to_rust(&self) -> Self::Target {
if self.is_empty() {
"".to_string()
} else {
unsafe { CStr::from_ptr(self.data) }
.to_str()
.expect("CStr::to_str failed")
.to_string()
}
}
}
#[repr(C)]
#[derive(Debug)]
pub struct OwnedFFIString {
data: *mut c_char,
size: usize,
capacity: usize,
}
impl OwnedFFIString {
pub const fn len(&self) -> usize {
self.size
}
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl ZeroInit for OwnedFFIString {
fn zero_init() -> Self {
Self {
data: std::ptr::null_mut(),
size: 0,
capacity: 0,
}
}
}
impl FFIFromRust for OwnedFFIString {
type From = String;
unsafe fn from_rust(string: &Self::From) -> Self {
let cstring = CString::new(string.clone()).expect("CString::new failed");
let len = cstring.as_bytes().len();
Self {
data: cstring.into_raw(),
size: len,
capacity: len + 1,
}
}
}
impl Drop for OwnedFFIString {
fn drop(&mut self) {
unsafe {
CString::from_raw(self.data);
}
}
}
#[repr(C)]
#[derive(Debug)]
pub struct FFIWString {
data: *mut uint_least16_t,
size: usize,
capacity: usize,
}
impl FFIWString {
pub const fn len(&self) -> usize {
self.size
}
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl ZeroInit for FFIWString {
fn zero_init() -> Self {
Self {
data: std::ptr::null_mut(),
size: 0,
capacity: 0,
}
}
}
impl FFIToRust for FFIWString {
type Target = Vec<u16>;
fn to_rust(&self) -> Self::Target {
unsafe { std::slice::from_raw_parts(self.data, self.len()) }
.iter()
.map(|&v| v as u16)
.collect::<Vec<_>>()
}
}
#[repr(C)]
#[derive(Debug)]
pub struct OwnedFFIWString {
data: *mut uint_least16_t,
size: usize,
capacity: usize,
}
impl OwnedFFIWString {
pub const fn len(&self) -> usize {
self.size
}
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl ZeroInit for OwnedFFIWString {
fn zero_init() -> Self {
Self {
data: std::ptr::null_mut(),
size: 0,
capacity: 0,
}
}
}
impl FFIFromRust for OwnedFFIWString {
type From = Vec<u16>;
unsafe fn from_rust(string: &Self::From) -> Self {
let mut string = string.clone();
string.push(0);
string.shrink_to_fit();
assert_eq!(string.len(), string.capacity());
let mut string = ManuallyDrop::new(string);
Self {
data: string.as_mut_ptr(),
size: string.len() - 1,
capacity: string.len(),
}
}
}
impl Drop for OwnedFFIWString {
fn drop(&mut self) {
unsafe { Vec::from_raw_parts(self.data, self.capacity, self.capacity) };
}
}