use core::ptr::NonNull;
pub struct SharedBuf {
ptr_len: Option<(NonNull<u8>, usize)>,
}
impl Default for SharedBuf {
fn default() -> Self {
Self::new()
}
}
impl SharedBuf {
pub fn new() -> Self {
Self { ptr_len: None }
}
pub fn set(&mut self, buf: &mut [u8]) {
self.ptr_len = if buf.is_empty() {
None
} else {
NonNull::new(buf.as_mut_ptr()).map(|p| (p, buf.len()))
};
}
pub fn clear(&mut self) {
self.ptr_len = None;
}
pub fn is_active(&self) -> bool {
self.ptr_len.is_some()
}
pub fn bytes(&self) -> Option<&[u8]> {
self.ptr_len.map(|(ptr, len)| {
unsafe { core::slice::from_raw_parts(ptr.as_ptr(), len) }
})
}
pub fn bytes_mut(&mut self) -> Option<&mut [u8]> {
self.ptr_len.map(|(ptr, len)| {
unsafe { core::slice::from_raw_parts_mut(ptr.as_ptr(), len) }
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn inactive_by_default_and_after_clear() {
let mut s = SharedBuf::new();
assert!(!s.is_active());
assert!(s.bytes().is_none());
let mut buf = [1u8, 2, 3, 4];
s.set(&mut buf);
assert!(s.is_active());
s.clear();
assert!(!s.is_active());
assert!(s.bytes().is_none());
}
#[test]
fn empty_buffer_is_inactive() {
let mut s = SharedBuf::new();
let mut empty: [u8; 0] = [];
s.set(&mut empty);
assert!(!s.is_active(), "an empty buffer means the slot model");
}
#[test]
fn round_trips_bytes_through_the_captured_pointer() {
let mut buf = [10u8, 20, 30, 40];
let mut s = SharedBuf::new();
s.set(&mut buf);
assert_eq!(s.bytes().unwrap(), &[10, 20, 30, 40]);
s.bytes_mut().unwrap()[1] = 99;
s.clear();
assert_eq!(buf, [10, 99, 30, 40]);
}
}