use crate::TractResult;
use std::alloc::*;
use std::fmt::Display;
use std::hash::Hash;
use std::ptr::null_mut;
#[derive(Eq)]
pub struct Blob {
layout: std::alloc::Layout,
data: *mut u8,
}
impl Default for Blob {
fn default() -> Blob {
Blob::from_bytes(&[]).unwrap()
}
}
impl Clone for Blob {
fn clone(&self) -> Self {
Blob::from_bytes_alignment(self, self.layout.align()).unwrap()
}
}
impl Drop for Blob {
fn drop(&mut self) {
if !self.data.is_null() {
unsafe { dealloc(self.data, self.layout) }
}
}
}
impl PartialEq for Blob {
fn eq(&self, other: &Self) -> bool {
self.layout == other.layout && self.as_bytes() == other.as_bytes()
}
}
impl Hash for Blob {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.layout.align().hash(state);
self.as_bytes().hash(state);
}
}
impl Blob {
pub fn from_bytes(s: &[u8]) -> TractResult<Blob> {
Self::from_bytes_alignment(s, 128)
}
fn as_bytes(&self) -> &[u8] {
if self.data.is_null() {
&[]
} else {
unsafe { std::slice::from_raw_parts(self.data, self.layout.size()) }
}
}
pub fn from_bytes_alignment(s: &[u8], alignment: usize) -> TractResult<Blob> {
unsafe {
let layout = Layout::from_size_align_unchecked(s.len(), alignment);
let mut data = null_mut();
if layout.size() > 0 {
data = alloc(layout);
std::ptr::copy_nonoverlapping(s.as_ptr(), data, s.len());
}
Ok(Blob { layout, data })
}
}
}
impl std::ops::Deref for Blob {
type Target = [u8];
fn deref(&self) -> &[u8] {
self.as_bytes()
}
}
impl std::fmt::Display for Blob {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
fmt,
"Blob of {} bytes (align @{}): {}",
self.len(),
self.layout.align(),
String::from_utf8_lossy(self)
)
}
}
impl std::fmt::Debug for Blob {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
<Self as Display>::fmt(self, fmt)
}
}
impl<'a> TryFrom<&'a [u8]> for Blob {
type Error = anyhow::Error;
fn try_from(s: &[u8]) -> Result<Blob, Self::Error> {
Blob::from_bytes(s)
}
}
unsafe impl Send for Blob {}
unsafe impl Sync for Blob {}