#[repr(C)]
pub struct FfiString {
pub ptr: *const u8,
pub len: usize,
}
impl FfiString {
#[inline]
pub fn from_string(s: String) -> Self {
let bytes = s.into_bytes();
let len = bytes.len();
let ptr = Box::into_raw(bytes.into_boxed_slice()) as *const u8;
Self { ptr, len }
}
#[inline]
#[allow(clippy::should_implement_trait)]
pub fn from_str(s: &str) -> Self {
Self::from_string(s.to_string())
}
#[inline]
#[allow(clippy::inherent_to_string)]
pub fn to_string(self) -> String {
ffi_to_string(self)
}
#[inline]
pub fn empty() -> Self {
Self {
ptr: std::ptr::null(),
len: 0,
}
}
}
#[inline]
pub fn string_to_ffi(s: String) -> FfiString {
FfiString::from_string(s)
}
#[inline]
pub fn ffi_to_string(ffi: FfiString) -> String {
if ffi.ptr.is_null() || ffi.len == 0 {
return String::new();
}
let bytes = unsafe { Vec::from_raw_parts(ffi.ptr as *mut u8, ffi.len, ffi.len) };
String::from_utf8(bytes).unwrap_or_else(|e| String::from_utf8_lossy(e.as_bytes()).into_owned())
}
#[no_mangle]
pub extern "C" fn ffi_free_string(ffi: FfiString) {
if !ffi.ptr.is_null() && ffi.len > 0 {
let _ = unsafe { Vec::from_raw_parts(ffi.ptr as *mut u8, ffi.len, ffi.len) };
}
}
#[repr(C)]
pub struct FfiBytes {
pub ptr: *mut u8,
pub len: usize,
pub cap: usize,
}
#[inline]
pub fn vec_to_ffi(mut v: Vec<u8>) -> FfiBytes {
let ptr = v.as_mut_ptr();
let len = v.len();
let cap = v.capacity();
std::mem::forget(v);
FfiBytes { ptr, len, cap }
}
#[inline]
pub fn ffi_to_vec(ffi: FfiBytes) -> Vec<u8> {
if ffi.ptr.is_null() || ffi.len == 0 {
return Vec::new();
}
unsafe { Vec::from_raw_parts(ffi.ptr, ffi.len, ffi.cap) }
}
#[no_mangle]
pub extern "C" fn ffi_free_bytes(ffi: FfiBytes) {
if !ffi.ptr.is_null() && (ffi.len > 0 || ffi.cap > 0) {
let _ = unsafe { Vec::from_raw_parts(ffi.ptr, ffi.len, ffi.cap) };
}
}