use std::fmt;
use std::ops::{Deref, Range};
use std::sync::Arc;
use bytes::Bytes;
use crate::{Dict, Error};
#[derive(Clone)]
pub struct ByteSpan {
buf: Bytes,
}
impl ByteSpan {
pub fn new(file: Arc<[u8]>, range: Range<usize>) -> Result<Self, Error> {
if range.start > range.end || range.end > file.len() {
return Err(Error::SpanOutOfBounds {
start: range.start,
end: range.end,
len: file.len(),
});
}
Ok(Self {
buf: Bytes::from_owner(file).slice(range),
})
}
#[must_use]
pub fn whole(file: Arc<[u8]>) -> Self {
Self {
buf: Bytes::from_owner(file),
}
}
#[must_use]
pub fn empty() -> Self {
Self { buf: Bytes::new() }
}
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
&self.buf
}
#[must_use]
pub fn len(&self) -> usize {
self.buf.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.buf.is_empty()
}
pub fn subspan(&self, range: Range<usize>) -> Result<Self, Error> {
if range.start > range.end || range.end > self.len() {
return Err(Error::SpanOutOfBounds {
start: range.start,
end: range.end,
len: self.len(),
});
}
Ok(Self {
buf: self.buf.slice(range),
})
}
}
impl Deref for ByteSpan {
type Target = [u8];
fn deref(&self) -> &[u8] {
self.as_bytes()
}
}
impl AsRef<[u8]> for ByteSpan {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl PartialEq for ByteSpan {
fn eq(&self, other: &Self) -> bool {
self.as_bytes() == other.as_bytes()
}
}
impl Eq for ByteSpan {}
impl fmt::Debug for ByteSpan {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ByteSpan")
.field("len", &self.len())
.finish_non_exhaustive()
}
}
impl From<Arc<[u8]>> for ByteSpan {
fn from(file: Arc<[u8]>) -> Self {
Self::whole(file)
}
}
impl From<Vec<u8>> for ByteSpan {
fn from(bytes: Vec<u8>) -> Self {
Self {
buf: Bytes::from(bytes),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Stream {
pub dict: Dict,
pub data: ByteSpan,
}
impl Stream {
#[must_use]
pub fn new(dict: Dict, data: ByteSpan) -> Self {
Self { dict, data }
}
}
#[cfg(test)]
mod tests {
use std::ops::Range;
use std::sync::Arc;
use super::ByteSpan;
use crate::Error;
#[test]
fn window_covers_only_its_range() {
let file: Arc<[u8]> = Arc::from(&b"0123456789"[..]);
let span = ByteSpan::new(Arc::clone(&file), 2..5).unwrap();
assert_eq!(&*span, b"234");
assert_eq!(span.len(), 3);
assert!(!span.is_empty());
}
#[test]
fn out_of_bounds_ranges_are_refused_not_clamped() {
let file: Arc<[u8]> = Arc::from(&b"0123"[..]);
assert_eq!(
ByteSpan::new(Arc::clone(&file), 0..5),
Err(Error::SpanOutOfBounds {
start: 0,
end: 5,
len: 4
})
);
let reversed = Range { start: 3, end: 1 };
assert!(ByteSpan::new(Arc::clone(&file), reversed).is_err());
assert!(ByteSpan::new(file, 4..4).is_ok());
}
#[test]
fn subspans_are_relative_and_bounded() {
let span = ByteSpan::from(b"0123456789".to_vec());
let inner = span.subspan(2..5).unwrap();
assert_eq!(&*inner, b"234");
assert_eq!(&*inner.subspan(1..2).unwrap(), b"3");
assert!(inner.subspan(0..4).is_err());
}
#[test]
fn spans_compare_by_content_not_by_backing_buffer() {
let a = ByteSpan::from(b"abc".to_vec());
let b = ByteSpan::new(Arc::from(&b"xxabcxx"[..]), 2..5).unwrap();
assert_eq!(a, b);
assert!(ByteSpan::empty().is_empty());
}
}