use std::{
fs::{self, File, OpenOptions},
io,
marker::PhantomData,
ops::Deref,
path::Path,
ptr, slice,
};
pub(crate) trait Sink<E> {
type Error: From<E>;
fn sink(&mut self, bytes: &[u8]) -> Result<(), Self::Error>;
}
#[cfg(test)]
impl<E> Sink<E> for Vec<u8> {
type Error = E;
#[inline]
fn sink(&mut self, bytes: &[u8]) -> Result<(), Self::Error> {
self.extend_from_slice(bytes);
Ok(())
}
}
pub(crate) struct FnSink<F, Error> {
inner: F,
_error: PhantomData<Error>,
}
impl<F, Error> FnSink<F, Error> {
#[inline]
pub(crate) fn new(inner: F) -> Self {
Self { inner, _error: PhantomData }
}
}
impl<F, E, Error> Sink<E> for FnSink<F, Error>
where
F: FnMut(&[u8]) -> Result<(), Error>,
Error: From<E>,
{
type Error = Error;
#[inline]
fn sink(&mut self, bytes: &[u8]) -> Result<(), Self::Error> {
(self.inner)(bytes)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(transparent)]
pub(crate) struct Magic(u32);
impl Magic {
#[inline]
pub(crate) const fn new(value: u32) -> Self {
Self(value)
}
#[inline]
pub(crate) const fn from_raw(raw: [u8; 4]) -> Self {
Self(u32::from_le_bytes(raw))
}
#[inline]
pub(crate) const fn raw(&self) -> [u8; 4] {
self.0.to_le_bytes()
}
}
impl From<[u8; 4]> for Magic {
#[inline]
fn from(value: [u8; 4]) -> Self {
Self::from_raw(value)
}
}
impl From<Magic> for [u8; 4] {
#[inline]
fn from(value: Magic) -> Self {
value.raw()
}
}
pub(crate) struct BytesBuf(Vec<u8>);
impl BytesBuf {
#[inline]
pub(crate) fn with_capacity(capacity: usize) -> Self {
Self(Vec::with_capacity(capacity))
}
#[inline]
pub(crate) fn len(&self) -> usize {
self.0.len()
}
#[inline]
pub(crate) fn as_buffer_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.0.as_mut_ptr(), self.0.capacity()) }
}
pub(crate) fn buffer(&mut self, bytes: &[u8]) -> usize {
let spare_capacity = self.0.capacity() - self.0.len();
let buffered = bytes.len().min(spare_capacity);
let old_len = self.0.len();
unsafe {
ptr::copy_nonoverlapping(bytes.as_ptr(), self.0.as_mut_ptr().add(old_len), buffered);
self.0.set_len(old_len + buffered);
}
buffered
}
pub(crate) fn drain(&mut self, len: usize) {
debug_assert!(len <= self.0.len());
let len = len.min(self.0.len());
let remaining = self.0.len() - len;
unsafe {
ptr::copy(self.0.as_ptr().add(len), self.0.as_mut_ptr(), remaining);
self.0.set_len(remaining);
}
}
pub(crate) fn clear(&mut self) {
self.0.clear()
}
}
impl Deref for BytesBuf {
type Target = [u8];
#[inline]
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
pub(crate) struct LazyFileWriter<'a> {
path: &'a Path,
inner: Option<File>,
}
impl<'a> LazyFileWriter<'a> {
#[inline]
pub(crate) fn new(path: &'a Path) -> Self {
Self { path, inner: None }
}
#[inline]
pub(crate) fn is_empty(&self) -> bool {
self.inner.is_none()
}
}
impl<'a> io::Write for LazyFileWriter<'a> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if self.inner.is_none() {
if let Some(parent_path) = self.path.parent() {
fs::create_dir_all(parent_path)?;
}
let file =
OpenOptions::new().create(true).truncate(true).write(true).open(self.path)?;
self.inner = Some(file);
}
let file = unsafe { self.inner.as_mut().unwrap_unchecked() };
file.write(buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
if let Some(file) = self.inner.as_mut() {
file.flush()
} else {
Ok(())
}
}
}
pub trait Sealed {}
impl<T> Sealed for Option<T> where T: Sealed {}
#[allow(dead_code)] pub(crate) fn decode_hex(str: &str) -> Option<Vec<u8>> {
if str.len() % 2 != 0 {
return None;
}
(0..str.len())
.step_by(2)
.map(|i| u8::from_str_radix(&str[i..i + 1], 16))
.collect::<Result<Vec<_>, _>>()
.ok()
}
#[cfg(test)]
mod tests {
use zstd_safe::WriteBuf;
use crate::common::BytesBuf;
#[test]
fn test_bytesbuf() {
let mut buffer = BytesBuf::with_capacity(4);
assert_eq!(buffer.buffer(&[1, 2, 3, 4, 5, 6]), 4);
assert_eq!(buffer.as_slice(), &[1, 2, 3, 4]);
buffer.drain(3);
assert_eq!(buffer.as_slice(), &[4]);
assert_eq!(buffer.buffer(&[1, 2, 3, 4, 5, 6]), 3);
assert_eq!(buffer.as_slice(), &[4, 1, 2, 3]);
}
}