use alloc::sync::Arc;
use alloc::vec::Vec;
use core::ops::Range;
#[derive(Debug, Clone)]
pub struct SampleBytes {
data: Arc<[u8]>,
range: Range<usize>,
}
impl SampleBytes {
#[must_use]
pub fn from_vec(v: Vec<u8>) -> Self {
let len = v.len();
Self {
data: Arc::from(v.into_boxed_slice()),
range: 0..len,
}
}
#[must_use]
pub fn from_arc(data: Arc<[u8]>) -> Self {
let len = data.len();
Self {
data,
range: 0..len,
}
}
#[must_use]
pub fn from_arc_slice(data: Arc<[u8]>, range: Range<usize>) -> Self {
assert!(
range.end <= data.len() && range.start <= range.end,
"SampleBytes range out of bounds"
);
Self { data, range }
}
#[must_use]
pub fn slice(&self, sub: Range<usize>) -> Self {
assert!(sub.end <= self.len(), "SampleBytes::slice out of bounds");
let start = self.range.start + sub.start;
let end = self.range.start + sub.end;
Self {
data: Arc::clone(&self.data),
range: start..end,
}
}
#[must_use]
pub fn as_slice(&self) -> &[u8] {
&self.data[self.range.clone()]
}
#[must_use]
pub fn len(&self) -> usize {
self.range.end - self.range.start
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.range.is_empty()
}
#[must_use]
pub fn to_vec(&self) -> Vec<u8> {
self.as_slice().to_vec()
}
}
impl AsRef<[u8]> for SampleBytes {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl core::ops::Deref for SampleBytes {
type Target = [u8];
fn deref(&self) -> &[u8] {
self.as_slice()
}
}
impl PartialEq for SampleBytes {
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl Eq for SampleBytes {}
impl From<Vec<u8>> for SampleBytes {
fn from(v: Vec<u8>) -> Self {
Self::from_vec(v)
}
}
impl From<Arc<[u8]>> for SampleBytes {
fn from(a: Arc<[u8]>) -> Self {
Self::from_arc(a)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_vec_roundtrip() {
let s = SampleBytes::from_vec(alloc::vec![1, 2, 3, 4]);
assert_eq!(s.len(), 4);
assert_eq!(s.as_slice(), &[1, 2, 3, 4]);
assert_eq!(s.to_vec(), alloc::vec![1, 2, 3, 4]);
}
#[test]
fn from_arc_full_range() {
let arc: Arc<[u8]> = Arc::from(alloc::vec![10, 20, 30].into_boxed_slice());
let s = SampleBytes::from_arc(arc);
assert_eq!(s.as_slice(), &[10, 20, 30]);
}
#[test]
fn slice_is_zero_copy() {
let arc: Arc<[u8]> = Arc::from(alloc::vec![1, 2, 3, 4, 5].into_boxed_slice());
let s = SampleBytes::from_arc(arc);
let inner_ptr_before = s.as_slice().as_ptr() as usize;
let sub = s.slice(2..5);
let inner_ptr_after = sub.as_slice().as_ptr() as usize;
assert_eq!(inner_ptr_after - inner_ptr_before, 2);
assert_eq!(sub.as_slice(), &[3, 4, 5]);
}
#[test]
fn nested_slice_offsets_compose() {
let s = SampleBytes::from_vec(alloc::vec![0, 1, 2, 3, 4, 5, 6, 7]);
let s1 = s.slice(2..7); let s2 = s1.slice(1..4); assert_eq!(s2.as_slice(), &[3, 4, 5]);
}
#[test]
fn clone_is_refcount_bump() {
let s = SampleBytes::from_vec(alloc::vec![1, 2, 3]);
let p1 = s.as_slice().as_ptr();
let s2 = s.clone();
let p2 = s2.as_slice().as_ptr();
assert_eq!(p1, p2, "Clone must share backing storage");
}
#[test]
fn empty_after_full_strip() {
let s = SampleBytes::from_vec(alloc::vec![1, 2, 3]);
let empty = s.slice(3..3);
assert!(empty.is_empty());
}
#[test]
#[should_panic(expected = "out of bounds")]
fn slice_oob_panics() {
let s = SampleBytes::from_vec(alloc::vec![1, 2]);
let _ = s.slice(0..5);
}
}