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);
        }
    }
}