1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#[macro_use]
extern crate cfg_if;

use std::fmt::{self, Display, Formatter};
use std::str;

#[macro_use]
mod utils;

use utils::*;

/// Html escape formatter
pub struct Escape<'a> {
    bytes: &'a [u8],
}

#[allow(dead_code)]
impl<'a> Escape<'a> {
    pub fn new(s: &[u8]) -> Escape {
        Escape { bytes: s }
    }
}

impl<'a> Display for Escape<'a> {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        _imp(self.bytes, fmt)
    }
}

cfg_if! {
    if #[cfg(all(target_arch = "x86_64", not(target_os = "windows"), v_escape_simd))] {

        use std::mem;
        use std::sync::atomic::{AtomicUsize, Ordering};
        mod avx;
        mod sse;

        #[inline(always)]
        fn _imp(bytes: &[u8], fmt: &mut Formatter) -> fmt::Result {
            // https://github.com/BurntSushi/rust-memchr/blob/master/src/x86/mod.rs#L9-L29
            static mut FN: fn(bytes: &[u8], fmt: &mut Formatter) -> fmt::Result = detect;

            fn detect(bytes: &[u8], fmt: &mut Formatter) -> fmt::Result {
                let fun = if cfg!(v_escape_avx) && is_x86_feature_detected!("avx2") {
                    avx::escape as usize
                } else if cfg!(v_escape_sse) && is_x86_feature_detected!("sse4.2") {
                    sse::escape as usize
                } else {
                    _escape as usize
                };

                let slot = unsafe { &*(&FN as *const _ as *const AtomicUsize) };
                slot.store(fun as usize, Ordering::Relaxed);
                unsafe {
                    mem::transmute::<usize, fn(bytes: &[u8], fmt: &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(bytes: &[u8], fmt: &mut Formatter) -> fmt::Result>(fun)(bytes, fmt)
            }
        }
    } else {

        #[inline(always)]
        fn _imp(bytes: &[u8], fmt: &mut Formatter) -> fmt::Result {
            _escape(bytes, fmt)
        }
    }
}

/// Scalar html escape
#[inline]
fn _escape(bytes: &[u8], fmt: &mut Formatter) -> fmt::Result {
    let mut start = 0;

    for (i, b) in bytes.iter().enumerate() {
        bodies!(i, *b, start, fmt, bytes, escape_body);
    }

    fmt.write_str(unsafe { str::from_utf8_unchecked(&bytes[start..]) })?;

    Ok(())
}