use super::ffi;
use std::io;
pub struct CMBlockBuffer(*mut std::ffi::c_void);
impl PartialEq for CMBlockBuffer {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl Eq for CMBlockBuffer {}
impl std::hash::Hash for CMBlockBuffer {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
unsafe {
let hash_value = ffi::cm_block_buffer_hash(self.0);
hash_value.hash(state);
}
}
}
impl CMBlockBuffer {
#[must_use]
pub fn create(data: &[u8]) -> Option<Self> {
if data.is_empty() {
return Self::create_empty();
}
let mut ptr: *mut std::ffi::c_void = std::ptr::null_mut();
let status = unsafe {
ffi::cm_block_buffer_create_with_data(data.as_ptr().cast(), data.len(), &mut ptr)
};
if status == 0 && !ptr.is_null() {
Some(Self(ptr))
} else {
None
}
}
#[must_use]
pub fn create_empty() -> Option<Self> {
let mut ptr: *mut std::ffi::c_void = std::ptr::null_mut();
let status = unsafe { ffi::cm_block_buffer_create_empty(&mut ptr) };
if status == 0 && !ptr.is_null() {
Some(Self(ptr))
} else {
None
}
}
pub fn from_raw(ptr: *mut std::ffi::c_void) -> Option<Self> {
if ptr.is_null() {
None
} else {
Some(Self(ptr))
}
}
pub unsafe fn from_ptr(ptr: *mut std::ffi::c_void) -> Self {
Self(ptr)
}
pub fn as_ptr(&self) -> *mut std::ffi::c_void {
self.0
}
pub fn data_length(&self) -> usize {
unsafe { ffi::cm_block_buffer_get_data_length(self.0) }
}
pub fn is_empty(&self) -> bool {
unsafe { ffi::cm_block_buffer_is_empty(self.0) }
}
pub fn is_range_contiguous(&self, offset: usize, length: usize) -> bool {
unsafe { ffi::cm_block_buffer_is_range_contiguous(self.0, offset, length) }
}
pub fn data_pointer(&self, offset: usize) -> Option<(*const u8, usize)> {
unsafe {
let mut length_at_offset: usize = 0;
let mut total_length: usize = 0;
let mut data_pointer: *mut std::ffi::c_void = std::ptr::null_mut();
let status = ffi::cm_block_buffer_get_data_pointer(
self.0,
offset,
&mut length_at_offset,
&mut total_length,
&mut data_pointer,
);
if status == 0 && !data_pointer.is_null() {
Some((data_pointer.cast::<u8>().cast_const(), length_at_offset))
} else {
None
}
}
}
pub unsafe fn data_pointer_mut(&self, offset: usize) -> Option<(*mut u8, usize)> {
let mut length_at_offset: usize = 0;
let mut total_length: usize = 0;
let mut data_pointer: *mut std::ffi::c_void = std::ptr::null_mut();
let status = ffi::cm_block_buffer_get_data_pointer(
self.0,
offset,
&mut length_at_offset,
&mut total_length,
&mut data_pointer,
);
if status == 0 && !data_pointer.is_null() {
Some((data_pointer.cast::<u8>(), length_at_offset))
} else {
None
}
}
pub fn copy_data_bytes(&self, offset: usize, length: usize) -> Option<Vec<u8>> {
if length == 0 {
return Some(Vec::new());
}
let mut data = vec![0u8; length];
unsafe {
let status = ffi::cm_block_buffer_copy_data_bytes(
self.0,
offset,
length,
data.as_mut_ptr().cast::<std::ffi::c_void>(),
);
if status == 0 {
Some(data)
} else {
None
}
}
}
pub fn copy_data_bytes_into(&self, offset: usize, destination: &mut [u8]) -> Result<(), i32> {
if destination.is_empty() {
return Ok(());
}
unsafe {
let status = ffi::cm_block_buffer_copy_data_bytes(
self.0,
offset,
destination.len(),
destination.as_mut_ptr().cast::<std::ffi::c_void>(),
);
if status == 0 {
Ok(())
} else {
Err(status)
}
}
}
pub fn as_slice(&self) -> Option<&[u8]> {
let len = self.data_length();
if len == 0 {
return Some(&[]);
}
if !self.is_range_contiguous(0, len) {
return None;
}
self.data_pointer(0).map(|(ptr, length)| {
let safe_len = length.min(len);
unsafe { std::slice::from_raw_parts(ptr, safe_len) }
})
}
pub fn cursor(&self) -> Option<io::Cursor<Vec<u8>>> {
self.copy_data_bytes(0, self.data_length())
.map(io::Cursor::new)
}
pub fn cursor_ref(&self) -> Option<io::Cursor<&[u8]>> {
self.as_slice().map(io::Cursor::new)
}
}
impl Clone for CMBlockBuffer {
fn clone(&self) -> Self {
unsafe {
let ptr = ffi::cm_block_buffer_retain(self.0);
Self(ptr)
}
}
}
impl Drop for CMBlockBuffer {
fn drop(&mut self) {
if !self.0.is_null() {
unsafe {
ffi::cm_block_buffer_release(self.0);
}
}
}
}
unsafe impl Send for CMBlockBuffer {}
unsafe impl Sync for CMBlockBuffer {}
impl std::fmt::Debug for CMBlockBuffer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CMBlockBuffer")
.field("ptr", &self.0)
.field("data_length", &self.data_length())
.field("is_empty", &self.is_empty())
.finish()
}
}
impl std::fmt::Display for CMBlockBuffer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "CMBlockBuffer({} bytes)", self.data_length())
}
}