use crate::ast::{Number, Value};
use rustc_hash::FxHashMap;
pub struct ValueBuilder {
object_capacity: usize,
array_capacity: usize,
}
impl ValueBuilder {
pub fn new() -> Self {
Self {
object_capacity: 8, array_capacity: 16,
}
}
pub fn with_capacity(object_capacity: usize, array_capacity: usize) -> Self {
Self {
object_capacity,
array_capacity,
}
}
#[inline]
pub fn build_object(&self) -> FxHashMap<String, Value> {
FxHashMap::with_capacity_and_hasher(self.object_capacity, Default::default())
}
#[inline]
pub fn build_array(&self) -> Vec<Value> {
Vec::with_capacity(self.array_capacity)
}
#[inline]
pub fn build_string(content: &str) -> Value {
if content.len() < 64 && !content.contains('\\') {
Value::String(content.to_string())
} else {
match super::string_parser::unescape_string_optimized(content) {
Ok(unescaped) => Value::String(unescaped),
Err(_) => Value::String(content.to_string()), }
}
}
#[inline]
pub fn build_number(s: &str) -> Result<Value, crate::error::Error> {
let num = super::string_parser::parse_number_optimized(s)?;
let number_value = if num.fract() == 0.0
&& num.is_finite()
&& num >= i64::MIN as f64
&& num <= i64::MAX as f64
{
Number::Integer(num as i64)
} else {
Number::Float(num)
};
Ok(Value::Number(number_value))
}
}
impl Default for ValueBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_build_object() {
let builder = ValueBuilder::new();
let obj = builder.build_object();
assert_eq!(obj.len(), 0);
}
#[test]
fn test_build_array() {
let builder = ValueBuilder::new();
let arr = builder.build_array();
assert_eq!(arr.len(), 0);
}
#[test]
fn test_build_string() {
let value = ValueBuilder::build_string("hello");
match value {
Value::String(s) => assert_eq!(s, "hello"),
_ => panic!("Expected string value"),
}
}
#[test]
fn test_build_number() {
let value = ValueBuilder::build_number("42").unwrap();
match value {
Value::Number(Number::Integer(42)) => {}
Value::Number(Number::Float(f)) => assert_eq!(f, 42.0),
_ => panic!("Expected number value"),
}
}
}