use bytes::BufMut;
use std::slice::from_raw_parts;
use crate::executor::utils::consts::NULL;
#[inline(always)]
pub fn write_and_escape_string(writer: &mut Vec<u8>, input: &str) {
format_string(input, writer, true);
}
pub fn write_named_operation(
writer: &mut Vec<u8>,
name: &[u8],
name_write_pos: usize,
input: &str,
) {
let pos = name_write_pos;
debug_assert!(pos <= input.len());
debug_assert!(
pos != 0 || input.starts_with('{'),
"name_write_pos 0 requires input to start with '{{', got: {:?}",
&input[..input.len().min(20)]
);
let name = std::str::from_utf8(name).expect("GraphQL operation names must be valid UTF-8");
writer.put(&b"\""[..]);
if pos == 0 && input.starts_with('{') {
format_string("query ", writer, false);
format_string(name, writer, false);
format_string(" ", writer, false);
format_string(input, writer, false);
writer.put(&b"\""[..]);
return;
}
format_string(&input[..pos], writer, false);
if pos > 0 {
format_string(" ", writer, false);
}
format_string(name, writer, false);
format_string(&input[pos..], writer, false);
writer.put(&b"\""[..]);
}
pub fn write_f64(writer: &mut Vec<u8>, value: f64) {
if !value.is_finite() {
writer.put(NULL);
return;
}
let mut buffer = ryu::Buffer::new();
let s = buffer.format_finite(value);
writer.put(s.as_bytes())
}
pub fn write_u64(writer: &mut Vec<u8>, value: u64) {
let mut buf = itoa::Buffer::new();
writer.put(buf.format(value).as_bytes());
}
pub fn write_i64(writer: &mut Vec<u8>, value: i64) {
let mut buf = itoa::Buffer::new();
writer.put(buf.format(value).as_bytes());
}
#[cfg(not(all(target_feature = "neon", target_arch = "aarch64")))]
use sonic_simd::u8x32;
#[cfg(all(target_feature = "neon", target_arch = "aarch64"))]
use sonic_simd::{bits::NeonBits, u8x16};
use sonic_simd::{BitMask, Mask, Simd};
#[inline(always)]
unsafe fn load_simd_chunk<V: Simd>(ptr: *const u8) -> V {
let chunk = from_raw_parts(ptr, V::LANES);
V::from_slice_unaligned_unchecked(chunk)
}
const QUOTE_TAB: [(u8, [u8; 8]); 256] = [
(6, *b"\\u0000\0\0"),
(6, *b"\\u0001\0\0"),
(6, *b"\\u0002\0\0"),
(6, *b"\\u0003\0\0"),
(6, *b"\\u0004\0\0"),
(6, *b"\\u0005\0\0"),
(6, *b"\\u0006\0\0"),
(6, *b"\\u0007\0\0"),
(2, *b"\\b\0\0\0\0\0\0"),
(2, *b"\\t\0\0\0\0\0\0"),
(2, *b"\\n\0\0\0\0\0\0"),
(6, *b"\\u000b\0\0"),
(2, *b"\\f\0\0\0\0\0\0"),
(2, *b"\\r\0\0\0\0\0\0"),
(6, *b"\\u000e\0\0"),
(6, *b"\\u000f\0\0"),
(6, *b"\\u0010\0\0"),
(6, *b"\\u0011\0\0"),
(6, *b"\\u0012\0\0"),
(6, *b"\\u0013\0\0"),
(6, *b"\\u0014\0\0"),
(6, *b"\\u0015\0\0"),
(6, *b"\\u0016\0\0"),
(6, *b"\\u0017\0\0"),
(6, *b"\\u0018\0\0"),
(6, *b"\\u0019\0\0"),
(6, *b"\\u001a\0\0"),
(6, *b"\\u001b\0\0"),
(6, *b"\\u001c\0\0"),
(6, *b"\\u001d\0\0"),
(6, *b"\\u001e\0\0"),
(6, *b"\\u001f\0\0"),
(0, [0; 8]),
(0, [0; 8]),
(2, *b"\\\"\0\0\0\0\0\0"), (0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(2, *b"\\\\\0\0\0\0\0\0"), (0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
(0, [0; 8]),
];
const NEED_ESCAPED: [u8; 256] = [
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
#[inline(always)]
unsafe fn escape_unchecked(
src_ptr: &mut *const u8,
remaining_bytes: &mut usize,
dst_ptr: &mut *mut u8,
) {
assert!(*remaining_bytes >= 1);
loop {
let byte = *(*src_ptr);
let escape_len = QUOTE_TAB[byte as usize].0 as usize;
assert!(
escape_len != 0,
"char is {}, cnt is {}, NEED_ESCAPED is {}",
byte as char,
escape_len,
NEED_ESCAPED[byte as usize]
);
std::ptr::copy_nonoverlapping(QUOTE_TAB[byte as usize].1.as_ptr(), *dst_ptr, 8);
(*dst_ptr) = (*dst_ptr).add(escape_len);
(*src_ptr) = (*src_ptr).add(1);
(*remaining_bytes) -= 1;
if (*remaining_bytes) == 0 || NEED_ESCAPED[*(*src_ptr) as usize] == 0 {
return;
}
}
}
#[inline(always)]
fn check_cross_page(ptr: *const u8, step: usize) -> bool {
#[cfg(any(target_os = "linux", target_os = "macos"))]
{
let page_size = 4096;
((ptr as usize & (page_size - 1)) + step) > page_size
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
{
true
}
}
#[inline(always)]
fn format_string(input_str: &str, writer: &mut Vec<u8>, need_quote: bool) {
let worst_case_required = input_str.len() * 6 + 32 + 3;
let original_len = writer.len();
writer.reserve(worst_case_required);
#[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
let mut chunk: u8x16;
#[cfg(not(all(target_arch = "aarch64", target_feature = "neon")))]
let mut chunk: u8x32;
#[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
const LANES: usize = 16;
#[cfg(not(all(target_arch = "aarch64", target_feature = "neon")))]
const LANES: usize = 32;
#[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
#[inline]
fn escaped_mask(v: u8x16) -> NeonBits {
let x1f = u8x16::splat(0x1f); let backslash = u8x16::splat(b'\\');
let quote = u8x16::splat(b'"');
let v = v.le(&x1f) | v.eq(&backslash) | v.eq("e);
v.bitmask()
}
#[cfg(not(all(target_arch = "aarch64", target_feature = "neon")))]
#[inline]
fn escaped_mask(v: u8x32) -> u32 {
let x1f = u8x32::splat(0x1f); let backslash = u8x32::splat(b'\\');
let quote = u8x32::splat(b'"');
let v = v.le(&x1f) | v.eq(&backslash) | v.eq("e);
v.bitmask()
}
unsafe {
let input_bytes = input_str.as_bytes();
let mut src_ptr = input_bytes.as_ptr();
let dst_start_ptr = writer.as_mut_ptr().add(original_len);
let mut dst_ptr = dst_start_ptr;
let mut remaining_len: usize = input_bytes.len();
if need_quote {
*dst_ptr = b'"';
dst_ptr = dst_ptr.add(1);
}
while remaining_len >= LANES {
chunk = load_simd_chunk(src_ptr);
chunk
.write_to_slice_unaligned_unchecked(std::slice::from_raw_parts_mut(dst_ptr, LANES));
let mask = escaped_mask(chunk);
if mask.all_zero() {
remaining_len -= LANES;
dst_ptr = dst_ptr.add(LANES);
src_ptr = src_ptr.add(LANES);
} else {
let cn = mask.first_offset();
remaining_len -= cn;
dst_ptr = dst_ptr.add(cn);
src_ptr = src_ptr.add(cn);
escape_unchecked(&mut src_ptr, &mut remaining_len, &mut dst_ptr);
}
}
let mut temp: [u8; LANES] = [0u8; LANES];
while remaining_len > 0 {
chunk = if check_cross_page(src_ptr, LANES) {
std::ptr::copy_nonoverlapping(src_ptr, temp[..].as_mut_ptr(), remaining_len);
load_simd_chunk(temp[..].as_ptr())
} else {
load_simd_chunk(src_ptr)
};
chunk
.write_to_slice_unaligned_unchecked(std::slice::from_raw_parts_mut(dst_ptr, LANES));
let mask = escaped_mask(chunk).clear_high_bits(LANES - remaining_len);
if mask.all_zero() {
dst_ptr = dst_ptr.add(remaining_len);
break;
} else {
let safe_len = mask.first_offset();
remaining_len -= safe_len;
dst_ptr = dst_ptr.add(safe_len);
src_ptr = src_ptr.add(safe_len);
escape_unchecked(&mut src_ptr, &mut remaining_len, &mut dst_ptr);
}
}
if need_quote {
*dst_ptr = b'"';
dst_ptr = dst_ptr.add(1);
}
let written_len = dst_ptr.offset_from(dst_start_ptr) as usize;
writer.set_len(original_len + written_len);
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_quote() {
let mut dst: Vec<u8> = Vec::with_capacity(1000);
format_string("", &mut dst, true);
assert_eq!(dst.as_slice(), b"\"\"");
format_string("\x00", &mut dst, true);
assert_eq!(dst.as_slice(), b"\"\"\"\\u0000\"");
format_string("test", &mut dst, true);
assert_eq!(dst.as_slice(), b"\"\"\"\\u0000\"\"test\"");
format_string("test\"test", &mut dst, true);
assert_eq!(dst.as_slice(), b"\"\"\"\\u0000\"\"test\"\"test\\\"test\"");
format_string("\\testtest\"", &mut dst, true);
assert_eq!(
dst.as_slice(),
b"\"\"\"\\u0000\"\"test\"\"test\\\"test\"\"\\\\testtest\\\"\""
);
let long_str = "this is a long string that should be \\\"quoted and escaped multiple \
times to test the performance and correctness of the function.";
format_string(long_str, &mut dst, true);
assert_eq!(dst.as_slice(), b"\"\"\"\\u0000\"\"test\"\"test\\\"test\"\"\\\\testtest\\\"\"\"this is a long string that should be \\\\\\\"quoted and escaped multiple times to test the performance and correctness of the function.\"");
}
#[test]
fn writes_named_operation_after_keyword() {
let mut dst = Vec::new();
write_named_operation(&mut dst, b"Foo", 5, "query($id: ID!){node(id:$id){id}}");
assert_eq!(dst.as_slice(), b"\"query Foo($id: ID!){node(id:$id){id}}\"");
}
#[test]
fn writes_named_operation_for_shorthand_query() {
let mut dst = Vec::new();
write_named_operation(&mut dst, b"Foo", 0, "{node{id}}");
assert_eq!(dst.as_slice(), b"\"query Foo {node{id}}\"");
}
#[test]
fn writes_named_operation_with_json_escaping() {
let mut dst = Vec::new();
write_named_operation(
&mut dst,
b"Foo",
5,
"query($id: ID!) { node(id: \"quoted\\value\") { field } }",
);
assert_eq!(
dst.as_slice(),
b"\"query Foo($id: ID!) { node(id: \\\"quoted\\\\value\\\") { field } }\""
);
}
}