use core::convert::TryInto;
use core::slice::Iter as SliceIter;
use core::{iter, str};
use crate::display::InputDisplay;
use crate::error::{
with_context, ExpectedContext, ExpectedLength, ExpectedValid, Length, OperationContext,
WithContext,
};
use crate::fmt;
use crate::util::{slice, utf8};
use super::{Bound, Input, MaybeString, Private, PrivateExt, String};
#[derive(Clone)]
#[must_use = "input must be consumed"]
pub struct Bytes<'i> {
value: &'i [u8],
#[cfg(feature = "retry")]
bound: Bound,
}
impl<'i> Bytes<'i> {
#[cfg(feature = "retry")]
#[inline(always)]
pub(crate) fn new(value: &'i [u8], bound: Bound) -> Self {
Self { value, bound }
}
#[cfg(not(feature = "retry"))]
#[inline(always)]
pub(crate) fn new(value: &'i [u8], _bound: Bound) -> Self {
Self { value }
}
#[must_use]
#[inline(always)]
pub fn len(&self) -> usize {
self.as_dangerous().len()
}
#[must_use]
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.as_dangerous().is_empty()
}
#[must_use]
pub fn count(&self, needle: u8) -> usize {
#[cfg(feature = "bytecount")]
{
bytecount::count(self.as_dangerous(), needle)
}
#[cfg(not(feature = "bytecount"))]
{
self.as_dangerous()
.iter()
.copied()
.filter(|b| *b == needle)
.count()
}
}
#[must_use]
#[inline(always)]
pub fn as_dangerous(&self) -> &'i [u8] {
self.value
}
#[inline(always)]
pub fn to_dangerous_str<E>(&self) -> Result<&'i str, E>
where
E: From<ExpectedValid<'i>>,
E: From<ExpectedLength<'i>>,
{
str::from_utf8(self.as_dangerous()).map_err(|err| {
self.clone()
.map_utf8_error(err.error_len(), err.valid_up_to(), "convert input to str")
})
}
pub fn to_dangerous_non_empty<E>(&self) -> Result<&'i [u8], E>
where
E: From<ExpectedLength<'i>>,
{
if self.is_empty() {
Err(E::from(ExpectedLength {
len: Length::AtLeast(1),
span: self.as_dangerous(),
input: self.clone().into_maybe_string(),
context: ExpectedContext {
operation: "convert input to non-empty slice",
expected: "non-empty input",
},
}))
} else {
Ok(self.as_dangerous())
}
}
pub fn to_dangerous_non_empty_str<E>(&self) -> Result<&'i str, E>
where
E: From<ExpectedValid<'i>>,
E: From<ExpectedLength<'i>>,
{
if self.is_empty() {
Err(E::from(ExpectedLength {
len: Length::AtLeast(1),
span: self.as_dangerous(),
input: self.clone().into_maybe_string(),
context: ExpectedContext {
operation: "convert input to non-empty str",
expected: "non empty input",
},
}))
} else {
self.to_dangerous_str()
}
}
#[inline(always)]
pub fn into_string<E>(self) -> Result<String<'i>, E>
where
E: From<ExpectedValid<'i>>,
E: From<ExpectedLength<'i>>,
{
self.to_dangerous_str()
.map(|s| String::new(s, self.bound()))
}
}
impl<'i> Input<'i> for Bytes<'i> {
#[cfg(feature = "retry")]
#[inline(always)]
fn bound(&self) -> Bound {
self.bound
}
#[cfg(not(feature = "retry"))]
#[inline(always)]
fn bound(&self) -> Bound {
Bound::Both
}
#[cfg(feature = "retry")]
#[inline(always)]
fn into_bound(mut self) -> Self {
self.bound = Bound::force_close();
self
}
#[cfg(not(feature = "retry"))]
#[inline(always)]
fn into_bound(self) -> Self {
self
}
#[inline(always)]
fn into_bytes(self) -> Bytes<'i> {
self
}
#[inline(always)]
fn into_maybe_string(self) -> MaybeString<'i> {
MaybeString::Bytes(self)
}
#[inline(always)]
fn display(&self) -> InputDisplay<'i> {
InputDisplay::new(self)
}
}
impl<'i> Bytes<'i> {
#[inline(always)]
pub(crate) fn split_str_while<F, E>(
self,
mut f: F,
operation: &'static str,
) -> Result<(String<'i>, Bytes<'i>), E>
where
E: From<ExpectedValid<'i>>,
E: From<ExpectedLength<'i>>,
F: FnMut(char) -> bool,
{
let bytes = self.as_dangerous();
let mut chars = utf8::CharIter::new(bytes);
let mut consumed = chars.as_forward();
while let Some(result) = chars.next() {
match result {
Ok(c) if f(c) => {
consumed = chars.as_forward();
}
Ok(_) => {
let head = String::new(consumed, self.bound().close_end());
let tail = Bytes::new(&bytes[consumed.as_bytes().len()..], self.bound());
return Ok((head, tail));
}
Err(utf8_err) => {
return Err(self.map_utf8_error(
utf8_err.error_len(),
consumed.as_bytes().len(),
operation,
))
}
}
}
Ok((String::new(consumed, self.bound()), self.end()))
}
#[inline(always)]
pub(crate) fn try_split_str_while<F, E>(
self,
mut f: F,
operation: &'static str,
) -> Result<(String<'i>, Bytes<'i>), E>
where
E: WithContext<'i>,
E: From<ExpectedValid<'i>>,
E: From<ExpectedLength<'i>>,
F: FnMut(char) -> Result<bool, E>,
{
let bytes = self.as_dangerous();
let mut chars = utf8::CharIter::new(bytes);
let mut consumed = chars.as_forward();
while let Some(result) = chars.next() {
match result {
Ok(c) => {
if with_context(self.clone(), OperationContext(operation), || f(c))? {
consumed = chars.as_forward();
} else {
let head = String::new(consumed, self.bound().close_end());
let tail = Bytes::new(&bytes[consumed.as_bytes().len()..], self.bound());
return Ok((head, tail));
}
}
Err(utf8_err) => {
return Err(self.map_utf8_error(
utf8_err.error_len(),
consumed.as_bytes().len(),
operation,
))
}
}
}
Ok((String::new(consumed, self.bound()), self.end()))
}
#[inline(always)]
pub(crate) fn split_arr_2<E>(self, operation: &'static str) -> Result<([u8; 2], Bytes<'i>), E>
where
E: From<ExpectedLength<'i>>,
{
match self.split_at(2, operation) {
Ok((head, tail)) => Ok((head.as_dangerous().try_into().unwrap(), tail)),
Err(err) => Err(err),
}
}
#[inline(always)]
pub(crate) fn split_arr_4<E>(self, operation: &'static str) -> Result<([u8; 4], Bytes<'i>), E>
where
E: From<ExpectedLength<'i>>,
{
match self.split_at(4, operation) {
Ok((head, tail)) => Ok((head.as_dangerous().try_into().unwrap(), tail)),
Err(err) => Err(err),
}
}
#[inline(always)]
pub(crate) fn split_arr_8<E>(self, operation: &'static str) -> Result<([u8; 8], Bytes<'i>), E>
where
E: From<ExpectedLength<'i>>,
{
match self.split_at(8, operation) {
Ok((head, tail)) => Ok((head.as_dangerous().try_into().unwrap(), tail)),
Err(err) => Err(err),
}
}
#[inline(always)]
pub(crate) fn split_arr_16<E>(self, operation: &'static str) -> Result<([u8; 16], Bytes<'i>), E>
where
E: From<ExpectedLength<'i>>,
{
match self.split_at(16, operation) {
Ok((head, tail)) => Ok((head.as_dangerous().try_into().unwrap(), tail)),
Err(err) => Err(err),
}
}
fn map_utf8_error<E>(
self,
error_len: Option<usize>,
valid_up_to: usize,
operation: &'static str,
) -> E
where
E: From<ExpectedValid<'i>>,
E: From<ExpectedLength<'i>>,
{
let bytes = self.as_dangerous();
match error_len {
None => {
let invalid = &bytes[valid_up_to..];
let first_invalid = unsafe { slice::first_unchecked(invalid) };
E::from(ExpectedLength {
len: Length::AtLeast(utf8::char_len(first_invalid)),
span: invalid,
input: self.into_maybe_string(),
context: ExpectedContext {
operation,
expected: "complete utf-8 code point",
},
})
}
Some(error_len) => {
let error_end = valid_up_to + error_len;
E::from(ExpectedValid {
span: &bytes[valid_up_to..error_end],
input: self.into_maybe_string(),
context: ExpectedContext {
operation,
expected: "utf-8 code point",
},
#[cfg(feature = "retry")]
retry_requirement: None,
})
}
}
}
}
impl<'i> Private<'i> for Bytes<'i> {
type Token = u8;
type TokenIter = iter::Enumerate<iter::Copied<SliceIter<'i, u8>>>;
#[inline(always)]
fn end(self) -> Self {
Self::new(slice::end(self.as_dangerous()), self.bound().for_end())
}
#[inline(always)]
fn tokens(self) -> Self::TokenIter {
self.as_dangerous().iter().copied().enumerate()
}
#[cfg(feature = "retry")]
#[inline(always)]
fn into_unbound_end(mut self) -> Self {
self.bound = self.bound.open_end();
self
}
#[cfg(not(feature = "retry"))]
#[inline(always)]
fn into_unbound_end(self) -> Self {
self
}
#[inline(always)]
fn split_at_opt(self, mid: usize) -> Option<(Self, Self)> {
slice::split_at_opt(self.as_dangerous(), mid).map(|(head, tail)| {
let head = Bytes::new(head, self.bound().close_end());
let tail = Bytes::new(tail, self.bound());
(head, tail)
})
}
#[inline(always)]
unsafe fn split_at_byte_unchecked(self, mid: usize) -> (Self, Self) {
let (head, tail) = slice::split_at_unchecked(self.as_dangerous(), mid);
(
Bytes::new(head, self.bound().close_end()),
Bytes::new(tail, self.bound()),
)
}
}
impl<'i> PartialEq for Bytes<'i> {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self.as_dangerous() == other.as_dangerous()
}
}
impl<'i> PartialEq<[u8]> for Bytes<'i> {
#[inline(always)]
fn eq(&self, other: &[u8]) -> bool {
self.as_dangerous() == other
}
}
impl<'i> PartialEq<[u8]> for &Bytes<'i> {
#[inline(always)]
fn eq(&self, other: &[u8]) -> bool {
self.as_dangerous() == other
}
}
impl<'i> PartialEq<&[u8]> for Bytes<'i> {
#[inline(always)]
fn eq(&self, other: &&[u8]) -> bool {
self.as_dangerous() == *other
}
}
impl<'i> PartialEq<Bytes<'i>> for [u8] {
#[inline(always)]
fn eq(&self, other: &Bytes<'i>) -> bool {
self == other.as_dangerous()
}
}
impl<'i> fmt::Debug for Bytes<'i> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let display = InputDisplay::from_formatter(self, f);
f.debug_struct("Bytes")
.field("bound", &self.bound())
.field("value", &display)
.finish()
}
}
impl<'i> fmt::DisplayBase for Bytes<'i> {
fn fmt(&self, w: &mut dyn fmt::Write) -> fmt::Result {
self.display().fmt(w)
}
}
impl<'i> fmt::Display for Bytes<'i> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
InputDisplay::from_formatter(self, f).fmt(f)
}
}
#[cfg(feature = "zc")]
unsafe impl<'i> zc::NoInteriorMut for Bytes<'i> {}