mod unquoted_attribute;
use core::str::from_utf8_unchecked;
use alloc::borrow::Cow;
use alloc::string::String;
use alloc::vec::Vec;
#[cfg(feature = "std")]
use std::io::{self, Write};
pub use unquoted_attribute::*;
macro_rules! escape_impl {
(@inner [$dollar:tt] $name:ident; $($l:expr => $r:expr),+ $(,)*) => {
macro_rules! $name {
($dollar e:expr) => {
match $dollar e {
$($l => break $r,)+
_ => (),
}
};
(vec $dollar e:expr, $dollar v:ident, $dollar b:ident, $dollar start:ident, $dollar end:ident) => {
match $dollar e {
$($l => {
$dollar v.extend_from_slice(&$dollar b[$dollar start..$dollar end]);
$dollar start = $dollar end + 1;
$dollar v.extend_from_slice($r);
})+
_ => (),
}
$dollar end += 1;
};
(writer $dollar e:expr, $dollar w:ident, $dollar b:ident, $dollar start:ident, $dollar end:ident) => {
match $dollar e {
$($l => {
$dollar w.write_all(&$dollar b[$dollar start..$dollar end])?;
$dollar start = $dollar end + 1;
$dollar w.write_all($r)?;
})+
_ => (),
}
$dollar end += 1;
};
}
};
($name:ident; $($l:expr => $r:expr),+ $(,)*) => {
escape_impl! {
@inner [$]
$name;
$($l => $r.as_ref(),)*
}
};
}
escape_impl! {
escape_text_minimal;
b'&' => b"&",
b'<' => b"<",
}
escape_impl! {
escape_text;
b'&' => b"&",
b'<' => b"<",
b'>' => b">",
}
escape_impl! {
escape_double_quote;
b'&' => b"&",
b'<' => b"<",
b'>' => b">",
b'"' => b""",
}
escape_impl! {
escape_single_quote;
b'&' => b"&",
b'<' => b"<",
b'>' => b">",
b'\'' => b"'",
}
escape_impl! {
escape_quote;
b'&' => b"&",
b'<' => b"<",
b'>' => b">",
b'"' => b""",
b'\'' => b"'",
}
escape_impl! {
escape_safe;
b'&' => b"&",
b'<' => b"<",
b'>' => b">",
b'"' => b""",
b'\'' => b"'",
b'/' => b"/",
}
macro_rules! encode_impl {
($(#[$attr: meta])* $escape_macro:ident; $(#[$encode_attr: meta])* $encode_name: ident; $(#[$encode_to_string_attr: meta])* $encode_to_string_name: ident; $(#[$encode_to_vec_attr: meta])* $encode_to_vec_name: ident; $(#[$encode_to_writer_attr: meta])* $encode_to_writer_name: ident $(;)*) => {
$(#[$encode_attr])*
$(#[$attr])*
#[inline]
pub fn $encode_name<S: ?Sized + AsRef<str>>(text: &S) -> Cow<str> {
let text = text.as_ref();
let text_bytes = text.as_bytes();
let text_length = text_bytes.len();
let mut p = 0;
let mut e;
let first = loop {
if p == text_length {
return Cow::from(text);
}
e = text_bytes[p];
$escape_macro!(e);
p += 1;
};
let mut v = Vec::with_capacity(text_length + 5);
v.extend_from_slice(&text_bytes[..p]);
v.extend_from_slice(first);
$encode_to_vec_name(unsafe { from_utf8_unchecked(&text_bytes[(p + 1)..]) }, &mut v);
Cow::from(unsafe { String::from_utf8_unchecked(v) })
}
$(#[$encode_to_string_attr])*
$(#[$attr])*
#[inline]
pub fn $encode_to_string_name<S: AsRef<str>>(text: S, output: &mut String) -> &str {
unsafe { from_utf8_unchecked($encode_to_vec_name(text, output.as_mut_vec())) }
}
$(#[$encode_to_vec_attr])*
$(#[$attr])*
#[inline]
pub fn $encode_to_vec_name<S: AsRef<str>>(text: S, output: &mut Vec<u8>) -> &[u8] {
let text = text.as_ref();
let text_bytes = text.as_bytes();
let text_length = text_bytes.len();
output.reserve(text_length);
let current_length = output.len();
let mut start = 0;
let mut end = 0;
for e in text_bytes.iter().copied() {
$escape_macro!(vec e, output, text_bytes, start, end);
}
output.extend_from_slice(&text_bytes[start..end]);
&output[current_length..]
}
#[cfg(feature = "std")]
$(#[$encode_to_writer_attr])*
$(#[$attr])*
#[inline]
pub fn $encode_to_writer_name<S: AsRef<str>, W: Write>(text: S, output: &mut W) -> Result<(), io::Error> {
let text = text.as_ref();
let text_bytes = text.as_bytes();
let mut start = 0;
let mut end = 0;
for e in text_bytes.iter().copied() {
$escape_macro!(writer e, output, text_bytes, start, end);
}
output.write_all(&text_bytes[start..end])
}
};
}
encode_impl! {
escape_text_minimal;
encode_text_minimal;
encode_text_minimal_to_string;
encode_text_minimal_to_vec;
encode_text_minimal_to_writer;
}
encode_impl! {
escape_text;
encode_text;
encode_text_to_string;
encode_text_to_vec;
encode_text_to_writer;
}
encode_impl! {
escape_double_quote;
encode_double_quoted_attribute;
encode_double_quoted_attribute_to_string;
encode_double_quoted_attribute_to_vec;
encode_double_quoted_attribute_to_writer;
}
encode_impl! {
escape_single_quote;
encode_single_quoted_attribute;
encode_single_quoted_attribute_to_string;
encode_single_quoted_attribute_to_vec;
encode_single_quoted_attribute_to_writer;
}
encode_impl! {
escape_quote;
encode_quoted_attribute;
encode_quoted_attribute_to_string;
encode_quoted_attribute_to_vec;
encode_quoted_attribute_to_writer;
}
encode_impl! {
escape_safe;
encode_safe;
encode_safe_to_string;
encode_safe_to_vec;
encode_safe_to_writer;
}