use std::any::Any;
use std::fmt::{Debug, Display, Formatter, Write};
use std::mem;
use std::ops::{Bound, Deref, Range, RangeBounds};
use std::sync::Arc;
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum Data {
#[doc(hidden)]
Static(&'static [u8]),
#[doc(hidden)]
Heap {
data: Arc<[u8]>,
range: Range<usize>,
},
}
impl Data {
pub fn new<T>(mut data: T) -> Self
where
T: Into<Vec<u8>> + 'static,
{
let any_data: &mut dyn Any = &mut data;
if let Some(data) = any_data.downcast_mut::<Self>() {
mem::take(data)
} else {
let data: Arc<[u8]> = Arc::from(data.into());
Self::Heap { range: 0..data.len(), data }
}
}
pub const fn new_empty() -> Self {
Self::Static(b"")
}
pub const fn new_static(static_: &'static [u8]) -> Self {
Self::Static(static_)
}
pub fn subcopy<T>(&self, range: T) -> Option<Self>
where
T: RangeBounds<usize>,
{
let current_range = match self {
Data::Static(static_) => 0..static_.len(),
Data::Heap { range, .. } => range.start..range.end,
};
let start = match range.start_bound() {
Bound::Included(start) => *start,
Bound::Excluded(_) => unreachable!("excluded bounds are invalid for range starts"),
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(before_end) => before_end.saturating_add(1),
Bound::Excluded(end) => *end,
Bound::Unbounded => self.len(),
};
let start = current_range.start.checked_add(start)?;
let end = current_range.start.checked_add(end)?;
if start > current_range.end || end > current_range.end {
return None;
}
let clone = match self {
Data::Static(static_) => Data::Static(&static_[start..end]),
Data::Heap { data: heap, .. } => Data::Heap { data: heap.clone(), range: start..end },
};
Some(clone)
}
}
impl Deref for Data {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
impl AsRef<[u8]> for Data {
fn as_ref(&self) -> &[u8] {
match self {
Self::Static(static_) => static_,
Self::Heap { data: heap, range } => &heap[range.start..range.end],
}
}
}
impl Display for Data {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
for byte in self.as_ref() {
let printable = byte.is_ascii_alphanumeric() || *byte == b' ';
match printable {
true => f.write_char(*byte as char)?,
false => write!(f, r#"\x{:02x}"#, *byte)?,
}
}
Ok(())
}
}
impl PartialEq<[u8]> for Data {
fn eq(&self, other: &[u8]) -> bool {
self.as_ref().eq(other)
}
}
impl<const SIZE: usize> PartialEq<[u8; SIZE]> for Data {
fn eq(&self, other: &[u8; SIZE]) -> bool {
self.as_ref().eq(other)
}
}
impl PartialEq<str> for Data {
fn eq(&self, other: &str) -> bool {
self.as_ref().eq(other.as_bytes())
}
}
impl PartialEq<&[u8]> for Data {
fn eq(&self, other: &&[u8]) -> bool {
self.eq(*other)
}
}
impl<const SIZE: usize> PartialEq<&[u8; SIZE]> for Data {
fn eq(&self, other: &&[u8; SIZE]) -> bool {
self.eq(*other)
}
}
impl PartialEq<&str> for Data {
fn eq(&self, other: &&str) -> bool {
self.eq(*other)
}
}
impl Default for Data {
fn default() -> Self {
Self::new_empty()
}
}
impl From<Vec<u8>> for Data {
fn from(value: Vec<u8>) -> Self {
Self::new(value)
}
}
impl From<&'static [u8]> for Data {
fn from(value: &'static [u8]) -> Self {
Self::new_static(value)
}
}
impl<const SIZE: usize> From<&'static [u8; SIZE]> for Data {
fn from(value: &'static [u8; SIZE]) -> Self {
Self::new_static(value)
}
}
impl From<String> for Data {
fn from(value: String) -> Self {
Self::new(value)
}
}
impl From<&'static str> for Data {
fn from(value: &'static str) -> Self {
Self::new_static(value.as_bytes())
}
}