#![no_std]
extern crate alloc;
use alloc::vec::Vec;
use core::mem::ManuallyDrop;
#[doc(alias = "PinnedBuffer")]
pub struct RawResource {
ptr: *const u8,
len: usize,
cap: usize,
}
unsafe impl Send for RawResource {}
unsafe impl Sync for RawResource {}
impl Drop for RawResource {
fn drop(&mut self) {
if !self.ptr.is_null() && self.cap > 0 {
unsafe {
let _ = Vec::from_raw_parts(self.ptr as *mut u8, self.len, self.cap);
}
}
}
}
impl RawResource {
pub fn refine(data: Vec<u8>) -> Result<Self, &'static str> {
if data.is_empty() {
return Err("Cannot refine empty data: buffer must contain at least one byte");
}
let mut domesticated = ManuallyDrop::new(data);
Ok(Self {
ptr: domesticated.as_mut_ptr() as *const u8,
len: domesticated.len(),
cap: domesticated.capacity(),
})
}
#[inline]
pub fn as_ptr(&self) -> *const u8 {
self.ptr
}
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub unsafe fn as_slice(&self) -> &[u8] {
unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_refine_success() {
let data = alloc::vec![1, 2, 3, 4, 5];
let resource = RawResource::refine(data).expect("should succeed");
assert_eq!(resource.len(), 5);
assert!(!resource.is_empty());
}
#[test]
fn test_refine_empty_fails() {
let data: Vec<u8> = alloc::vec![];
let result = RawResource::refine(data);
assert!(result.is_err());
}
#[test]
fn test_as_slice() {
let data = alloc::vec![10, 20, 30];
let resource = RawResource::refine(data).expect("should succeed");
let slice = unsafe { resource.as_slice() };
assert_eq!(slice, &[10, 20, 30]);
}
#[test]
fn test_drop_is_called() {
let data = alloc::vec![1, 2, 3, 4, 5];
let resource = RawResource::refine(data).expect("should succeed");
drop(resource);
}
}