use proc_macro2::{Ident, TokenStream};
use quote::quote;
pub fn escape_new(name: &Ident) -> TokenStream {
quote! {
pub struct #name<'a> {
bytes: &'a [u8],
}
impl<'a> #name<'a> {
#[inline]
pub fn new(bytes: &[u8]) -> #name {
#name { bytes }
}
}
impl<'a> From<&'a str> for #name<'a> {
#[inline]
fn from(s: &str) -> #name {
#name {
bytes: s.as_bytes(),
}
}
}
#[inline]
pub fn escape(s: &str) -> #name {
#name::from(s)
}
impl<'a> std::fmt::Display for #name<'a> {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
#[allow(unused_unsafe)]
unsafe {
_escape(self.bytes, fmt)
}
}
}
#[cfg(feature = "bytes-buf")]
#[inline]
pub fn b_escape<B: buf_min::Buffer>(s: &[u8], buf: &mut B) {
#[allow(unused_unsafe)]
unsafe {
_b_escape(s, buf)
}
}
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
#[inline(always)]
fn _escape(bytes: &[u8], fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
use std::mem;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::fmt::{self, Formatter};
static mut FN: fn(&[u8], &mut Formatter) -> fmt::Result = detect;
fn detect(bytes: &[u8], fmt: &mut Formatter) -> fmt::Result {
let fun = if is_x86_feature_detected!("avx2") {
ranges::avx::escape as usize
} else if is_x86_feature_detected!("sse2") {
ranges::sse::escape as usize
} else {
scalar::_escape as usize
};
let slot = unsafe { &*(&FN as *const _ as *const AtomicUsize) };
slot.store(fun, Ordering::Relaxed);
unsafe {
mem::transmute::<usize, fn(&[u8], &mut Formatter) -> fmt::Result>(fun)(
bytes, fmt,
)
}
}
unsafe {
let slot = &*(&FN as *const _ as *const AtomicUsize);
let fun = slot.load(Ordering::Relaxed);
mem::transmute::<usize, fn(&[u8], &mut Formatter) -> fmt::Result>(fun)(bytes, fmt)
}
}
#[inline(always)]
#[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))]
fn _escape(bytes: &[u8], fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
scalar::_escape(bytes, fmt)
}
#[inline(always)]
#[cfg(feature = "bytes-buf")]
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
pub unsafe fn _b_escape<B: buf_min::Buffer>(bytes: &[u8], buf: &mut B) {
#[cfg(not(v_escape_avx))] {
#[cfg(not(v_escape_sse))] {
scalar::b_escape(bytes, buf)
}
#[cfg(v_escape_sse)] {
ranges::sse::b_escape(bytes, buf)
}
}
#[cfg(v_escape_avx)] {
ranges::avx::b_escape(bytes, buf)
}
}
#[inline(always)]
#[cfg(feature = "bytes-buf")]
#[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))]
pub unsafe fn _b_escape<B: buf_min::Buffer>(bytes: &[u8], buf: &mut B) {
scalar::b_escape(bytes, buf)
}
}
}