use crate::event_processor::{EscapeTiming, ParserCore};
use crate::parse_error::ParseError;
use crate::shared::{Event, PullParser};
use crate::slice_content_builder::SliceContentBuilder;
use crate::slice_input_buffer::InputBuffer;
use crate::ujson;
use ujson::{BitStackConfig, DefaultConfig};
pub struct SliceParser<'a, 'b, C: BitStackConfig = DefaultConfig> {
parser_core: ParserCore<C::Bucket, C::Counter>,
content_builder: SliceContentBuilder<'a, 'b>,
}
impl<'a> SliceParser<'a, '_, DefaultConfig> {
pub fn new(input: &'a str) -> Self {
Self::new_from_slice(input.as_bytes())
}
pub fn new_from_slice(input: &'a [u8]) -> Self {
Self::with_config_from_slice(input)
}
}
impl<'a, 'b> SliceParser<'a, 'b, DefaultConfig> {
pub fn with_buffer(input: &'a str, scratch_buffer: &'b mut [u8]) -> Self {
Self::with_buffer_from_slice(input.as_bytes(), scratch_buffer)
}
pub fn with_buffer_from_slice(input: &'a [u8], scratch_buffer: &'b mut [u8]) -> Self {
Self::with_config_and_buffer_from_slice(input, scratch_buffer)
}
}
impl<'a, 'b, C: BitStackConfig> SliceParser<'a, 'b, C> {
pub fn with_config(input: &'a str) -> Self {
Self::with_config_from_slice(input.as_bytes())
}
pub fn with_config_from_slice(input: &'a [u8]) -> Self {
Self::with_config_and_buffer_from_slice(input, &mut [])
}
pub fn with_config_and_buffer(input: &'a str, scratch_buffer: &'b mut [u8]) -> Self {
Self::with_config_and_buffer_from_slice(input.as_bytes(), scratch_buffer)
}
pub fn with_config_and_buffer_from_slice(
input: &'a [u8],
scratch_buffer: &'b mut [u8],
) -> Self {
SliceParser {
parser_core: ParserCore::new(),
content_builder: SliceContentBuilder::new(input, scratch_buffer),
}
}
fn next_event_impl(&mut self) -> Result<Event<'_, '_>, ParseError> {
self.parser_core.next_event_impl(
&mut self.content_builder,
EscapeTiming::OnBegin,
|_, _| Ok(()),
)
}
}
impl<C: BitStackConfig> PullParser for SliceParser<'_, '_, C> {
fn next_event(&mut self) -> Result<Event<'_, '_>, ParseError> {
if self.content_builder.buffer().is_past_end() {
return Ok(Event::EndDocument);
}
self.next_event_impl()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{ArrayBitStack, BitStackStruct, String};
#[test]
fn make_parser() {
let input = r#"{"key": "value"}"#;
let mut scratch = [0u8; 1024];
let mut parser = SliceParser::with_buffer(input, &mut scratch);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
assert_eq!(parser.next_event(), Ok(Event::Key(String::Borrowed("key"))));
assert_eq!(
parser.next_event(),
Ok(Event::String(String::Borrowed("value")))
);
assert_eq!(parser.next_event(), Ok(Event::EndObject));
assert_eq!(parser.next_event(), Ok(Event::EndDocument));
assert_eq!(parser.next_event(), Ok(Event::EndDocument));
}
#[test]
fn parse_number() {
let input = r#"{"key": 124}"#;
let mut scratch = [0u8; 1024];
let mut parser = SliceParser::with_buffer(input, &mut scratch);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
assert_eq!(parser.next_event(), Ok(Event::Key(String::Borrowed("key"))));
match parser.next_event() {
Ok(Event::Number(num)) => {
assert_eq!(num.as_str(), "124");
assert_eq!(num.as_int(), Some(124));
}
other => panic!("Expected Number, got: {:?}", other),
}
assert_eq!(parser.next_event(), Ok(Event::EndObject));
assert_eq!(parser.next_event(), Ok(Event::EndDocument));
}
#[test]
fn parse_bool_and_null() {
let input = r#"{"key": true, "key2": false, "key3": null}"#;
let mut scratch = [0u8; 1024];
let mut parser = SliceParser::with_buffer(input, &mut scratch);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
assert_eq!(parser.next_event(), Ok(Event::Key(String::Borrowed("key"))));
assert_eq!(parser.next_event(), Ok(Event::Bool(true)));
assert_eq!(
parser.next_event(),
Ok(Event::Key(String::Borrowed("key2")))
);
assert_eq!(parser.next_event(), Ok(Event::Bool(false)));
assert_eq!(
parser.next_event(),
Ok(Event::Key(String::Borrowed("key3")))
);
assert_eq!(parser.next_event(), Ok(Event::Null));
assert_eq!(parser.next_event(), Ok(Event::EndObject));
assert_eq!(parser.next_event(), Ok(Event::EndDocument));
}
#[test]
fn parse_array() {
#[cfg(feature = "float-error")]
let input = r#"{"key": [1, 2, 3]}"#; #[cfg(not(feature = "float-error"))]
let input = r#"{"key": [1, 2.2, 3]}"#;
let mut scratch = [0u8; 1024];
let mut parser = SliceParser::with_buffer(input, &mut scratch);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
assert_eq!(parser.next_event(), Ok(Event::Key(String::Borrowed("key"))));
assert_eq!(parser.next_event(), Ok(Event::StartArray));
match parser.next_event() {
Ok(Event::Number(num)) => {
assert_eq!(num.as_str(), "1");
assert_eq!(num.as_int(), Some(1));
}
other => panic!("Expected Number(1), got: {:?}", other),
}
match parser.next_event() {
Ok(Event::Number(num)) => {
#[cfg(feature = "float-error")]
{
assert_eq!(num.as_str(), "2");
assert_eq!(num.as_int(), Some(2));
}
#[cfg(not(feature = "float-error"))]
{
assert_eq!(num.as_str(), "2.2");
#[cfg(feature = "float")]
assert_eq!(num.as_f64(), Some(2.2));
#[cfg(not(feature = "float-error"))]
assert!(num.is_float());
}
}
other => panic!("Expected Number, got: {:?}", other),
}
match parser.next_event() {
Ok(Event::Number(num)) => {
assert_eq!(num.as_str(), "3");
assert_eq!(num.as_int(), Some(3));
}
other => panic!("Expected Number(3), got: {:?}", other),
}
assert_eq!(parser.next_event(), Ok(Event::EndArray));
assert_eq!(parser.next_event(), Ok(Event::EndObject));
assert_eq!(parser.next_event(), Ok(Event::EndDocument));
}
#[test]
fn test_simple_parser_api() {
let input = r#"{"name": "test"}"#;
let mut scratch = [0u8; 1024];
let mut parser = SliceParser::with_buffer(input, &mut scratch);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
assert_eq!(
parser.next_event(),
Ok(Event::Key(String::Borrowed("name")))
);
assert_eq!(
parser.next_event(),
Ok(Event::String(String::Borrowed("test")))
);
assert_eq!(parser.next_event(), Ok(Event::EndObject));
assert_eq!(parser.next_event(), Ok(Event::EndDocument));
}
#[test]
fn test_parser_with_escaped_strings() {
let input = "{\"name\": \"John\\nDoe\", \"message\": \"Hello\\tWorld!\"}";
let mut scratch = [0u8; 1024];
let mut parser = SliceParser::with_buffer(input, &mut scratch);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
if let Ok(Event::Key(key)) = parser.next_event() {
assert_eq!(&*key, "name");
assert!(matches!(key, String::Borrowed(_)));
} else {
panic!("Expected Key event");
}
if let Ok(Event::String(value)) = parser.next_event() {
assert_eq!(&*value, "John\nDoe");
assert!(matches!(value, String::Unescaped(_)));
} else {
panic!("Expected String event");
}
if let Ok(Event::Key(key)) = parser.next_event() {
assert_eq!(&*key, "message");
assert!(matches!(key, String::Borrowed(_)));
} else {
panic!("Expected Key event");
}
if let Ok(Event::String(value)) = parser.next_event() {
assert_eq!(&*value, "Hello\tWorld!");
assert!(matches!(value, String::Unescaped(_)));
} else {
panic!("Expected String event");
}
assert_eq!(parser.next_event(), Ok(Event::EndObject));
}
#[test]
fn test_copy_on_escape_optimization() {
let input = "{\"simple\": \"no escapes\", \"complex\": \"has\\nescapes\"}";
let mut scratch = [0u8; 1024];
let mut parser = SliceParser::with_buffer(input, &mut scratch);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
if let Ok(Event::Key(key)) = parser.next_event() {
assert_eq!(&*key, "simple");
assert!(matches!(key, String::Borrowed(_)));
} else {
panic!("Expected Key event");
}
if let Ok(Event::String(value)) = parser.next_event() {
assert_eq!(&*value, "no escapes");
assert!(matches!(value, String::Borrowed(_)));
} else {
panic!("Expected String event");
}
if let Ok(Event::Key(key)) = parser.next_event() {
assert_eq!(&*key, "complex");
assert!(matches!(key, String::Borrowed(_)));
} else {
panic!("Expected Key event");
}
if let Ok(Event::String(value)) = parser.next_event() {
assert_eq!(&*value, "has\nescapes");
assert!(matches!(value, String::Unescaped(_)));
} else {
panic!("Expected String event");
}
assert_eq!(parser.next_event(), Ok(Event::EndObject));
assert_eq!(parser.next_event(), Ok(Event::EndDocument));
}
#[test]
fn test_coe2_integration_multiple_escapes() {
let input = r#"{"key": "a\nb\tc\rd"}"#;
let mut scratch = [0u8; 1024];
let mut parser = SliceParser::with_buffer(input, &mut scratch);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
assert_eq!(parser.next_event(), Ok(Event::Key(String::Borrowed("key"))));
let string_event = parser.next_event().unwrap();
match string_event {
Event::String(String::Unescaped(s)) => {
assert_eq!(s, "a\nb\tc\rd");
}
_ => panic!("Expected unescaped string value, got: {:?}", string_event),
}
assert_eq!(parser.next_event(), Ok(Event::EndObject));
assert_eq!(parser.next_event(), Ok(Event::EndDocument));
}
#[test]
fn test_coe2_integration_zero_copy_path() {
let input = r#"{"simple": "no_escapes_here"}"#;
let mut scratch = [0u8; 1024];
let mut parser = SliceParser::with_buffer(input, &mut scratch);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
assert_eq!(
parser.next_event(),
Ok(Event::Key(String::Borrowed("simple")))
);
let string_event = parser.next_event().unwrap();
match string_event {
Event::String(String::Borrowed(s)) => {
assert_eq!(s, "no_escapes_here");
}
_ => panic!(
"Expected borrowed string value for zero-copy, got: {:?}",
string_event
),
}
assert_eq!(parser.next_event(), Ok(Event::EndObject));
assert_eq!(parser.next_event(), Ok(Event::EndDocument));
}
#[test]
fn test_coe2_integration_mixed_strings() {
let input = r#"["plain", "with\nescapes", "plain2", "more\tescapes"]"#;
let mut scratch = [0u8; 1024];
let mut parser = SliceParser::with_buffer(input, &mut scratch);
assert_eq!(parser.next_event(), Ok(Event::StartArray));
match parser.next_event().unwrap() {
Event::String(String::Borrowed(s)) => assert_eq!(s, "plain"),
other => panic!("Expected borrowed string, got: {:?}", other),
}
match parser.next_event().unwrap() {
Event::String(String::Unescaped(s)) => assert_eq!(s, "with\nescapes"),
other => panic!("Expected unescaped string, got: {:?}", other),
}
match parser.next_event().unwrap() {
Event::String(String::Borrowed(s)) => assert_eq!(s, "plain2"),
other => panic!("Expected borrowed string, got: {:?}", other),
}
match parser.next_event().unwrap() {
Event::String(String::Unescaped(s)) => assert_eq!(s, "more\tescapes"),
other => panic!("Expected unescaped string, got: {:?}", other),
}
assert_eq!(parser.next_event(), Ok(Event::EndArray));
assert_eq!(parser.next_event(), Ok(Event::EndDocument));
}
#[test]
fn test_unicode_escape_integration() {
let input = r#"{"key": "Hello\u0041World"}"#; let mut scratch = [0u8; 1024];
let mut parser = SliceParser::with_buffer(input, &mut scratch);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
assert_eq!(parser.next_event(), Ok(Event::Key(String::Borrowed("key"))));
match parser.next_event().unwrap() {
Event::String(String::Unescaped(s)) => {
assert_eq!(s, "HelloAWorld");
}
other => panic!("Expected unescaped string value, got: {:?}", other),
}
assert_eq!(parser.next_event(), Ok(Event::EndObject));
assert_eq!(parser.next_event(), Ok(Event::EndDocument));
}
#[test]
fn test_original_parser_escape_trace() {
let input = r#""a\nb""#;
let mut scratch = [0u8; 1024];
let mut parser = SliceParser::with_buffer(input, &mut scratch);
let event = parser.next_event().unwrap();
if let Event::String(s) = event {
assert_eq!(&*s, "a\nb");
} else {
panic!("Expected String event, got {:?}", event);
}
let event = parser.next_event().unwrap();
assert_eq!(event, Event::EndDocument);
}
#[test]
fn make_parser_from_slice() {
let input = br#"{"key": "value"}"#;
let mut scratch = [0u8; 1024];
let mut parser = SliceParser::with_buffer_from_slice(input, &mut scratch);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
assert_eq!(parser.next_event(), Ok(Event::Key(String::Borrowed("key"))));
assert_eq!(
parser.next_event(),
Ok(Event::String(String::Borrowed("value")))
);
assert_eq!(parser.next_event(), Ok(Event::EndObject));
assert_eq!(parser.next_event(), Ok(Event::EndDocument));
assert_eq!(parser.next_event(), Ok(Event::EndDocument));
}
#[test]
fn test_with_config_constructors() {
let json = r#"{"simple": "no_escapes"}"#;
let mut parser = SliceParser::<BitStackStruct<u64, u16>>::with_config(json);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
assert_eq!(
parser.next_event(),
Ok(Event::Key(String::Borrowed("simple")))
);
assert_eq!(
parser.next_event(),
Ok(Event::String(String::Borrowed("no_escapes")))
);
assert_eq!(parser.next_event(), Ok(Event::EndObject));
assert_eq!(parser.next_event(), Ok(Event::EndDocument));
}
#[test]
fn test_with_config_and_buffer_constructors() {
let json = r#"{"escaped": "hello\nworld"}"#;
let mut scratch = [0u8; 64];
let mut parser =
SliceParser::<BitStackStruct<u64, u16>>::with_config_and_buffer(json, &mut scratch);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
assert_eq!(
parser.next_event(),
Ok(Event::Key(String::Borrowed("escaped")))
);
if let Ok(Event::String(s)) = parser.next_event() {
assert_eq!(s.as_ref(), "hello\nworld"); } else {
panic!("Expected String event");
}
assert_eq!(parser.next_event(), Ok(Event::EndObject));
assert_eq!(parser.next_event(), Ok(Event::EndDocument));
}
#[test]
fn test_alternative_config_deep_nesting() {
let json = r#"{"a":{"b":{"c":{"d":{"e":"deep"}}}}}"#;
let mut scratch = [0u8; 64];
let mut parser =
SliceParser::<ArrayBitStack<8, u32, u16>>::with_config_and_buffer(json, &mut scratch);
let mut depth = 0;
while let Ok(event) = parser.next_event() {
match event {
Event::StartObject => depth += 1,
Event::EndObject => depth -= 1,
Event::EndDocument => break,
_ => {}
}
}
assert_eq!(depth, 0); }
}