extern "C" {
pub fn free(ptr: *mut std::ffi::c_void);
}
type BartlebyHandleMutPtr = *mut std::ffi::c_void;
extern "C" {
fn saq_bartleby_new() -> BartlebyHandleMutPtr;
fn saq_bartleby_free(bh: BartlebyHandleMutPtr);
fn saq_bartleby_set_prefix(bh: BartlebyHandleMutPtr, prefix: *const i8) -> std::ffi::c_int;
fn saq_bartleby_add_binary(
bh: BartlebyHandleMutPtr,
s: *const std::ffi::c_void,
n: usize,
) -> std::ffi::c_int;
fn saq_bartleby_build_archive(
bh: BartlebyHandleMutPtr,
s: *mut *mut std::ffi::c_void,
n: *mut usize,
) -> std::ffi::c_int;
}
#[derive(Debug)]
pub struct Archive {
buffer: *mut std::ffi::c_void,
size: usize,
}
impl std::ops::Drop for Archive {
fn drop(&mut self) {
unsafe {
free(self.buffer);
}
self.buffer = std::ptr::null_mut();
}
}
impl std::convert::AsRef<[u8]> for Archive {
fn as_ref(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.buffer.cast(), self.size) }
}
}
pub struct Bartleby(BartlebyHandleMutPtr);
impl std::fmt::Debug for Bartleby {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Bartleby(c_ptr={:p})", self.0)
}
}
impl std::ops::Drop for Bartleby {
fn drop(&mut self) {
unsafe {
saq_bartleby_free(self.0);
}
self.0 = std::ptr::null_mut();
}
}
impl Bartleby {
pub fn try_new() -> Result<Self, String> {
let bh = unsafe { saq_bartleby_new() };
if bh.is_null() {
Err("`saq_bartleby_new` returned a null pointer.".into())
} else {
Ok(Self(bh))
}
}
pub fn set_prefix(&mut self, prefix: impl std::convert::AsRef<str>) -> Result<(), String> {
let cstring = std::ffi::CString::new(prefix.as_ref())
.map_err(|e| format!("`CString::new` failed: {e}"))?;
match unsafe { saq_bartleby_set_prefix(self.0, cstring.as_ptr()) } {
0 => Ok(()),
n => Err(format!("`saq_bartleby_set_prefix` returned {n}")),
}
}
pub fn add_binary(&mut self, bin: impl std::convert::AsRef<[u8]>) -> Result<(), String> {
let buf = bin.as_ref();
match unsafe { saq_bartleby_add_binary(self.0, buf.as_ptr().cast(), buf.len()) } {
0 => Ok(()),
n => Err(format!("`saq_bartleby_add_binary` returned {n}")),
}
}
pub fn into_archive(mut self) -> Result<Archive, String> {
let mut out: *mut std::ffi::c_void = std::ptr::null_mut();
let mut out_size: usize = 0;
let r = unsafe {
saq_bartleby_build_archive(self.0, &mut out as *mut _, &mut out_size as *mut _)
};
self.0 = std::ptr::null_mut();
match r {
0 => Ok(Archive {
buffer: out,
size: out_size,
}),
n => Err(format!("`saq_bartleby_build_archive` returned {n}")),
}
}
}