use std::ffi::CStr;
use std::fmt;
use std::mem::MaybeUninit;
use std::result::Result as StdResult;
use foreign_types::{ForeignType, ForeignTypeRef};
use libc::c_char;
use malloc_buf::Malloc;
use crate::common::{Database, DatabaseRef};
use crate::error::{AsResult, Error, Result};
use crate::ffi;
pub trait Serialized {
type Error: fmt::Debug;
fn size(&self) -> StdResult<usize, Self::Error>;
fn info(&self) -> StdResult<String, Self::Error>;
fn deserialize<M>(&self) -> StdResult<Database<M>, Self::Error>;
}
impl<T: AsRef<[u8]>> Serialized for T {
type Error = Error;
fn size(&self) -> Result<usize> {
let buf = self.as_ref();
let mut size = MaybeUninit::uninit();
unsafe {
ffi::hs_serialized_database_size(buf.as_ptr() as *const _, buf.len(), size.as_mut_ptr())
.map(|_| size.assume_init())
}
}
fn info(&self) -> Result<String> {
let buf = self.as_ref();
let mut p = MaybeUninit::uninit();
unsafe {
ffi::hs_serialized_database_info(buf.as_ptr() as *const _, buf.len(), p.as_mut_ptr()).and_then(|_| {
let p = p.assume_init();
let info = CStr::from_ptr(p).to_str()?.to_owned();
libc::free(p as *mut _);
Ok(info)
})
}
}
fn deserialize<M>(&self) -> Result<Database<M>> {
let buf = self.as_ref();
let mut db = MaybeUninit::uninit();
unsafe {
ffi::hs_deserialize_database(buf.as_ptr() as *const c_char, buf.len(), db.as_mut_ptr())
.map(|_| Database::from_ptr(db.assume_init()))
}
}
}
impl<T> DatabaseRef<T> {
pub fn serialize(&self) -> Result<Malloc<[u8]>> {
let mut ptr = MaybeUninit::uninit();
let mut size = MaybeUninit::uninit();
unsafe {
ffi::hs_serialize_database(self.as_ptr(), ptr.as_mut_ptr(), size.as_mut_ptr())
.map(|_| Malloc::from_array(ptr.assume_init() as *mut u8, size.assume_init()))
}
}
pub fn deserialize_at<B: AsRef<[u8]>>(&mut self, bytes: B) -> Result<()> {
let bytes = bytes.as_ref();
unsafe { ffi::hs_deserialize_database_at(bytes.as_ptr() as *const c_char, bytes.len(), self.as_ptr()).ok() }
}
}
#[cfg(test)]
pub mod tests {
use crate::common::database::tests::*;
use crate::prelude::*;
use super::*;
pub fn validate_serialized_database<S: Serialized>(data: &S) {
assert!(data.size().unwrap() >= DATABASE_SIZE);
validate_database_info(data.info().unwrap().as_str());
}
#[test]
fn test_database_serialize() {
let db: StreamingDatabase = "test".parse().unwrap();
let data = db.serialize().unwrap();
validate_serialized_database(&data);
assert!(!data.info().unwrap().is_empty());
}
#[test]
fn test_database_deserialize() {
let db: VectoredDatabase = "test".parse().unwrap();
let data = db.serialize().unwrap();
validate_serialized_database(&data);
let db: VectoredDatabase = data.deserialize().unwrap();
validate_database(&db);
}
#[test]
fn test_database_deserialize_at() {
let mut db: BlockDatabase = "test".parse().unwrap();
let data = db.serialize().unwrap();
validate_serialized_database(&data);
db.deserialize_at(&data).unwrap();
validate_database(&db);
}
}