use std::{
fmt, ops,
os::raw::{c_char, c_uint, c_ulonglong},
slice, str,
};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct ByteSlice<'a>(&'a [u8]);
impl<'a> fmt::Debug for ByteSlice<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let b = self.as_slice();
match str::from_utf8(b) {
Ok(s) => write!(f, "ByteSlice({:?})", s),
Err(_) => write!(f, "ByteSlice(non-utf8: {:?})", b),
}
}
}
impl<'a> fmt::Display for ByteSlice<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let b = self.as_slice();
match str::from_utf8(b) {
Ok(s) => write!(f, "{}", s),
Err(_) => write!(f, "(non-utf8: {:?})", b),
}
}
}
impl<'a> ByteSlice<'a> {
pub const fn from_slice(data: &'a [u8]) -> Self { Self(data) }
pub const fn as_slice(&self) -> &'a [u8] { self.0 }
pub(crate) const fn as_ptr(&self) -> *const c_char { self.as_slice().as_ptr() as *const c_char }
pub(crate) const fn native_len(&self) -> c_uint { self.as_slice().len() as c_uint }
}
impl<'a> From<&'a [u8]> for ByteSlice<'a> {
fn from(x: &'a [u8]) -> Self { Self::from_slice(x) }
}
impl<'a, const N: usize> From<&'a [u8; N]> for ByteSlice<'a> {
fn from(x: &'a [u8; N]) -> Self { Self::from_slice(x.as_ref()) }
}
impl<'a> ByteSlice<'a> {
pub const fn from_str(data: &'a str) -> Self { Self::from_slice(data.as_bytes()) }
pub const unsafe fn as_str(&self) -> &'a str { str::from_utf8_unchecked(self.as_slice()) }
}
impl<'a> From<&'a str> for ByteSlice<'a> {
fn from(x: &'a str) -> Self { Self::from_str(x) }
}
impl<'a> ByteSlice<'a> {
pub fn index_range(&self, range: impl slice::SliceIndex<[u8], Output=[u8]>) -> Option<Self> {
self.as_slice().get(range).map(Self::from_slice)
}
}
#[cfg(feature = "vectored")]
pub(crate) mod vectored {
use super::{ByteSlice, Range};
use std::{
cmp, mem, ops,
os::raw::{c_char, c_uint},
slice,
};
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct VectoredByteSlices<'string, 'slice>(&'slice [ByteSlice<'string>]);
impl<'string, 'slice> VectoredByteSlices<'string, 'slice> {
pub const fn from_slices(data: &'slice [ByteSlice<'string>]) -> Self { Self(data) }
#[cfg(feature = "vectored")]
pub(crate) fn from_io_slices(
cache: &'slice mut Vec<mem::MaybeUninit<ByteSlice<'static>>>,
bufs: &'string [std::io::IoSlice<'string>],
) -> Self {
cache.clear();
cache.reserve(bufs.len());
unsafe {
cache.set_len(bufs.len());
}
for (out_slice, in_slice) in cache.iter_mut().zip(bufs.iter()) {
let in_slice: &'static std::io::IoSlice<'static> = unsafe { mem::transmute(in_slice) };
out_slice.write(ByteSlice::from_slice(in_slice));
}
let bufs: &'slice [ByteSlice<'string>] = unsafe { mem::transmute(&cache[..]) };
Self::from_slices(bufs)
}
pub fn length_sum(&self) -> usize { self.0.iter().map(|s| s.as_slice().len()).sum() }
pub(crate) fn pointers_and_lengths(&self) -> (Vec<*const c_char>, Vec<c_uint>) {
let lengths: Vec<c_uint> = self.0.iter().map(|col| col.native_len()).collect();
let data_pointers: Vec<*const c_char> = self.0.iter().map(|col| col.as_ptr()).collect();
(data_pointers, lengths)
}
pub(crate) const fn native_len(&self) -> c_uint { self.0.len() as c_uint }
}
impl<'string, 'slice> From<&'slice [ByteSlice<'string>]> for VectoredByteSlices<'string, 'slice> {
fn from(x: &'slice [ByteSlice<'string>]) -> Self { Self::from_slices(x) }
}
impl<'string, 'slice, const N: usize> From<&'slice [ByteSlice<'string>; N]>
for VectoredByteSlices<'string, 'slice>
{
fn from(x: &'slice [ByteSlice<'string>; N]) -> Self { Self::from_slices(x.as_ref()) }
}
impl<'string, 'slice> From<&'slice [&'string [u8]]> for VectoredByteSlices<'string, 'slice> {
fn from(x: &'slice [&'string [u8]]) -> Self {
let x: &'slice [ByteSlice<'string>] = unsafe { mem::transmute(x) };
Self(x)
}
}
impl<'string, 'slice, const N: usize> From<&'slice [&'string [u8]; N]>
for VectoredByteSlices<'string, 'slice>
{
fn from(x: &'slice [&'string [u8]; N]) -> Self {
let x: &'slice [ByteSlice<'string>; N] = unsafe { mem::transmute(x) };
x.into()
}
}
impl<'string, 'slice> VectoredByteSlices<'string, 'slice> {
fn find_index_at(
&self,
mut column: usize,
mut within_column_index: usize,
mut remaining: usize,
) -> Option<(usize, usize)> {
let num_columns = self.0.len();
if column >= num_columns {
return None;
}
if remaining == 0 {
return Some((column, within_column_index));
}
let within_column_index = loop {
let cur_col = &self.0[column];
let (prev, max_diff) = if within_column_index > 0 {
let x = within_column_index;
within_column_index = 0;
assert_ne!(cur_col.0.len(), x);
(x, cur_col.0.len() - x)
} else {
(0, cur_col.0.len())
};
assert_ne!(max_diff, 0);
let new_offset = cmp::min(remaining, max_diff);
let cur_ind = prev + new_offset;
remaining -= new_offset;
if remaining == 0 {
break cur_ind;
} else if column == (num_columns - 1) {
return None;
} else {
column += 1;
}
};
Some((column, within_column_index))
}
fn collect_slices_range(
&self,
range: Range,
start: (usize, usize),
end: (usize, usize),
) -> Option<VectoredSubset<'string, 'slice>> {
let (start_col, start_ind) = start;
let (end_col, end_ind) = end;
assert!(end_col >= start_col);
if start_col == end_col {
assert!(end_ind >= start_ind);
let col_substring = self.0[start_col].index_range(start_ind..end_ind)?;
Some(VectoredSubset::from_single_slice(range, col_substring))
} else {
Some(VectoredSubset {
range,
start: Some(self.0[start_col].index_range(start_ind..)?),
directly_referenced: &self.0[(start_col + 1)..end_col],
end: Some(self.0[end_col].index_range(..end_ind)?),
})
}
}
pub fn index_range(&self, range: ops::Range<usize>) -> Option<VectoredSubset<'string, 'slice>> {
let ops::Range { start, end } = range.clone();
let range: Range = range.into();
let (start_col, start_ind) = self.find_index_at(0, 0, start)?;
let (end_col, end_ind) = self.find_index_at(start_col, start_ind, end - start)?;
self.collect_slices_range(range, (start_col, start_ind), (end_col, end_ind))
}
pub fn as_slices(&self) -> &'slice [ByteSlice<'string>] { unsafe { mem::transmute(self.0) } }
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct VectoredSubset<'string, 'slice> {
pub range: Range,
start: Option<ByteSlice<'string>>,
directly_referenced: &'slice [ByteSlice<'string>],
end: Option<ByteSlice<'string>>,
}
impl<'string, 'slice> VectoredSubset<'string, 'slice> {
pub(crate) fn from_single_slice(range: Range, data: ByteSlice<'string>) -> Self {
Self {
range,
start: Some(data),
directly_referenced: &[],
end: None,
}
}
pub fn iter_slices(
&self,
) -> impl ExactSizeIterator<Item=ByteSlice<'string>>+DoubleEndedIterator+'_ {
VectorIter::new(self)
}
}
struct VectorIter<'string, 'slice> {
done_start: Option<&'slice ByteSlice<'string>>,
done_inner: slice::Iter<'slice, ByteSlice<'string>>,
done_end: Option<&'slice ByteSlice<'string>>,
}
impl<'string, 'slice> VectorIter<'string, 'slice> {
pub fn new(data: &'slice VectoredSubset<'string, 'slice>) -> Self {
Self {
done_start: data.start.as_ref(),
done_inner: data.directly_referenced.iter(),
done_end: data.end.as_ref(),
}
}
fn remaining_len(&self) -> usize {
let mut len: usize = 0;
if self.done_start.is_some() {
len += 1;
}
len += self.done_inner.as_slice().len();
if self.done_end.is_some() {
len += 1;
}
len
}
}
impl<'string, 'slice> Iterator for VectorIter<'string, 'slice> {
type Item = ByteSlice<'string>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(start) = self.done_start.take() {
return Some(*start);
}
if let Some(inner) = self.done_inner.next() {
return Some(*inner);
}
if let Some(end) = self.done_end.take() {
return Some(*end);
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
let rem = self.remaining_len();
(rem, Some(rem))
}
}
impl<'string, 'slice> ExactSizeIterator for VectorIter<'string, 'slice> {}
impl<'string, 'slice> DoubleEndedIterator for VectorIter<'string, 'slice> {
fn next_back(&mut self) -> Option<Self::Item> {
if let Some(end) = self.done_end.take() {
return Some(*end);
}
if let Some(inner) = self.done_inner.next_back() {
return Some(*inner);
}
if let Some(start) = self.done_start.take() {
return Some(*start);
}
None
}
}
}
#[cfg(feature = "vectored")]
#[cfg_attr(docsrs, doc(cfg(feature = "vectored")))]
pub use vectored::{VectoredByteSlices, VectoredSubset};
#[allow(missing_docs)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Range {
pub from: usize,
pub to: usize,
}
static_assertions::assert_eq_size!(Range, ops::Range<usize>);
static_assertions::assert_eq_size!(usize, c_ulonglong);
static_assertions::assert_eq_size!((c_ulonglong, c_ulonglong), ops::Range<usize>);
impl Range {
#[allow(missing_docs)]
pub const fn from_range(x: ops::Range<usize>) -> Self {
let ops::Range { start, end } = x;
Self {
from: start,
to: end,
}
}
#[allow(missing_docs)]
pub const fn into_range(self) -> ops::Range<usize> {
let Self { from, to } = self;
from..to
}
pub const fn len(&self) -> usize {
assert!(self.to >= self.from);
self.to - self.from
}
pub const fn is_empty(&self) -> bool { self.len() == 0 }
}
impl From<ops::Range<usize>> for Range {
fn from(x: ops::Range<usize>) -> Self { Self::from_range(x) }
}
impl From<Range> for ops::Range<usize> {
fn from(x: Range) -> Self { x.into_range() }
}