use crate::stack::{Stack, peek_heap_mut_second, pop, push};
use crate::value::Value;
use std::sync::Arc;
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_variant_field_count(stack: Stack) -> Stack {
unsafe {
let (stack, value) = pop(stack);
match value {
Value::Variant(variant_data) => {
let count = variant_data.fields.len() as i64;
push(stack, Value::Int(count))
}
_ => panic!("variant-field-count: expected Variant, got {:?}", value),
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_variant_tag(stack: Stack) -> Stack {
unsafe {
let (stack, value) = pop(stack);
match value {
Value::Variant(variant_data) => {
push(stack, Value::Symbol(variant_data.tag.clone()))
}
_ => panic!("variant-tag: expected Variant, got {:?}", value),
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_symbol_eq_cstr(stack: Stack, c_str: *const i8) -> Stack {
use std::ffi::CStr;
unsafe {
let (stack, value) = pop(stack);
let symbol_str = match value {
Value::Symbol(s) => s,
_ => panic!("symbol_eq_cstr: expected Symbol, got {:?}", value),
};
let expected = CStr::from_ptr(c_str)
.to_str()
.expect("Invalid UTF-8 in variant name");
let is_equal = symbol_str.as_str() == expected;
push(stack, Value::Bool(is_equal))
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_variant_field_at(stack: Stack) -> Stack {
unsafe {
let (stack, index_val) = pop(stack);
let index = match index_val {
Value::Int(i) => i,
_ => panic!(
"variant-field-at: expected Int (index), got {:?}",
index_val
),
};
if index < 0 {
panic!("variant-field-at: index cannot be negative: {}", index);
}
let (stack, variant_val) = pop(stack);
match variant_val {
Value::Variant(variant_data) => {
let idx = index as usize;
if idx >= variant_data.fields.len() {
panic!(
"variant-field-at: index {} out of bounds (variant has {} fields)",
index,
variant_data.fields.len()
);
}
let field = variant_data.fields[idx].clone();
push(stack, field)
}
_ => panic!("variant-field-at: expected Variant, got {:?}", variant_val),
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_make_variant_0(stack: Stack) -> Stack {
use crate::value::VariantData;
unsafe {
let (stack, tag_val) = pop(stack);
let tag = match tag_val {
Value::Symbol(s) => s,
_ => panic!("make-variant-0: expected Symbol (tag), got {:?}", tag_val),
};
let variant = Value::Variant(Arc::new(VariantData::new(tag, vec![])));
push(stack, variant)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_make_variant_1(stack: Stack) -> Stack {
use crate::value::VariantData;
unsafe {
let (stack, tag_val) = pop(stack);
let tag = match tag_val {
Value::Symbol(s) => s,
_ => panic!("make-variant-1: expected Symbol (tag), got {:?}", tag_val),
};
let (stack, field1) = pop(stack);
let variant = Value::Variant(Arc::new(VariantData::new(tag, vec![field1])));
push(stack, variant)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_make_variant_2(stack: Stack) -> Stack {
use crate::value::VariantData;
unsafe {
let (stack, tag_val) = pop(stack);
let tag = match tag_val {
Value::Symbol(s) => s,
_ => panic!("make-variant-2: expected Symbol (tag), got {:?}", tag_val),
};
let (stack, field2) = pop(stack);
let (stack, field1) = pop(stack);
let variant = Value::Variant(Arc::new(VariantData::new(tag, vec![field1, field2])));
push(stack, variant)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_make_variant_3(stack: Stack) -> Stack {
use crate::value::VariantData;
unsafe {
let (stack, tag_val) = pop(stack);
let tag = match tag_val {
Value::Symbol(s) => s,
_ => panic!("make-variant-3: expected Symbol (tag), got {:?}", tag_val),
};
let (stack, field3) = pop(stack);
let (stack, field2) = pop(stack);
let (stack, field1) = pop(stack);
let variant = Value::Variant(Arc::new(VariantData::new(
tag,
vec![field1, field2, field3],
)));
push(stack, variant)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_make_variant_4(stack: Stack) -> Stack {
use crate::value::VariantData;
unsafe {
let (stack, tag_val) = pop(stack);
let tag = match tag_val {
Value::Symbol(s) => s,
_ => panic!("make-variant-4: expected Symbol (tag), got {:?}", tag_val),
};
let (stack, field4) = pop(stack);
let (stack, field3) = pop(stack);
let (stack, field2) = pop(stack);
let (stack, field1) = pop(stack);
let variant = Value::Variant(Arc::new(VariantData::new(
tag,
vec![field1, field2, field3, field4],
)));
push(stack, variant)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_make_variant_5(stack: Stack) -> Stack {
use crate::value::VariantData;
unsafe {
let (stack, tag_val) = pop(stack);
let tag = match tag_val {
Value::Symbol(s) => s,
_ => panic!("make-variant-5: expected Symbol (tag), got {:?}", tag_val),
};
let (stack, field5) = pop(stack);
let (stack, field4) = pop(stack);
let (stack, field3) = pop(stack);
let (stack, field2) = pop(stack);
let (stack, field1) = pop(stack);
let variant = Value::Variant(Arc::new(VariantData::new(
tag,
vec![field1, field2, field3, field4, field5],
)));
push(stack, variant)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_make_variant_6(stack: Stack) -> Stack {
use crate::value::VariantData;
unsafe {
let (stack, tag_val) = pop(stack);
let tag = match tag_val {
Value::Symbol(s) => s,
_ => panic!("make-variant-6: expected Symbol (tag), got {:?}", tag_val),
};
let (stack, field6) = pop(stack);
let (stack, field5) = pop(stack);
let (stack, field4) = pop(stack);
let (stack, field3) = pop(stack);
let (stack, field2) = pop(stack);
let (stack, field1) = pop(stack);
let variant = Value::Variant(Arc::new(VariantData::new(
tag,
vec![field1, field2, field3, field4, field5, field6],
)));
push(stack, variant)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_make_variant_7(stack: Stack) -> Stack {
use crate::value::VariantData;
unsafe {
let (stack, tag_val) = pop(stack);
let tag = match tag_val {
Value::Symbol(s) => s,
_ => panic!("make-variant-7: expected Symbol (tag), got {:?}", tag_val),
};
let (stack, field7) = pop(stack);
let (stack, field6) = pop(stack);
let (stack, field5) = pop(stack);
let (stack, field4) = pop(stack);
let (stack, field3) = pop(stack);
let (stack, field2) = pop(stack);
let (stack, field1) = pop(stack);
let variant = Value::Variant(Arc::new(VariantData::new(
tag,
vec![field1, field2, field3, field4, field5, field6, field7],
)));
push(stack, variant)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_make_variant_8(stack: Stack) -> Stack {
use crate::value::VariantData;
unsafe {
let (stack, tag_val) = pop(stack);
let tag = match tag_val {
Value::Symbol(s) => s,
_ => panic!("make-variant-8: expected Symbol (tag), got {:?}", tag_val),
};
let (stack, field8) = pop(stack);
let (stack, field7) = pop(stack);
let (stack, field6) = pop(stack);
let (stack, field5) = pop(stack);
let (stack, field4) = pop(stack);
let (stack, field3) = pop(stack);
let (stack, field2) = pop(stack);
let (stack, field1) = pop(stack);
let variant = Value::Variant(Arc::new(VariantData::new(
tag,
vec![
field1, field2, field3, field4, field5, field6, field7, field8,
],
)));
push(stack, variant)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_make_variant_9(stack: Stack) -> Stack {
use crate::value::VariantData;
unsafe {
let (stack, tag_val) = pop(stack);
let tag = match tag_val {
Value::Symbol(s) => s,
_ => panic!("make-variant-9: expected Symbol (tag), got {:?}", tag_val),
};
let (stack, field9) = pop(stack);
let (stack, field8) = pop(stack);
let (stack, field7) = pop(stack);
let (stack, field6) = pop(stack);
let (stack, field5) = pop(stack);
let (stack, field4) = pop(stack);
let (stack, field3) = pop(stack);
let (stack, field2) = pop(stack);
let (stack, field1) = pop(stack);
let variant = Value::Variant(Arc::new(VariantData::new(
tag,
vec![
field1, field2, field3, field4, field5, field6, field7, field8, field9,
],
)));
push(stack, variant)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_make_variant_10(stack: Stack) -> Stack {
use crate::value::VariantData;
unsafe {
let (stack, tag_val) = pop(stack);
let tag = match tag_val {
Value::Symbol(s) => s,
_ => panic!("make-variant-10: expected Symbol (tag), got {:?}", tag_val),
};
let (stack, field10) = pop(stack);
let (stack, field9) = pop(stack);
let (stack, field8) = pop(stack);
let (stack, field7) = pop(stack);
let (stack, field6) = pop(stack);
let (stack, field5) = pop(stack);
let (stack, field4) = pop(stack);
let (stack, field3) = pop(stack);
let (stack, field2) = pop(stack);
let (stack, field1) = pop(stack);
let variant = Value::Variant(Arc::new(VariantData::new(
tag,
vec![
field1, field2, field3, field4, field5, field6, field7, field8, field9, field10,
],
)));
push(stack, variant)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_make_variant_11(stack: Stack) -> Stack {
use crate::value::VariantData;
unsafe {
let (stack, tag_val) = pop(stack);
let tag = match tag_val {
Value::Symbol(s) => s,
_ => panic!("make-variant-11: expected Symbol (tag), got {:?}", tag_val),
};
let (stack, field11) = pop(stack);
let (stack, field10) = pop(stack);
let (stack, field9) = pop(stack);
let (stack, field8) = pop(stack);
let (stack, field7) = pop(stack);
let (stack, field6) = pop(stack);
let (stack, field5) = pop(stack);
let (stack, field4) = pop(stack);
let (stack, field3) = pop(stack);
let (stack, field2) = pop(stack);
let (stack, field1) = pop(stack);
let variant = Value::Variant(Arc::new(VariantData::new(
tag,
vec![
field1, field2, field3, field4, field5, field6, field7, field8, field9, field10,
field11,
],
)));
push(stack, variant)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_make_variant_12(stack: Stack) -> Stack {
use crate::value::VariantData;
unsafe {
let (stack, tag_val) = pop(stack);
let tag = match tag_val {
Value::Symbol(s) => s,
_ => panic!("make-variant-12: expected Symbol (tag), got {:?}", tag_val),
};
let (stack, field12) = pop(stack);
let (stack, field11) = pop(stack);
let (stack, field10) = pop(stack);
let (stack, field9) = pop(stack);
let (stack, field8) = pop(stack);
let (stack, field7) = pop(stack);
let (stack, field6) = pop(stack);
let (stack, field5) = pop(stack);
let (stack, field4) = pop(stack);
let (stack, field3) = pop(stack);
let (stack, field2) = pop(stack);
let (stack, field1) = pop(stack);
let variant = Value::Variant(Arc::new(VariantData::new(
tag,
vec![
field1, field2, field3, field4, field5, field6, field7, field8, field9, field10,
field11, field12,
],
)));
push(stack, variant)
}
}
pub use patch_seq_make_variant_0 as make_variant_0;
pub use patch_seq_make_variant_1 as make_variant_1;
pub use patch_seq_make_variant_2 as make_variant_2;
pub use patch_seq_make_variant_3 as make_variant_3;
pub use patch_seq_make_variant_4 as make_variant_4;
pub use patch_seq_make_variant_5 as make_variant_5;
pub use patch_seq_make_variant_6 as make_variant_6;
pub use patch_seq_make_variant_7 as make_variant_7;
pub use patch_seq_make_variant_8 as make_variant_8;
pub use patch_seq_make_variant_9 as make_variant_9;
pub use patch_seq_make_variant_10 as make_variant_10;
pub use patch_seq_make_variant_11 as make_variant_11;
pub use patch_seq_make_variant_12 as make_variant_12;
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_variant_append(stack: Stack) -> Stack {
use crate::value::VariantData;
unsafe {
if let Some(Value::Variant(variant_arc)) = peek_heap_mut_second(stack)
&& let Some(data) = Arc::get_mut(variant_arc)
{
let (stack, value) = pop(stack);
data.fields.push(value);
return stack; }
let (stack, value) = pop(stack);
let (stack, variant_val) = pop(stack);
match variant_val {
Value::Variant(mut arc) => {
if let Some(data) = Arc::get_mut(&mut arc) {
data.fields.push(value);
push(stack, Value::Variant(arc))
} else {
let mut new_fields = Vec::with_capacity(arc.fields.len() + 1);
new_fields.extend(arc.fields.iter().cloned());
new_fields.push(value);
let new_variant =
Value::Variant(Arc::new(VariantData::new(arc.tag.clone(), new_fields)));
push(stack, new_variant)
}
}
_ => panic!("variant-append: expected Variant, got {:?}", variant_val),
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_variant_last(stack: Stack) -> Stack {
unsafe {
let (stack, variant_val) = pop(stack);
match variant_val {
Value::Variant(variant_data) => {
if variant_data.fields.is_empty() {
panic!("variant-last: variant has no fields");
}
let last = variant_data.fields.last().unwrap().clone();
push(stack, last)
}
_ => panic!("variant-last: expected Variant, got {:?}", variant_val),
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_variant_init(stack: Stack) -> Stack {
use crate::value::VariantData;
unsafe {
let (stack, variant_val) = pop(stack);
match variant_val {
Value::Variant(variant_data) => {
if variant_data.fields.is_empty() {
panic!("variant-init: variant has no fields");
}
let new_fields: Vec<Value> =
variant_data.fields[..variant_data.fields.len() - 1].to_vec();
let new_variant = Value::Variant(Arc::new(VariantData::new(
variant_data.tag.clone(),
new_fields,
)));
push(stack, new_variant)
}
_ => panic!("variant-init: expected Variant, got {:?}", variant_val),
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_unpack_variant(stack: Stack, field_count: i64) -> Stack {
unsafe {
let (mut stack, variant_val) = pop(stack);
match variant_val {
Value::Variant(variant_data) => {
let count = field_count as usize;
if count > variant_data.fields.len() {
panic!(
"unpack-variant: requested {} fields but variant only has {}",
count,
variant_data.fields.len()
);
}
for i in 0..count {
stack = push(stack, variant_data.fields[i].clone());
}
stack
}
_ => panic!("unpack-variant: expected Variant, got {:?}", variant_val),
}
}
}
pub use patch_seq_unpack_variant as unpack_variant;
pub use patch_seq_variant_append as variant_append;
pub use patch_seq_variant_field_at as variant_field_at;
pub use patch_seq_variant_field_count as variant_field_count;
pub use patch_seq_variant_init as variant_init;
pub use patch_seq_variant_last as variant_last;
pub use patch_seq_variant_tag as variant_tag;
#[cfg(test)]
mod tests {
use super::*;
use crate::seqstring::global_string;
use crate::value::VariantData;
#[test]
fn test_variant_field_count() {
unsafe {
let variant = Value::Variant(Arc::new(VariantData::new(
global_string("TestTag".to_string()),
vec![Value::Int(10), Value::Int(20), Value::Int(30)],
)));
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, variant);
let stack = variant_field_count(stack);
let (_stack, result) = pop(stack);
assert_eq!(result, Value::Int(3));
}
}
#[test]
fn test_variant_tag() {
unsafe {
let variant = Value::Variant(Arc::new(VariantData::new(
global_string("MyTag".to_string()),
vec![Value::Int(10)],
)));
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, variant);
let stack = variant_tag(stack);
let (_stack, result) = pop(stack);
assert_eq!(result, Value::Symbol(global_string("MyTag".to_string())));
}
}
#[test]
fn test_variant_field_at() {
unsafe {
let str1 = global_string("hello".to_string());
let str2 = global_string("world".to_string());
let variant = Value::Variant(Arc::new(VariantData::new(
global_string("TestTag".to_string()),
vec![
Value::String(str1.clone()),
Value::Int(42),
Value::String(str2.clone()),
],
)));
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, variant.clone());
let stack = push(stack, Value::Int(0));
let stack = variant_field_at(stack);
let (_stack, result) = pop(stack);
assert_eq!(result, Value::String(str1.clone()));
let stack = push(stack, variant.clone());
let stack = push(stack, Value::Int(1));
let stack = variant_field_at(stack);
let (_stack, result) = pop(stack);
assert_eq!(result, Value::Int(42));
let stack = push(stack, variant.clone());
let stack = push(stack, Value::Int(2));
let stack = variant_field_at(stack);
let (_stack, result) = pop(stack);
assert_eq!(result, Value::String(str2));
}
}
#[test]
fn test_variant_field_count_empty() {
unsafe {
let variant = Value::Variant(Arc::new(VariantData::new(
global_string("Empty".to_string()),
vec![],
)));
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, variant);
let stack = variant_field_count(stack);
let (_stack, result) = pop(stack);
assert_eq!(result, Value::Int(0));
}
}
#[test]
fn test_make_variant_with_fields() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Int(10)); let stack = push(stack, Value::Int(20)); let stack = push(stack, Value::Int(30)); let stack = push(stack, Value::Symbol(global_string("Tag".to_string())));
let stack = make_variant_3(stack);
let (_stack, result) = pop(stack);
match result {
Value::Variant(v) => {
assert_eq!(v.tag.as_str(), "Tag");
assert_eq!(v.fields.len(), 3);
assert_eq!(v.fields[0], Value::Int(10));
assert_eq!(v.fields[1], Value::Int(20));
assert_eq!(v.fields[2], Value::Int(30));
}
_ => panic!("Expected Variant"),
}
}
}
#[test]
fn test_make_variant_empty() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Symbol(global_string("None".to_string())));
let stack = make_variant_0(stack);
let (_stack, result) = pop(stack);
match result {
Value::Variant(v) => {
assert_eq!(v.tag.as_str(), "None");
assert_eq!(v.fields.len(), 0);
}
_ => panic!("Expected Variant"),
}
}
}
#[test]
fn test_make_variant_with_mixed_types() {
unsafe {
let s = global_string("hello".to_string());
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Int(42));
let stack = push(stack, Value::String(s.clone()));
let stack = push(stack, Value::Float(3.5));
let stack = push(stack, Value::Symbol(global_string("Mixed".to_string())));
let stack = make_variant_3(stack);
let (_stack, result) = pop(stack);
match result {
Value::Variant(v) => {
assert_eq!(v.tag.as_str(), "Mixed");
assert_eq!(v.fields.len(), 3);
assert_eq!(v.fields[0], Value::Int(42));
assert_eq!(v.fields[1], Value::String(s));
assert_eq!(v.fields[2], Value::Float(3.5));
}
_ => panic!("Expected Variant"),
}
}
}
#[test]
fn test_variant_append() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Symbol(global_string("Array".to_string()))); let stack = make_variant_0(stack);
let stack = push(stack, Value::Int(42));
let stack = variant_append(stack);
let (_stack, result) = pop(stack);
match result {
Value::Variant(v) => {
assert_eq!(v.tag.as_str(), "Array");
assert_eq!(v.fields.len(), 1);
assert_eq!(v.fields[0], Value::Int(42));
}
_ => panic!("Expected Variant"),
}
}
}
#[test]
fn test_variant_append_multiple() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Symbol(global_string("Object".to_string()))); let stack = make_variant_0(stack);
let key = global_string("name".to_string());
let stack = push(stack, Value::String(key.clone()));
let stack = variant_append(stack);
let val = global_string("John".to_string());
let stack = push(stack, Value::String(val.clone()));
let stack = variant_append(stack);
let (_stack, result) = pop(stack);
match result {
Value::Variant(v) => {
assert_eq!(v.tag.as_str(), "Object");
assert_eq!(v.fields.len(), 2);
assert_eq!(v.fields[0], Value::String(key));
assert_eq!(v.fields[1], Value::String(val));
}
_ => panic!("Expected Variant"),
}
}
}
#[test]
fn test_variant_last() {
unsafe {
let variant = Value::Variant(Arc::new(VariantData::new(
global_string("List".to_string()),
vec![Value::Int(10), Value::Int(20), Value::Int(30)],
)));
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, variant);
let stack = variant_last(stack);
let (_stack, result) = pop(stack);
assert_eq!(result, Value::Int(30));
}
}
#[test]
fn test_variant_init() {
unsafe {
let variant = Value::Variant(Arc::new(VariantData::new(
global_string("Custom".to_string()),
vec![Value::Int(10), Value::Int(20), Value::Int(30)],
)));
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, variant);
let stack = variant_init(stack);
let (_stack, result) = pop(stack);
match result {
Value::Variant(v) => {
assert_eq!(v.tag.as_str(), "Custom"); assert_eq!(v.fields.len(), 2);
assert_eq!(v.fields[0], Value::Int(10));
assert_eq!(v.fields[1], Value::Int(20));
}
_ => panic!("Expected Variant"),
}
}
}
#[test]
fn test_variant_stack_operations() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Symbol(global_string("Stack".to_string()))); let stack = make_variant_0(stack);
let stack = push(stack, Value::Int(10));
let stack = variant_append(stack);
let stack = push(stack, Value::Int(20));
let stack = variant_append(stack);
let (stack, variant) = pop(stack);
let stack = push(stack, variant.clone());
let stack = push(stack, variant);
let stack = variant_last(stack);
let (stack, top) = pop(stack);
assert_eq!(top, Value::Int(20));
let stack = variant_init(stack);
let (stack, variant) = pop(stack);
let stack = push(stack, variant.clone());
let stack = push(stack, variant);
let stack = variant_last(stack);
let (stack, top) = pop(stack);
assert_eq!(top, Value::Int(10));
let (_stack, result) = pop(stack);
match result {
Value::Variant(v) => {
assert_eq!(v.fields.len(), 1);
assert_eq!(v.fields[0], Value::Int(10));
}
_ => panic!("Expected Variant"),
}
}
}
#[test]
fn test_variant_clone_is_o1() {
let mut variant = Value::Variant(Arc::new(VariantData::new(
global_string("Level0".to_string()),
vec![],
)));
for i in 0..100 {
variant = Value::Variant(Arc::new(VariantData::new(
global_string(format!("Level{}", i)),
vec![variant.clone()],
)));
}
let start = std::time::Instant::now();
for _ in 0..1000 {
let _copy = variant.clone();
}
let elapsed = start.elapsed();
assert!(
elapsed.as_millis() < 10,
"Clone took {:?} - should be O(1) with Arc",
elapsed
);
}
#[test]
fn test_variant_arc_sharing() {
let inner = Value::Variant(Arc::new(VariantData::new(
global_string("Inner".to_string()),
vec![Value::Int(42)],
)));
let outer = Value::Variant(Arc::new(VariantData::new(
global_string("Outer".to_string()),
vec![inner.clone()],
)));
let outer_clone = outer.clone();
match (&outer, &outer_clone) {
(Value::Variant(a), Value::Variant(b)) => {
assert_eq!(a.tag, b.tag);
assert_eq!(a.fields.len(), b.fields.len());
}
_ => panic!("Expected Variants"),
}
}
#[test]
fn test_variant_thread_safe_sharing() {
use std::sync::Arc as StdArc;
use std::thread;
let variant = Value::Variant(Arc::new(VariantData::new(
global_string("ThreadSafe".to_string()),
vec![Value::Int(1), Value::Int(2), Value::Int(3)],
)));
let shared = StdArc::new(variant);
let handles: Vec<_> = (0..4)
.map(|_| {
let v = StdArc::clone(&shared);
thread::spawn(move || {
match &*v {
Value::Variant(data) => {
assert_eq!(data.tag.as_str(), "ThreadSafe");
assert_eq!(data.fields.len(), 3);
}
_ => panic!("Expected Variant"),
}
})
})
.collect();
for h in handles {
h.join().expect("Thread panicked");
}
}
}