perf improvements

This commit is contained in:
2026-04-06 02:51:42 +03:00
parent b0ea71e104
commit 953b39d433
7 changed files with 47 additions and 40 deletions
+14 -13
View File
@@ -2,6 +2,7 @@ use indexmap::IndexMap;
use rust_decimal::Decimal;
use smol_str::SmolStr;
use std::fmt;
use std::rc::Rc;
/// Value type for the dExpr language
#[derive(Debug, Clone, PartialEq, Default)]
@@ -11,9 +12,9 @@ pub enum Value {
Number(Decimal),
String(SmolStr),
Boolean(bool),
NumberList(Box<Vec<Decimal>>),
StringList(Box<Vec<SmolStr>>),
Object(Box<IndexMap<SmolStr, Value>>),
NumberList(Rc<Vec<Decimal>>),
StringList(Rc<Vec<SmolStr>>),
Object(Rc<IndexMap<SmolStr, Value>>),
}
/// Type tag constants for serialization
@@ -209,19 +210,19 @@ impl From<SmolStr> for Value {
impl From<Vec<Decimal>> for Value {
fn from(v: Vec<Decimal>) -> Self {
Value::NumberList(Box::new(v))
Value::NumberList(Rc::new(v))
}
}
impl From<Vec<SmolStr>> for Value {
fn from(v: Vec<SmolStr>) -> Self {
Value::StringList(Box::new(v))
Value::StringList(Rc::new(v))
}
}
impl From<IndexMap<SmolStr, Value>> for Value {
fn from(m: IndexMap<SmolStr, Value>) -> Self {
Value::Object(Box::new(m))
Value::Object(Rc::new(m))
}
}
@@ -292,7 +293,7 @@ impl Value {
list.push(Decimal::deserialize(decimal_bytes));
}
Ok((Value::NumberList(Box::new(list)), pos))
Ok((Value::NumberList(Rc::new(list)), pos))
}
TYPE_STRING_LIST => {
if bytes.len() < pos + 2 {
@@ -321,7 +322,7 @@ impl Value {
list.push(s.into());
}
Ok((Value::StringList(Box::new(list)), pos))
Ok((Value::StringList(Rc::new(list)), pos))
}
TYPE_OBJECT => {
if bytes.len() < pos + 2 {
@@ -354,7 +355,7 @@ impl Value {
map.insert(key.into(), val);
}
Ok((Value::Object(Box::new(map)), pos))
Ok((Value::Object(Rc::new(map)), pos))
}
_ => Err(format!("Unknown type tag: {}", type_tag)),
}
@@ -407,7 +408,7 @@ impl Value {
serde_json::Value::String(s) => Ok(Value::String(SmolStr::new(s))),
serde_json::Value::Array(arr) => {
if arr.is_empty() {
return Ok(Value::StringList(Box::new(Vec::new())));
return Ok(Value::StringList(Rc::new(Vec::new())));
}
// Check if all elements are the same type
let first = &arr[0];
@@ -418,12 +419,12 @@ impl Value {
nums.push(n);
}
}
Ok(Value::NumberList(Box::new(nums)))
Ok(Value::NumberList(Rc::new(nums)))
} else if first.is_string() && arr.iter().all(|v| v.is_string()) {
let strings: Vec<SmolStr> = arr.iter()
.filter_map(|v| v.as_str().map(SmolStr::new))
.collect();
Ok(Value::StringList(Box::new(strings)))
Ok(Value::StringList(Rc::new(strings)))
} else {
Err("Arrays must contain all numbers or all strings".to_string())
}
@@ -433,7 +434,7 @@ impl Value {
for (k, v) in obj {
map.insert(SmolStr::new(k), Self::from_json_value(v)?);
}
Ok(Value::Object(Box::new(map)))
Ok(Value::Object(Rc::new(map)))
}
}
}
+2 -1
View File
@@ -11,6 +11,7 @@
//! use indexmap::IndexMap;
//! use smol_str::SmolStr;
//! use rust_decimal_macros::dec;
//! use std::rc::Rc;
//!
//! let mut info = LanguageInfo::builtin();
//!
@@ -24,7 +25,7 @@
//! let mut customer = IndexMap::new();
//! customer.insert(SmolStr::new("name"), Value::String("Alice".into()));
//! customer.insert(SmolStr::new("age"), Value::Number(dec!(30)));
//! info.add_value("customer", &Value::Object(Box::new(customer)), None);
//! info.add_value("customer", &Value::Object(Rc::new(customer)), None);
//! info.add_value("price", &Value::Number(dec!(100)), None);
//!
//! let json = info.to_json();
+12 -11
View File
@@ -1,6 +1,7 @@
use crate::ast::value::Value;
use rust_decimal::{prelude::ToPrimitive, Decimal};
use smol_str::{SmolStr, StrExt};
use std::rc::Rc;
use super::error::VMError;
use super::vm::VM;
@@ -72,7 +73,7 @@ impl<'a> VM<'a> {
match &args[0] {
Value::String(delim) => {
let parts: Vec<SmolStr> = s.split(delim.as_str()).map(SmolStr::new).collect();
Ok(Value::StringList(Box::new(parts)))
Ok(Value::StringList(Rc::new(parts)))
}
_ => Err(VMError::RuntimeError(
"split() requires a string delimiter".to_string(),
@@ -263,7 +264,7 @@ impl<'a> VM<'a> {
} else {
list.len()
};
Ok(Value::StringList(Box::new(list[start..end].to_vec())))
Ok(Value::StringList(Rc::new(list[start..end].to_vec())))
}
_ => Err(VMError::RuntimeError("slice() requires a number index".to_string())),
}
@@ -271,12 +272,12 @@ impl<'a> VM<'a> {
"reverse" => {
let mut reversed = list.to_vec();
reversed.reverse();
Ok(Value::StringList(Box::new(reversed)))
Ok(Value::StringList(Rc::new(reversed)))
}
"sort" => {
let mut sorted = list.to_vec();
sorted.sort();
Ok(Value::StringList(Box::new(sorted)))
Ok(Value::StringList(Rc::new(sorted)))
}
"join" => {
let delim = if args.is_empty() {
@@ -368,7 +369,7 @@ impl<'a> VM<'a> {
} else {
list.len()
};
Ok(Value::NumberList(Box::new(list[start..end].to_vec())))
Ok(Value::NumberList(Rc::new(list[start..end].to_vec())))
}
_ => Err(VMError::RuntimeError("slice() requires a number index".to_string())),
}
@@ -376,12 +377,12 @@ impl<'a> VM<'a> {
"reverse" => {
let mut reversed = list.to_vec();
reversed.reverse();
Ok(Value::NumberList(Box::new(reversed)))
Ok(Value::NumberList(Rc::new(reversed)))
}
"sort" => {
let mut sorted = list.to_vec();
sorted.sort();
Ok(Value::NumberList(Box::new(sorted)))
Ok(Value::NumberList(Rc::new(sorted)))
}
"sum" => {
let sum: Decimal = list.iter().sum();
@@ -426,12 +427,12 @@ impl<'a> VM<'a> {
match method {
"keys" => {
let keys: Vec<SmolStr> = map.keys().cloned().collect();
Ok(Value::StringList(Box::new(keys)))
Ok(Value::StringList(Rc::new(keys)))
}
"values" => {
let vals: Vec<Value> = map.values().cloned().collect();
if vals.is_empty() {
Ok(Value::StringList(Box::new(Vec::new())))
Ok(Value::StringList(Rc::new(Vec::new())))
} else if vals.iter().all(|v| matches!(v, Value::String(_))) {
let strings: Vec<SmolStr> = vals
.into_iter()
@@ -440,7 +441,7 @@ impl<'a> VM<'a> {
_ => unreachable!(),
})
.collect();
Ok(Value::StringList(Box::new(strings)))
Ok(Value::StringList(Rc::new(strings)))
} else if vals.iter().all(|v| matches!(v, Value::Number(_))) {
let numbers: Vec<Decimal> = vals
.into_iter()
@@ -449,7 +450,7 @@ impl<'a> VM<'a> {
_ => unreachable!(),
})
.collect();
Ok(Value::NumberList(Box::new(numbers)))
Ok(Value::NumberList(Rc::new(numbers)))
} else {
Err(VMError::RuntimeError(
"values() only works when all values are the same type (String or Number)".to_string(),
+2 -1
View File
@@ -1,4 +1,5 @@
use crate::{ast::value::Value, bytecode::BytecodeReader, opcodes::OpCodeByte};
use std::rc::Rc;
use micromap::Map;
use rust_decimal::{Decimal, MathematicalOps};
use rustc_hash::FxHashMap;
@@ -704,7 +705,7 @@ impl<'a> VM<'a> {
let value = self.registers[val].clone();
match &mut self.registers[obj] {
Value::Object(map) => {
map.insert(SmolStr::from(prop), value);
Rc::make_mut(map).insert(SmolStr::from(prop), value);
}
other => {
return Err(VMError::RuntimeError(format!(