use crate::ast::{Token, Value};
use crate::error::{Error, Result, Span};
use crate::lexer::Lexer;
use crate::parser::ParserOptions;
use rustc_hash::FxHashMap;
use std::sync::{Arc, Mutex};
pub mod array;
pub mod number;
pub mod object;
pub mod string;
pub use array::LazyArray;
pub use object::LazyObject;
#[derive(Debug, Clone)]
pub enum LazyValue {
Resolved(Value),
Deferred {
input: Arc<str>,
span: Span,
options: ParserOptions,
cache: Arc<Mutex<Option<Value>>>,
},
}
pub struct LazyParser<'a> {
pub(super) input: &'a str,
pub(super) lexer: Lexer<'a>,
pub(super) options: ParserOptions,
pub(super) lazy_threshold: usize,
}
impl LazyValue {
pub fn deferred(input: Arc<str>, span: Span, options: ParserOptions) -> Self {
LazyValue::Deferred {
input,
span,
options,
cache: Arc::new(Mutex::new(None)),
}
}
pub fn resolved(value: Value) -> Self {
LazyValue::Resolved(value)
}
pub fn evaluate(&self) -> Result<Value> {
match self {
LazyValue::Resolved(value) => Ok(value.clone()),
LazyValue::Deferred {
input,
span,
options,
cache,
} => {
{
let cache_guard = cache.lock().unwrap();
if let Some(cached_value) = cache_guard.as_ref() {
return Ok(cached_value.clone());
}
}
let slice = &input[span.start..span.end];
let mut parser = LazyParser::new(slice, options.clone());
parser.set_lazy_threshold(0); let value = parser.parse()?;
let resolved_value = Self::force_resolve(value)?;
{
let mut cache_guard = cache.lock().unwrap();
*cache_guard = Some(resolved_value.clone());
}
Ok(resolved_value)
}
}
}
fn force_resolve(value: Value) -> Result<Value> {
match value {
Value::Object(obj) => {
let mut resolved_obj = FxHashMap::default();
for (key, val) in obj {
resolved_obj.insert(key, Self::force_resolve(val)?);
}
Ok(Value::Object(resolved_obj))
}
Value::Array(arr) => {
let mut resolved_arr = Vec::new();
for val in arr {
resolved_arr.push(Self::force_resolve(val)?);
}
Ok(Value::Array(resolved_arr))
}
other => Ok(other),
}
}
pub fn is_resolved(&self) -> bool {
matches!(self, LazyValue::Resolved(_))
}
pub fn try_get_resolved(&self) -> Option<Value> {
match self {
LazyValue::Resolved(value) => Some(value.clone()),
LazyValue::Deferred { cache, .. } => cache.lock().unwrap().clone(),
}
}
}
impl<'a> LazyParser<'a> {
pub fn new(input: &'a str, options: ParserOptions) -> Self {
LazyParser {
input,
lexer: Lexer::new(input),
options,
lazy_threshold: 1024, }
}
pub fn set_lazy_threshold(&mut self, threshold: usize) {
self.lazy_threshold = threshold;
}
pub fn parse(&mut self) -> Result<Value> {
let (token, span) = self.next_token()?;
self.parse_value(token, span)
}
pub(super) fn next_token(&mut self) -> Result<(Token, Span)> {
self.lexer.next_token_with_span()
}
pub(super) fn peek_token(&mut self) -> Result<(Token, Span)> {
self.lexer
.peek_with_span()
.map(|&(token, span)| (token, span))
}
pub(super) fn parse_value(&mut self, token: Token, span: Span) -> Result<Value> {
match token {
Token::LeftBrace => self.parse_object(span),
Token::LeftBracket => self.parse_array(span),
Token::String => self.parse_string(span),
Token::Number => self.parse_number(span),
Token::True => Ok(Value::Bool(true)),
Token::False => Ok(Value::Bool(false)),
Token::Null => Ok(Value::Null),
_ => Err(Error::UnexpectedChar(
self.input.chars().nth(span.start).unwrap_or('\0'),
span.start,
)),
}
}
}
pub fn parse_lazy(input: &str) -> Result<Value> {
let mut parser = LazyParser::new(input, ParserOptions::default());
parser.parse()
}
pub fn parse_lazy_with_options(input: &str, options: ParserOptions) -> Result<Value> {
let mut parser = LazyParser::new(input, options);
parser.parse()
}
pub fn parse_lazy_with_threshold(input: &str, threshold: usize) -> Result<Value> {
let mut parser = LazyParser::new(input, ParserOptions::default());
parser.set_lazy_threshold(threshold);
parser.parse()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_lazy_value_resolved() {
let value = LazyValue::resolved(Value::String("test".to_string()));
assert!(value.is_resolved());
let result = value.evaluate().unwrap();
assert_eq!(result, Value::String("test".to_string()));
}
#[test]
fn test_lazy_parser_small_object() {
let input = r#"{"name": "test", "value": 42}"#;
let result = parse_lazy(input).unwrap();
match result {
Value::Object(obj) => {
assert_eq!(obj.get("name"), Some(&Value::String("test".to_string())));
assert_eq!(
obj.get("value"),
Some(&Value::Number(crate::ast::Number::Integer(42)))
);
}
_ => panic!("Expected object"),
}
}
#[test]
fn test_lazy_parser_with_threshold() {
let input = r#"{"small": "value"}"#;
let mut parser = LazyParser::new(input, ParserOptions::default());
parser.set_lazy_threshold(10);
let result = parser.parse().unwrap();
match result {
Value::Object(obj) => {
assert_eq!(obj.get("small"), Some(&Value::String("value".to_string())));
}
_ => panic!("Expected object"),
}
}
#[test]
fn test_lazy_array() {
let input = r#"[1, 2, 3]"#;
let result = parse_lazy(input).unwrap();
match result {
Value::Array(arr) => {
assert_eq!(arr.len(), 3);
assert_eq!(arr[0], Value::Number(crate::ast::Number::Integer(1)));
}
_ => panic!("Expected array"),
}
}
}