use std::borrow::{Borrow, Cow};
use std::fmt::{self, Debug, Formatter};
use std::iter::FusedIterator;
use std::ops::Deref;
use oxixml_support::bytes::{memchr, memchr3};
#[cfg(feature = "serialize")]
use serde::de::{Deserialize, Deserializer, Error, Visitor};
#[cfg(feature = "serialize")]
use serde::ser::{Serialize, Serializer};
#[allow(clippy::ptr_arg)]
pub fn write_cow_string(f: &mut Formatter, cow_string: &Cow<[u8]>) -> fmt::Result {
match cow_string {
Cow::Owned(s) => {
write!(f, "Owned(")?;
write_byte_string(f, s)?;
}
Cow::Borrowed(s) => {
write!(f, "Borrowed(")?;
write_byte_string(f, s)?;
}
}
write!(f, ")")
}
pub fn write_byte_string(f: &mut Formatter, byte_string: &[u8]) -> fmt::Result {
write!(f, "\"")?;
for b in byte_string {
match *b {
32..=33 | 35..=126 => write!(f, "{}", *b as char)?,
34 => write!(f, "\\\"")?,
_ => write!(f, "{:#02X}", b)?,
}
}
write!(f, "\"")?;
Ok(())
}
pub enum CowRef<'i, 's, B>
where
B: ToOwned + ?Sized,
{
Input(&'i B),
Slice(&'s B),
Owned(<B as ToOwned>::Owned),
}
impl<B> Deref for CowRef<'_, '_, B>
where
B: ToOwned + ?Sized,
B::Owned: Borrow<B>,
{
type Target = B;
fn deref(&self) -> &B {
match *self {
Self::Input(borrowed) => borrowed,
Self::Slice(borrowed) => borrowed,
Self::Owned(ref owned) => owned.borrow(),
}
}
}
impl<B> Debug for CowRef<'_, '_, B>
where
B: ToOwned + ?Sized + Debug,
B::Owned: Debug,
{
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match *self {
Self::Input(borrowed) => Debug::fmt(borrowed, f),
Self::Slice(borrowed) => Debug::fmt(borrowed, f),
Self::Owned(ref owned) => Debug::fmt(owned, f),
}
}
}
impl<'i> CowRef<'i, '_, str> {
#[cfg(feature = "serialize")]
pub fn deserialize_str<V, E>(self, visitor: V) -> Result<V::Value, E>
where
V: Visitor<'i>,
E: Error,
{
match self {
Self::Input(s) => visitor.visit_borrowed_str(s),
Self::Slice(s) => visitor.visit_str(s),
Self::Owned(s) => visitor.visit_string(s),
}
}
#[cfg(feature = "serialize")]
pub fn deserialize_bool<V, E>(self, visitor: V) -> Result<V::Value, E>
where
V: Visitor<'i>,
E: Error,
{
match self.as_ref() {
"1" | "true" => visitor.visit_bool(true),
"0" | "false" => visitor.visit_bool(false),
_ => self.deserialize_str(visitor),
}
}
}
#[cfg_attr(
feature = "serialize",
doc = "[`deserialize_byte_buf`](serde::Deserializer::deserialize_byte_buf) instead of the \
vector's generic [`deserialize_seq`](serde::Deserializer::deserialize_seq)."
)]
#[cfg_attr(
not(feature = "serialize"),
doc = "`Deserializer::deserialize_byte_buf` instead of the vector's generic \
`Deserializer::deserialize_seq`."
)]
#[derive(PartialEq, Eq)]
pub struct ByteBuf(pub Vec<u8>);
impl Debug for ByteBuf {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write_byte_string(f, &self.0)
}
}
#[cfg(feature = "serialize")]
impl<'de> Deserialize<'de> for ByteBuf {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct ValueVisitor;
impl<'de> Visitor<'de> for ValueVisitor {
type Value = ByteBuf;
fn expecting(&self, f: &mut Formatter) -> fmt::Result {
f.write_str("byte data")
}
fn visit_bytes<E: Error>(self, v: &[u8]) -> Result<Self::Value, E> {
Ok(ByteBuf(v.to_vec()))
}
fn visit_byte_buf<E: Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
Ok(ByteBuf(v))
}
}
d.deserialize_byte_buf(ValueVisitor)
}
}
#[cfg(feature = "serialize")]
impl Serialize for ByteBuf {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_bytes(&self.0)
}
}
#[cfg_attr(
feature = "serialize",
doc = "[`deserialize_bytes`](serde::Deserializer::deserialize_bytes) instead of the \
vector's generic [`deserialize_seq`](serde::Deserializer::deserialize_seq)."
)]
#[cfg_attr(
not(feature = "serialize"),
doc = "`Deserializer::deserialize_bytes` instead of the vector's generic \
`Deserializer::deserialize_seq`."
)]
#[derive(PartialEq, Eq)]
pub struct Bytes<'de>(pub &'de [u8]);
impl<'de> Debug for Bytes<'de> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write_byte_string(f, self.0)
}
}
#[cfg(feature = "serialize")]
impl<'de> Deserialize<'de> for Bytes<'de> {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct ValueVisitor;
impl<'de> Visitor<'de> for ValueVisitor {
type Value = Bytes<'de>;
fn expecting(&self, f: &mut Formatter) -> fmt::Result {
f.write_str("borrowed bytes")
}
fn visit_borrowed_bytes<E: Error>(self, v: &'de [u8]) -> Result<Self::Value, E> {
Ok(Bytes(v))
}
}
d.deserialize_bytes(ValueVisitor)
}
}
#[cfg(feature = "serialize")]
impl<'de> Serialize for Bytes<'de> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_bytes(self.0)
}
}
#[inline]
pub const fn is_whitespace(b: u8) -> bool {
matches!(b, b' ' | b'\r' | b'\n' | b'\t')
}
#[derive(Debug)]
pub(crate) struct MemchrIter<'a> {
haystack: &'a [u8],
offset: usize,
needles: [u8; 3],
count: u8,
}
impl<'a> MemchrIter<'a> {
#[inline]
pub(crate) const fn one(needle: u8, haystack: &'a [u8]) -> Self {
Self {
haystack,
offset: 0,
needles: [needle, 0, 0],
count: 1,
}
}
#[inline]
pub(crate) const fn three(n1: u8, n2: u8, n3: u8, haystack: &'a [u8]) -> Self {
Self {
haystack,
offset: 0,
needles: [n1, n2, n3],
count: 3,
}
}
}
impl Iterator for MemchrIter<'_> {
type Item = usize;
#[inline]
fn next(&mut self) -> Option<usize> {
let rest = &self.haystack[self.offset..];
let found = if self.count == 1 {
memchr(self.needles[0], rest)
} else {
memchr3(self.needles[0], self.needles[1], self.needles[2], rest)
};
found.map(|i| {
let absolute = self.offset + i;
self.offset = absolute + 1;
absolute
})
}
}
impl FusedIterator for MemchrIter<'_> {}
#[inline]
pub(crate) fn memchr_iter(needle: u8, haystack: &[u8]) -> MemchrIter<'_> {
MemchrIter::one(needle, haystack)
}
#[inline]
pub(crate) fn memchr3_iter(n1: u8, n2: u8, n3: u8, haystack: &[u8]) -> MemchrIter<'_> {
MemchrIter::three(n1, n2, n3, haystack)
}
#[inline]
pub const fn name_len(mut bytes: &[u8]) -> usize {
let mut len = 0;
while let [first, rest @ ..] = bytes {
if is_whitespace(*first) {
break;
}
len += 1;
bytes = rest;
}
len
}
#[inline]
pub const fn trim_xml_start(mut bytes: &[u8]) -> &[u8] {
while let [first, rest @ ..] = bytes {
if is_whitespace(*first) {
bytes = rest;
} else {
break;
}
}
bytes
}
#[inline]
pub const fn trim_xml_end(mut bytes: &[u8]) -> &[u8] {
while let [rest @ .., last] = bytes {
if is_whitespace(*last) {
bytes = rest;
} else {
break;
}
}
bytes
}
#[inline]
pub fn trim_xml_spaces(text: &str) -> &str {
let bytes = trim_xml_end(trim_xml_start(text.as_bytes()));
core::str::from_utf8(bytes).unwrap_or_default()
}
#[derive(Debug, Clone)]
pub(crate) struct CDataIterator<'a> {
unprocessed: &'a str,
finished: bool,
}
impl<'a> CDataIterator<'a> {
pub const fn new(value: &'a str) -> Self {
Self {
unprocessed: value,
finished: false,
}
}
}
impl<'a> Iterator for CDataIterator<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<&'a str> {
if self.finished {
return None;
}
let bytes = self.unprocessed.as_bytes();
let mut base = 0;
while let Some(rel) = memchr(b'>', &bytes[base..]) {
let gt = base + rel;
let (slice, rest) = self.unprocessed.split_at(gt);
if slice.ends_with("]]") {
self.unprocessed = rest;
return Some(slice);
}
base = gt + 1;
}
self.finished = true;
Some(self.unprocessed)
}
}
impl FusedIterator for CDataIterator<'_> {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn write_byte_string_hex_and_ascii() {
let bytes = ByteBuf(vec![10, 32, 32, 32, 32, 32, 32, 32, 32]);
assert_eq!(format!("{:?}", bytes), "\"0xA \"");
}
#[test]
fn write_byte_string_url() {
let bytes = ByteBuf(b"http://www.w3.org/2002/07/owl#".to_vec());
assert_eq!(
format!("{:?}", bytes),
r##""http://www.w3.org/2002/07/owl#""##
);
}
#[test]
fn write_byte_string_quote() {
let bytes = ByteBuf(b"Class IRI=\"#B\"".to_vec());
assert_eq!(format!("{:?}", bytes), r##""Class IRI=\"#B\"""##);
}
#[test]
fn name_len_boundaries() {
assert_eq!(super::name_len(b""), 0);
assert_eq!(super::name_len(b" abc"), 0);
assert_eq!(super::name_len(b" \t\r\n"), 0);
assert_eq!(super::name_len(b"abc"), 3);
assert_eq!(super::name_len(b"abc "), 3);
assert_eq!(super::name_len(b"a bc"), 1);
assert_eq!(super::name_len(b"ab\tc"), 2);
assert_eq!(super::name_len(b"ab\rc"), 2);
assert_eq!(super::name_len(b"ab\nc"), 2);
}
#[test]
fn trim_start() {
assert_eq!(Bytes(super::trim_xml_start(b"")), Bytes(b""));
assert_eq!(Bytes(super::trim_xml_start(b"abc")), Bytes(b"abc"));
assert_eq!(
Bytes(super::trim_xml_start(b"\r\n\t ab \t\r\nc \t\r\n")),
Bytes(b"ab \t\r\nc \t\r\n")
);
}
#[test]
fn trim_end() {
assert_eq!(Bytes(super::trim_xml_end(b"")), Bytes(b""));
assert_eq!(Bytes(super::trim_xml_end(b"abc")), Bytes(b"abc"));
assert_eq!(
Bytes(super::trim_xml_end(b"\r\n\t ab \t\r\nc \t\r\n")),
Bytes(b"\r\n\t ab \t\r\nc")
);
}
#[test]
fn cdata_split() {
let pieces: Vec<_> = CDataIterator::new("foo]]>bar]]>baz").collect();
assert_eq!(pieces, vec!["foo]]", ">bar]]", ">baz"]);
let pieces: Vec<_> = CDataIterator::new("no marker").collect();
assert_eq!(pieces, vec!["no marker"]);
}
}