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
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//! # Quick start
//!
//! ```
//! use v_jsonescape::escape;
//!
//! print!("{}", escape("foo<bar"));
//! ```
//!
// https://tools.ietf.org/id/draft-ietf-json-rfc4627bis-09.html#rfc.section.7
// https://github.com/serde-rs/json/blob/master/src/ser.rs#L2113-L2143
macro_rules! build {
    ($($t:tt)*) => {
        v_escape::new!(
            JSONEscape,
            "0x00->\\u0000 || \
            0x01->\\u0001 || \
            0x02->\\u0002 || \
            0x03->\\u0003 || \
            0x04->\\u0004 || \
            0x05->\\u0005 || \
            0x06->\\u0006 || \
            0x07->\\u0007 || \
            0x08->\\b || \
            0x09->\\t || \
            0x0A->\\n || \
            0x0B->\\u000b || \
            0x0C->\\f || \
            0x0D->\\r || \
            0x0E->\\u000e || \
            0x0F->\\u000f || \
            0x10->\\u0010 || \
            0x11->\\u0011 || \
            0x12->\\u0012 || \
            0x13->\\u0013 || \
            0x14->\\u0014 || \
            0x15->\\u0015 || \
            0x16->\\u0016 || \
            0x17->\\u0017 || \
            0x18->\\u0018 || \
            0x19->\\u0019 || \
            0x1A->\\u001a || \
            0x1B->\\u001b || \
            0x1C->\\u001c || \
            0x1D->\\u001d || \
            0x1E->\\u001e || \
            0x1F->\\u001f || \
            0x22->\\\" || \
            0x5C->\\\\",
            $($t)*
        );
    };
}

/// Without simd optimizations
pub mod fallback {
    build!(simd = false);
}

cfg_if::cfg_if! {
    if #[cfg(all(v_jsonescape_simd, v_jsonescape_avx))] {
        build!(simd = true, avx = true);
    } else if #[cfg(all(v_jsonescape_simd, v_jsonescape_sse))] {
        build!(simd = true, avx = false);
    } else {
        pub use self::fallback::*;
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_escape() {
        use super::*;

        let empty = "";
        assert_eq!(escape(empty).to_string(), empty);
        let tests = &[
            ('n', "n"),
            ('"', "\\\""),
            ('\\', "\\\\"),
            ('/', "/"),
            ('\x08', "\\b"),
            ('\x0C', "\\f"),
            ('\n', "\\n"),
            ('\r', "\\r"),
            ('\t', "\\t"),
            ('\x0B', "\\u000b"),
            ('\u{3A3}', "\u{3A3}"),
        ];
        for (c, e) in tests {
            assert_eq!(escape_char(*c).to_string(), *e);
            assert_eq!(escape(&c.to_string()).to_string(), *e);
        }
        let tests = tests
            .into_iter()
            .fold((String::new(), String::new()), |mut acc, (c, e)| {
                acc.0.push(*c);
                acc.1.push_str(e);
                acc
            });

        assert_eq!(escape(&tests.0).to_string(), tests.1);
        assert_eq!(escape(&tests.0.repeat(2)).to_string(), tests.1.repeat(2));
        assert_eq!(escape(&tests.0.repeat(4)).to_string(), tests.1.repeat(4));
        assert_eq!(escape(&tests.0.repeat(16)).to_string(), tests.1.repeat(16));
        assert_eq!(
            escape(&tests.0.repeat(128)).to_string(),
            tests.1.repeat(128)
        );

        let tests = &[("", ""), ("foo", "foo")];
        for (c, e) in tests {
            assert_eq!(escape(c).to_string(), *e);
        }
    }
}