2025-08-12 10:08:30 +00:00
|
|
|
/*!
|
|
|
|
|
* NyashValue - Revolutionary unified value representation system
|
|
|
|
|
*
|
|
|
|
|
* Replaces Arc<Mutex<T>> overuse with direct value storage for primitives
|
|
|
|
|
* and smart synchronization only where needed.
|
|
|
|
|
*
|
|
|
|
|
* Inspired by Lua's TValue system for performance-critical language implementations.
|
|
|
|
|
*/
|
|
|
|
|
|
2025-08-12 20:15:44 +00:00
|
|
|
use std::sync::{Arc, Mutex, Weak};
|
2025-08-12 10:08:30 +00:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
use std::fmt::{self, Display, Debug};
|
|
|
|
|
use crate::box_trait::NyashBox;
|
|
|
|
|
|
|
|
|
|
/// Revolutionary unified value type - replaces individual Box allocations
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub enum NyashValue {
|
|
|
|
|
// Direct primitive values - no Arc<Mutex> overhead
|
|
|
|
|
Integer(i64),
|
|
|
|
|
Float(f64),
|
|
|
|
|
Bool(bool),
|
|
|
|
|
String(String),
|
|
|
|
|
|
|
|
|
|
// Collections - need synchronization
|
|
|
|
|
Array(Arc<Mutex<Vec<NyashValue>>>),
|
|
|
|
|
Map(Arc<Mutex<HashMap<String, NyashValue>>>),
|
|
|
|
|
|
|
|
|
|
// Legacy Box compatibility and custom types
|
|
|
|
|
Box(Arc<Mutex<dyn NyashBox>>),
|
|
|
|
|
|
2025-08-12 20:15:44 +00:00
|
|
|
// 🔗 Weak reference system - prevents circular reference memory leaks
|
|
|
|
|
WeakBox(Weak<Mutex<dyn NyashBox>>),
|
|
|
|
|
|
2025-08-12 10:08:30 +00:00
|
|
|
// Special values
|
|
|
|
|
Null,
|
|
|
|
|
Void,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl NyashValue {
|
|
|
|
|
/// Create a new NyashValue from a primitive value
|
|
|
|
|
pub fn new_integer(value: i64) -> Self {
|
|
|
|
|
NyashValue::Integer(value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn new_float(value: f64) -> Self {
|
|
|
|
|
NyashValue::Float(value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn new_bool(value: bool) -> Self {
|
|
|
|
|
NyashValue::Bool(value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn new_string(value: String) -> Self {
|
|
|
|
|
NyashValue::String(value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn new_array() -> Self {
|
|
|
|
|
NyashValue::Array(Arc::new(Mutex::new(Vec::new())))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn new_map() -> Self {
|
|
|
|
|
NyashValue::Map(Arc::new(Mutex::new(HashMap::new())))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn new_null() -> Self {
|
|
|
|
|
NyashValue::Null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn new_void() -> Self {
|
|
|
|
|
NyashValue::Void
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Convert to string representation
|
|
|
|
|
pub fn to_string(&self) -> String {
|
|
|
|
|
match self {
|
|
|
|
|
NyashValue::Integer(n) => n.to_string(),
|
|
|
|
|
NyashValue::Float(f) => f.to_string(),
|
|
|
|
|
NyashValue::Bool(b) => b.to_string(),
|
|
|
|
|
NyashValue::String(s) => s.clone(),
|
|
|
|
|
NyashValue::Array(arr) => {
|
|
|
|
|
if let Ok(guard) = arr.try_lock() {
|
|
|
|
|
let elements: Vec<String> = guard.iter()
|
|
|
|
|
.map(|v| v.to_string())
|
|
|
|
|
.collect();
|
|
|
|
|
format!("[{}]", elements.join(", "))
|
|
|
|
|
} else {
|
|
|
|
|
"[Array (locked)]".to_string()
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
NyashValue::Map(map) => {
|
|
|
|
|
if let Ok(guard) = map.try_lock() {
|
|
|
|
|
let pairs: Vec<String> = guard.iter()
|
|
|
|
|
.map(|(k, v)| format!("{}: {}", k, v.to_string()))
|
|
|
|
|
.collect();
|
|
|
|
|
format!("{{{}}}", pairs.join(", "))
|
|
|
|
|
} else {
|
|
|
|
|
"{Map (locked)}".to_string()
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
NyashValue::Box(b) => {
|
|
|
|
|
if let Ok(guard) = b.try_lock() {
|
|
|
|
|
guard.to_string_box().value
|
|
|
|
|
} else {
|
|
|
|
|
"Box (locked)".to_string()
|
|
|
|
|
}
|
|
|
|
|
},
|
2025-08-12 20:15:44 +00:00
|
|
|
NyashValue::WeakBox(weak_ref) => {
|
|
|
|
|
if let Some(arc) = weak_ref.upgrade() {
|
|
|
|
|
if let Ok(guard) = arc.try_lock() {
|
|
|
|
|
format!("WeakRef({})", guard.to_string_box().value)
|
|
|
|
|
} else {
|
|
|
|
|
"WeakRef(locked)".to_string()
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
"WeakRef(null)".to_string()
|
|
|
|
|
}
|
|
|
|
|
},
|
2025-08-12 10:08:30 +00:00
|
|
|
NyashValue::Null => "null".to_string(),
|
|
|
|
|
NyashValue::Void => "void".to_string(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Convert to integer (with type coercion)
|
|
|
|
|
pub fn to_integer(&self) -> Result<i64, String> {
|
|
|
|
|
match self {
|
|
|
|
|
NyashValue::Integer(n) => Ok(*n),
|
|
|
|
|
NyashValue::Float(f) => Ok(*f as i64),
|
|
|
|
|
NyashValue::Bool(b) => Ok(if *b { 1 } else { 0 }),
|
|
|
|
|
NyashValue::String(s) => {
|
|
|
|
|
s.parse::<i64>()
|
|
|
|
|
.map_err(|_| format!("Cannot convert '{}' to integer", s))
|
|
|
|
|
},
|
|
|
|
|
_ => Err(format!("Cannot convert {:?} to integer", self.type_name())),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Convert to float (with type coercion)
|
|
|
|
|
pub fn to_float(&self) -> Result<f64, String> {
|
|
|
|
|
match self {
|
|
|
|
|
NyashValue::Integer(n) => Ok(*n as f64),
|
|
|
|
|
NyashValue::Float(f) => Ok(*f),
|
|
|
|
|
NyashValue::Bool(b) => Ok(if *b { 1.0 } else { 0.0 }),
|
|
|
|
|
NyashValue::String(s) => {
|
|
|
|
|
s.parse::<f64>()
|
|
|
|
|
.map_err(|_| format!("Cannot convert '{}' to float", s))
|
|
|
|
|
},
|
|
|
|
|
_ => Err(format!("Cannot convert {:?} to float", self.type_name())),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Convert to boolean (with type coercion)
|
|
|
|
|
pub fn to_bool(&self) -> Result<bool, String> {
|
|
|
|
|
match self {
|
|
|
|
|
NyashValue::Bool(b) => Ok(*b),
|
|
|
|
|
NyashValue::Integer(n) => Ok(*n != 0),
|
|
|
|
|
NyashValue::Float(f) => Ok(*f != 0.0),
|
|
|
|
|
NyashValue::String(s) => Ok(!s.is_empty()),
|
|
|
|
|
NyashValue::Null => Ok(false),
|
|
|
|
|
NyashValue::Void => Ok(false),
|
2025-08-12 20:15:44 +00:00
|
|
|
NyashValue::WeakBox(weak_ref) => {
|
|
|
|
|
// WeakBox is truthy if it can be upgraded (still alive)
|
|
|
|
|
Ok(weak_ref.upgrade().is_some())
|
|
|
|
|
},
|
2025-08-12 10:08:30 +00:00
|
|
|
_ => Ok(true), // Arrays, Maps, Boxes are truthy
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get the type name for error messages
|
|
|
|
|
pub fn type_name(&self) -> &'static str {
|
|
|
|
|
match self {
|
|
|
|
|
NyashValue::Integer(_) => "Integer",
|
|
|
|
|
NyashValue::Float(_) => "Float",
|
|
|
|
|
NyashValue::Bool(_) => "Bool",
|
|
|
|
|
NyashValue::String(_) => "String",
|
|
|
|
|
NyashValue::Array(_) => "Array",
|
|
|
|
|
NyashValue::Map(_) => "Map",
|
|
|
|
|
NyashValue::Box(_) => "Box",
|
2025-08-12 20:15:44 +00:00
|
|
|
NyashValue::WeakBox(_) => "WeakBox",
|
2025-08-12 10:08:30 +00:00
|
|
|
NyashValue::Null => "Null",
|
|
|
|
|
NyashValue::Void => "Void",
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Check if this value is numeric (Integer or Float)
|
|
|
|
|
pub fn is_numeric(&self) -> bool {
|
|
|
|
|
matches!(self, NyashValue::Integer(_) | NyashValue::Float(_))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Check if this value is falsy
|
|
|
|
|
pub fn is_falsy(&self) -> bool {
|
|
|
|
|
matches!(self, NyashValue::Null | NyashValue::Void) ||
|
|
|
|
|
self.to_bool().unwrap_or(false) == false
|
|
|
|
|
}
|
2025-08-12 20:15:44 +00:00
|
|
|
|
|
|
|
|
/// 🔗 Weak Reference System - Core functionality
|
|
|
|
|
|
|
|
|
|
/// Upgrade a weak reference to a strong reference
|
|
|
|
|
/// Returns None if the referenced object has been dropped
|
|
|
|
|
pub fn upgrade_weak(&self) -> Option<NyashValue> {
|
|
|
|
|
match self {
|
|
|
|
|
NyashValue::WeakBox(weak_ref) => {
|
|
|
|
|
weak_ref.upgrade().map(|arc| NyashValue::Box(arc))
|
|
|
|
|
},
|
|
|
|
|
_ => Some(self.clone()), // Non-weak values return themselves
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Downgrade a strong reference to a weak reference
|
|
|
|
|
/// Only works on Box values, others return None
|
|
|
|
|
pub fn downgrade_to_weak(&self) -> Option<NyashValue> {
|
|
|
|
|
match self {
|
|
|
|
|
NyashValue::Box(arc) => {
|
|
|
|
|
Some(NyashValue::WeakBox(Arc::downgrade(arc)))
|
|
|
|
|
},
|
|
|
|
|
_ => None, // Can only create weak refs from strong Box refs
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Check if this is a weak reference
|
|
|
|
|
pub fn is_weak_reference(&self) -> bool {
|
|
|
|
|
matches!(self, NyashValue::WeakBox(_))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Check if a weak reference is still valid (not dropped)
|
|
|
|
|
pub fn is_weak_alive(&self) -> bool {
|
|
|
|
|
match self {
|
|
|
|
|
NyashValue::WeakBox(weak_ref) => weak_ref.strong_count() > 0,
|
|
|
|
|
_ => true, // Non-weak values are always "alive"
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-12 10:08:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl PartialEq for NyashValue {
|
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
|
match (self, other) {
|
|
|
|
|
// Exact type matches
|
|
|
|
|
(NyashValue::Integer(a), NyashValue::Integer(b)) => a == b,
|
|
|
|
|
(NyashValue::Float(a), NyashValue::Float(b)) => (a - b).abs() < f64::EPSILON,
|
|
|
|
|
(NyashValue::Bool(a), NyashValue::Bool(b)) => a == b,
|
|
|
|
|
(NyashValue::String(a), NyashValue::String(b)) => a == b,
|
|
|
|
|
(NyashValue::Null, NyashValue::Null) => true,
|
|
|
|
|
(NyashValue::Void, NyashValue::Void) => true,
|
|
|
|
|
|
|
|
|
|
// Cross-type numeric equality (42 == 42.0)
|
|
|
|
|
(NyashValue::Integer(a), NyashValue::Float(b)) => (*a as f64 - b).abs() < f64::EPSILON,
|
|
|
|
|
(NyashValue::Float(a), NyashValue::Integer(b)) => (a - *b as f64).abs() < f64::EPSILON,
|
|
|
|
|
|
|
|
|
|
// Arrays and Maps require deep comparison (simplified for now)
|
|
|
|
|
(NyashValue::Array(a), NyashValue::Array(b)) => Arc::ptr_eq(a, b),
|
|
|
|
|
(NyashValue::Map(a), NyashValue::Map(b)) => Arc::ptr_eq(a, b),
|
|
|
|
|
(NyashValue::Box(a), NyashValue::Box(b)) => Arc::ptr_eq(a, b),
|
|
|
|
|
|
2025-08-12 20:15:44 +00:00
|
|
|
// Weak reference equality
|
|
|
|
|
(NyashValue::WeakBox(a), NyashValue::WeakBox(b)) => {
|
|
|
|
|
// Compare if they point to the same object (if both still alive)
|
|
|
|
|
match (a.upgrade(), b.upgrade()) {
|
|
|
|
|
(Some(arc_a), Some(arc_b)) => Arc::ptr_eq(&arc_a, &arc_b),
|
|
|
|
|
(None, None) => true, // Both dropped, consider equal
|
|
|
|
|
_ => false, // One dropped, one alive
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// WeakBox vs Box comparison (upgrade weak, then compare)
|
|
|
|
|
(NyashValue::WeakBox(weak), NyashValue::Box(strong)) => {
|
|
|
|
|
if let Some(upgraded) = weak.upgrade() {
|
|
|
|
|
Arc::ptr_eq(&upgraded, strong)
|
|
|
|
|
} else {
|
|
|
|
|
false // Dropped weak ref != any strong ref
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
(NyashValue::Box(strong), NyashValue::WeakBox(weak)) => {
|
|
|
|
|
if let Some(upgraded) = weak.upgrade() {
|
|
|
|
|
Arc::ptr_eq(strong, &upgraded)
|
|
|
|
|
} else {
|
|
|
|
|
false // Dropped weak ref != any strong ref
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2025-08-12 10:08:30 +00:00
|
|
|
// Everything else is not equal
|
|
|
|
|
_ => false,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Display for NyashValue {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
write!(f, "{}", self.to_string())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Debug for NyashValue {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
match self {
|
|
|
|
|
NyashValue::Integer(n) => write!(f, "Integer({})", n),
|
|
|
|
|
NyashValue::Float(fl) => write!(f, "Float({})", fl),
|
|
|
|
|
NyashValue::Bool(b) => write!(f, "Bool({})", b),
|
|
|
|
|
NyashValue::String(s) => write!(f, "String(\"{}\")", s),
|
|
|
|
|
NyashValue::Array(_) => write!(f, "Array([...])"),
|
|
|
|
|
NyashValue::Map(_) => write!(f, "Map({{...}})"),
|
|
|
|
|
NyashValue::Box(_) => write!(f, "Box(...)"),
|
2025-08-12 20:15:44 +00:00
|
|
|
NyashValue::WeakBox(weak_ref) => {
|
|
|
|
|
if weak_ref.upgrade().is_some() {
|
|
|
|
|
write!(f, "WeakBox(alive)")
|
|
|
|
|
} else {
|
|
|
|
|
write!(f, "WeakBox(dropped)")
|
|
|
|
|
}
|
|
|
|
|
},
|
2025-08-12 10:08:30 +00:00
|
|
|
NyashValue::Null => write!(f, "Null"),
|
|
|
|
|
NyashValue::Void => write!(f, "Void"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Legacy Box compatibility - convert from existing Box types
|
|
|
|
|
impl NyashValue {
|
|
|
|
|
/// Convert from a legacy NyashBox to NyashValue
|
|
|
|
|
pub fn from_box(nyash_box: Arc<Mutex<dyn NyashBox>>) -> Self {
|
|
|
|
|
// Try to extract primitive values for better performance
|
|
|
|
|
if let Ok(guard) = nyash_box.try_lock() {
|
|
|
|
|
let type_name = guard.type_name();
|
|
|
|
|
let string_rep = guard.to_string_box().value;
|
|
|
|
|
|
|
|
|
|
// Convert common types to direct values
|
|
|
|
|
match type_name {
|
|
|
|
|
"IntegerBox" => {
|
|
|
|
|
if let Ok(value) = string_rep.parse::<i64>() {
|
|
|
|
|
return NyashValue::Integer(value);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"FloatBox" => {
|
|
|
|
|
if let Ok(value) = string_rep.parse::<f64>() {
|
|
|
|
|
return NyashValue::Float(value);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"BoolBox" => {
|
|
|
|
|
if let Ok(value) = string_rep.parse::<bool>() {
|
|
|
|
|
return NyashValue::Bool(value);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"StringBox" => {
|
|
|
|
|
return NyashValue::String(string_rep);
|
|
|
|
|
},
|
|
|
|
|
"NullBox" => {
|
|
|
|
|
return NyashValue::Null;
|
|
|
|
|
},
|
|
|
|
|
"VoidBox" => {
|
|
|
|
|
return NyashValue::Void;
|
|
|
|
|
},
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fallback to Box wrapper
|
|
|
|
|
NyashValue::Box(nyash_box)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Convert back to a legacy NyashBox for compatibility
|
|
|
|
|
pub fn to_box(&self) -> Result<Arc<Mutex<dyn NyashBox>>, String> {
|
|
|
|
|
use crate::box_trait::{StringBox, IntegerBox, BoolBox, VoidBox};
|
|
|
|
|
use crate::boxes::null_box::NullBox;
|
|
|
|
|
|
|
|
|
|
match self {
|
|
|
|
|
NyashValue::Integer(n) => {
|
|
|
|
|
Ok(Arc::new(Mutex::new(IntegerBox::new(*n))))
|
|
|
|
|
},
|
|
|
|
|
NyashValue::Float(f) => {
|
|
|
|
|
// Note: Need FloatBox implementation - for now convert to string
|
|
|
|
|
Ok(Arc::new(Mutex::new(StringBox::new(f.to_string()))))
|
|
|
|
|
},
|
|
|
|
|
NyashValue::Bool(b) => {
|
|
|
|
|
Ok(Arc::new(Mutex::new(BoolBox::new(*b))))
|
|
|
|
|
},
|
|
|
|
|
NyashValue::String(s) => {
|
|
|
|
|
Ok(Arc::new(Mutex::new(StringBox::new(s.clone()))))
|
|
|
|
|
},
|
|
|
|
|
NyashValue::Null => {
|
|
|
|
|
Ok(Arc::new(Mutex::new(NullBox::new())))
|
|
|
|
|
},
|
|
|
|
|
NyashValue::Void => {
|
|
|
|
|
Ok(Arc::new(Mutex::new(VoidBox::new())))
|
|
|
|
|
},
|
|
|
|
|
NyashValue::Box(b) => {
|
|
|
|
|
Ok(b.clone())
|
|
|
|
|
},
|
2025-08-12 20:15:44 +00:00
|
|
|
NyashValue::WeakBox(weak_ref) => {
|
|
|
|
|
// Try to upgrade weak reference
|
|
|
|
|
match weak_ref.upgrade() {
|
|
|
|
|
Some(arc) => Ok(arc),
|
|
|
|
|
None => Err("Cannot convert dropped weak reference to Box".to_string()),
|
|
|
|
|
}
|
|
|
|
|
},
|
2025-08-12 10:08:30 +00:00
|
|
|
_ => Err(format!("Cannot convert {} to legacy Box", self.type_name())),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Unified object creation system
|
|
|
|
|
impl NyashValue {
|
|
|
|
|
/// Create objects of different types with unified interface
|
|
|
|
|
pub fn create_object(type_name: &str, args: Vec<NyashValue>) -> Result<NyashValue, String> {
|
|
|
|
|
match type_name {
|
|
|
|
|
"StringBox" => {
|
|
|
|
|
let value = match args.get(0) {
|
|
|
|
|
Some(arg) => arg.to_string(),
|
|
|
|
|
None => String::new(),
|
|
|
|
|
};
|
|
|
|
|
Ok(NyashValue::String(value))
|
|
|
|
|
},
|
|
|
|
|
"IntegerBox" => {
|
|
|
|
|
let value = match args.get(0) {
|
|
|
|
|
Some(arg) => arg.to_integer()?,
|
|
|
|
|
None => 0,
|
|
|
|
|
};
|
|
|
|
|
Ok(NyashValue::Integer(value))
|
|
|
|
|
},
|
|
|
|
|
"FloatBox" => {
|
|
|
|
|
let value = match args.get(0) {
|
|
|
|
|
Some(arg) => arg.to_float()?,
|
|
|
|
|
None => 0.0,
|
|
|
|
|
};
|
|
|
|
|
Ok(NyashValue::Float(value))
|
|
|
|
|
},
|
|
|
|
|
"BoolBox" => {
|
|
|
|
|
let value = match args.get(0) {
|
|
|
|
|
Some(arg) => arg.to_bool()?,
|
|
|
|
|
None => false,
|
|
|
|
|
};
|
|
|
|
|
Ok(NyashValue::Bool(value))
|
|
|
|
|
},
|
|
|
|
|
"ArrayBox" => {
|
|
|
|
|
Ok(NyashValue::Array(Arc::new(Mutex::new(Vec::new()))))
|
|
|
|
|
},
|
|
|
|
|
"MapBox" => {
|
|
|
|
|
Ok(NyashValue::Map(Arc::new(Mutex::new(HashMap::new()))))
|
|
|
|
|
},
|
|
|
|
|
_ => {
|
|
|
|
|
Err(format!("Unknown object type: {}", type_name))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_basic_creation() {
|
|
|
|
|
let int_val = NyashValue::new_integer(42);
|
|
|
|
|
let float_val = NyashValue::new_float(3.14);
|
|
|
|
|
let bool_val = NyashValue::new_bool(true);
|
|
|
|
|
let string_val = NyashValue::new_string("hello".to_string());
|
|
|
|
|
|
|
|
|
|
assert_eq!(int_val.to_string(), "42");
|
|
|
|
|
assert_eq!(float_val.to_string(), "3.14");
|
|
|
|
|
assert_eq!(bool_val.to_string(), "true");
|
|
|
|
|
assert_eq!(string_val.to_string(), "hello");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_type_conversion() {
|
|
|
|
|
let int_val = NyashValue::new_integer(42);
|
|
|
|
|
assert_eq!(int_val.to_float().unwrap(), 42.0);
|
|
|
|
|
assert_eq!(int_val.to_bool().unwrap(), true);
|
|
|
|
|
|
|
|
|
|
let float_val = NyashValue::new_float(3.14);
|
|
|
|
|
assert_eq!(float_val.to_integer().unwrap(), 3);
|
|
|
|
|
|
|
|
|
|
let zero_val = NyashValue::new_integer(0);
|
|
|
|
|
assert_eq!(zero_val.to_bool().unwrap(), false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_cross_type_equality() {
|
|
|
|
|
let int_val = NyashValue::new_integer(42);
|
|
|
|
|
let float_val = NyashValue::new_float(42.0);
|
|
|
|
|
|
|
|
|
|
assert_eq!(int_val, float_val);
|
|
|
|
|
assert_eq!(float_val, int_val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_object_creation() {
|
|
|
|
|
let string_obj = NyashValue::create_object("StringBox", vec![
|
|
|
|
|
NyashValue::new_string("test".to_string())
|
|
|
|
|
]).unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(string_obj.to_string(), "test");
|
|
|
|
|
|
|
|
|
|
let int_obj = NyashValue::create_object("IntegerBox", vec![
|
|
|
|
|
NyashValue::new_integer(100)
|
|
|
|
|
]).unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(int_obj.to_integer().unwrap(), 100);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_type_names() {
|
|
|
|
|
assert_eq!(NyashValue::new_integer(1).type_name(), "Integer");
|
|
|
|
|
assert_eq!(NyashValue::new_float(1.0).type_name(), "Float");
|
|
|
|
|
assert_eq!(NyashValue::new_bool(true).type_name(), "Bool");
|
|
|
|
|
assert_eq!(NyashValue::new_string("".to_string()).type_name(), "String");
|
|
|
|
|
assert_eq!(NyashValue::new_null().type_name(), "Null");
|
|
|
|
|
assert_eq!(NyashValue::new_void().type_name(), "Void");
|
|
|
|
|
}
|
2025-08-12 20:15:44 +00:00
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_weak_reference_basic() {
|
|
|
|
|
use crate::box_trait::StringBox;
|
|
|
|
|
|
|
|
|
|
// Create a strong reference
|
|
|
|
|
let strong_ref = NyashValue::Box(Arc::new(Mutex::new(StringBox::new("test".to_string()))));
|
|
|
|
|
|
|
|
|
|
// Create weak reference
|
|
|
|
|
let weak_ref = strong_ref.downgrade_to_weak().unwrap();
|
|
|
|
|
assert!(weak_ref.is_weak_reference());
|
|
|
|
|
assert_eq!(weak_ref.type_name(), "WeakBox");
|
|
|
|
|
|
|
|
|
|
// Upgrade should work
|
|
|
|
|
let upgraded = weak_ref.upgrade_weak().unwrap();
|
|
|
|
|
assert_eq!(upgraded, strong_ref);
|
|
|
|
|
|
|
|
|
|
// Both should be alive initially
|
|
|
|
|
assert!(weak_ref.is_weak_alive());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_weak_reference_drop() {
|
|
|
|
|
use crate::box_trait::StringBox;
|
|
|
|
|
|
|
|
|
|
let weak_ref = {
|
|
|
|
|
let strong_ref = NyashValue::Box(Arc::new(Mutex::new(StringBox::new("test".to_string()))));
|
|
|
|
|
strong_ref.downgrade_to_weak().unwrap()
|
|
|
|
|
}; // strong_ref goes out of scope and is dropped
|
|
|
|
|
|
|
|
|
|
// Weak reference should now be invalid
|
|
|
|
|
assert!(!weak_ref.is_weak_alive());
|
|
|
|
|
assert!(weak_ref.upgrade_weak().is_none());
|
|
|
|
|
|
|
|
|
|
// to_bool should return false for dropped weak ref
|
|
|
|
|
assert_eq!(weak_ref.to_bool().unwrap(), false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_weak_reference_equality() {
|
|
|
|
|
use crate::box_trait::StringBox;
|
|
|
|
|
|
|
|
|
|
let strong_ref = NyashValue::Box(Arc::new(Mutex::new(StringBox::new("test".to_string()))));
|
|
|
|
|
let weak_ref1 = strong_ref.downgrade_to_weak().unwrap();
|
|
|
|
|
let weak_ref2 = strong_ref.downgrade_to_weak().unwrap();
|
|
|
|
|
|
|
|
|
|
// Weak refs to same object should be equal
|
|
|
|
|
assert_eq!(weak_ref1, weak_ref2);
|
|
|
|
|
|
|
|
|
|
// Weak ref should equal its strong ref
|
|
|
|
|
assert_eq!(weak_ref1, strong_ref);
|
|
|
|
|
assert_eq!(strong_ref, weak_ref1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_weak_reference_string_representation() {
|
|
|
|
|
use crate::box_trait::StringBox;
|
|
|
|
|
|
|
|
|
|
let strong_ref = NyashValue::Box(Arc::new(Mutex::new(StringBox::new("hello".to_string()))));
|
|
|
|
|
let weak_ref = strong_ref.downgrade_to_weak().unwrap();
|
|
|
|
|
|
|
|
|
|
// Should show weak reference to the content
|
|
|
|
|
assert!(weak_ref.to_string().contains("WeakRef"));
|
|
|
|
|
assert!(weak_ref.to_string().contains("hello"));
|
|
|
|
|
|
|
|
|
|
// After dropping strong ref
|
|
|
|
|
drop(strong_ref);
|
|
|
|
|
assert_eq!(weak_ref.to_string(), "WeakRef(null)");
|
|
|
|
|
}
|
2025-08-12 10:08:30 +00:00
|
|
|
}
|