use super::PrecompiledError;
use std::{
fmt,
ops::{Deref, Range},
sync::Arc,
};
#[derive(Clone)]
enum Storage {
Bytes(Arc<[u8]>),
Owner(Arc<dyn AsRef<[u8]> + Send + Sync>),
}
#[derive(Clone)]
pub struct PrecompiledBytes {
storage: Storage,
range: Range<usize>,
}
impl PrecompiledBytes {
pub fn new(owner: impl AsRef<[u8]> + Send + Sync + 'static) -> Self {
Self::from_shared_owner(Arc::new(owner))
}
pub fn from_shared_owner<T: AsRef<[u8]> + Send + Sync + 'static>(owner: Arc<T>) -> Self {
let len = owner.as_ref().as_ref().len();
Self {
storage: Storage::Owner(owner),
range: 0..len,
}
}
pub fn slice(&self, range: Range<usize>) -> Result<Self, PrecompiledError> {
if range.start > range.end || range.end > self.len() {
return Err(PrecompiledError::InvalidData);
}
Ok(Self {
storage: self.storage.clone(),
range: self.range.start + range.start..self.range.start + range.end,
})
}
}
impl From<Vec<u8>> for PrecompiledBytes {
fn from(bytes: Vec<u8>) -> Self {
Self::new(bytes)
}
}
impl From<Arc<[u8]>> for PrecompiledBytes {
fn from(bytes: Arc<[u8]>) -> Self {
let len = bytes.len();
Self {
storage: Storage::Bytes(bytes),
range: 0..len,
}
}
}
impl AsRef<[u8]> for PrecompiledBytes {
fn as_ref(&self) -> &[u8] {
let bytes: &[u8] = match &self.storage {
Storage::Bytes(bytes) => bytes,
Storage::Owner(owner) => owner.as_ref().as_ref(),
};
&bytes[self.range.clone()]
}
}
impl Deref for PrecompiledBytes {
type Target = [u8];
fn deref(&self) -> &[u8] {
self.as_ref()
}
}
impl fmt::Debug for PrecompiledBytes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PrecompiledBytes")
.field("len", &self.len())
.finish_non_exhaustive()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn nested_views_share_storage_and_check_relative_bounds() {
let owner = Arc::new(vec![1, 2, 3, 4, 5]);
let weak = Arc::downgrade(&owner);
let image = PrecompiledBytes::from_shared_owner(Arc::clone(&owner));
let view = image.slice(1..5).unwrap().slice(1..3).unwrap();
assert_eq!(&*view, &[3, 4]);
assert_eq!(view.as_ptr(), owner[2..].as_ptr());
assert!(image.slice(Range { start: 4, end: 3 }).is_err());
assert!(image.slice(0..6).is_err());
assert!(image.slice(0..usize::MAX).is_err());
assert!(image.slice(5..5).unwrap().is_empty());
drop(owner);
drop(image);
assert!(weak.upgrade().is_some());
drop(view);
assert!(weak.upgrade().is_none());
}
#[test]
fn existing_arc_slice_is_retained_without_copying() {
let bytes: Arc<[u8]> = Arc::from([1, 2, 3]);
let image = PrecompiledBytes::from(Arc::clone(&bytes));
assert_eq!(image.as_ptr(), bytes.as_ptr());
assert_eq!(format!("{image:?}"), "PrecompiledBytes { len: 3, .. }");
}
}