seq_runtime/
variant_ops.rs

1//! Variant field access operations for Seq
2//!
3//! Provides runtime functions for accessing variant fields, tags, and metadata.
4//! These are used to work with composite data created by operations like string-split.
5
6use crate::stack::{Stack, pop, push};
7use crate::value::Value;
8use std::sync::Arc;
9
10/// Get the number of fields in a variant
11///
12/// Stack effect: ( Variant -- Int )
13///
14/// # Safety
15/// Stack must have a Variant on top
16#[unsafe(no_mangle)]
17pub unsafe extern "C" fn patch_seq_variant_field_count(stack: Stack) -> Stack {
18    unsafe {
19        let (stack, value) = pop(stack);
20
21        match value {
22            Value::Variant(variant_data) => {
23                let count = variant_data.fields.len() as i64;
24                push(stack, Value::Int(count))
25            }
26            _ => panic!("variant-field-count: expected Variant, got {:?}", value),
27        }
28    }
29}
30
31/// Get the tag of a variant
32///
33/// Stack effect: ( Variant -- Int )
34///
35/// # Safety
36/// Stack must have a Variant on top
37#[unsafe(no_mangle)]
38pub unsafe extern "C" fn patch_seq_variant_tag(stack: Stack) -> Stack {
39    unsafe {
40        let (stack, value) = pop(stack);
41
42        match value {
43            Value::Variant(variant_data) => {
44                let tag = variant_data.tag as i64;
45                push(stack, Value::Int(tag))
46            }
47            _ => panic!("variant-tag: expected Variant, got {:?}", value),
48        }
49    }
50}
51
52/// Get a field from a variant at the given index
53///
54/// Stack effect: ( Variant Int -- Value )
55///
56/// Returns a clone of the field value at the specified index.
57/// Panics if index is out of bounds (this is a programming bug, not recoverable).
58/// Use variant.field-count to check bounds first if needed.
59///
60/// # Safety
61/// Stack must have a Variant and Int on top
62#[unsafe(no_mangle)]
63pub unsafe extern "C" fn patch_seq_variant_field_at(stack: Stack) -> Stack {
64    unsafe {
65        let (stack, index_val) = pop(stack);
66        let index = match index_val {
67            Value::Int(i) => i,
68            _ => panic!(
69                "variant-field-at: expected Int (index), got {:?}",
70                index_val
71            ),
72        };
73
74        if index < 0 {
75            panic!("variant-field-at: index cannot be negative: {}", index);
76        }
77
78        let (stack, variant_val) = pop(stack);
79
80        match variant_val {
81            Value::Variant(variant_data) => {
82                let idx = index as usize;
83                if idx >= variant_data.fields.len() {
84                    panic!(
85                        "variant-field-at: index {} out of bounds (variant has {} fields)",
86                        index,
87                        variant_data.fields.len()
88                    );
89                }
90
91                // Clone the field value and push it
92                let field = variant_data.fields[idx].clone();
93                push(stack, field)
94            }
95            _ => panic!("variant-field-at: expected Variant, got {:?}", variant_val),
96        }
97    }
98}
99
100// ============================================================================
101// Type-safe variant constructors with fixed arity
102// ============================================================================
103
104/// Create a variant with 0 fields (just a tag)
105///
106/// Stack effect: ( tag -- Variant )
107///
108/// # Safety
109/// Stack must have at least one Int (the tag) on top
110#[unsafe(no_mangle)]
111pub unsafe extern "C" fn patch_seq_make_variant_0(stack: Stack) -> Stack {
112    use crate::value::VariantData;
113
114    unsafe {
115        let (stack, tag_val) = pop(stack);
116        let tag = match tag_val {
117            Value::Int(t) => {
118                if t < 0 {
119                    panic!("make-variant-0: tag cannot be negative: {}", t);
120                }
121                t as u32
122            }
123            _ => panic!("make-variant-0: expected Int (tag), got {:?}", tag_val),
124        };
125
126        let variant = Value::Variant(Arc::new(VariantData::new(tag, vec![])));
127        push(stack, variant)
128    }
129}
130
131/// Create a variant with 1 field
132///
133/// Stack effect: ( field1 tag -- Variant )
134///
135/// # Safety
136/// Stack must have field1 and tag on top
137#[unsafe(no_mangle)]
138pub unsafe extern "C" fn patch_seq_make_variant_1(stack: Stack) -> Stack {
139    use crate::value::VariantData;
140
141    unsafe {
142        let (stack, tag_val) = pop(stack);
143        let tag = match tag_val {
144            Value::Int(t) => {
145                if t < 0 {
146                    panic!("make-variant-1: tag cannot be negative: {}", t);
147                }
148                t as u32
149            }
150            _ => panic!("make-variant-1: expected Int (tag), got {:?}", tag_val),
151        };
152
153        let (stack, field1) = pop(stack);
154        let variant = Value::Variant(Arc::new(VariantData::new(tag, vec![field1])));
155        push(stack, variant)
156    }
157}
158
159/// Create a variant with 2 fields
160///
161/// Stack effect: ( field1 field2 tag -- Variant )
162///
163/// # Safety
164/// Stack must have field1, field2, and tag on top
165#[unsafe(no_mangle)]
166pub unsafe extern "C" fn patch_seq_make_variant_2(stack: Stack) -> Stack {
167    use crate::value::VariantData;
168
169    unsafe {
170        let (stack, tag_val) = pop(stack);
171        let tag = match tag_val {
172            Value::Int(t) => {
173                if t < 0 {
174                    panic!("make-variant-2: tag cannot be negative: {}", t);
175                }
176                t as u32
177            }
178            _ => panic!("make-variant-2: expected Int (tag), got {:?}", tag_val),
179        };
180
181        let (stack, field2) = pop(stack);
182        let (stack, field1) = pop(stack);
183        let variant = Value::Variant(Arc::new(VariantData::new(tag, vec![field1, field2])));
184        push(stack, variant)
185    }
186}
187
188/// Create a variant with 3 fields
189///
190/// Stack effect: ( field1 field2 field3 tag -- Variant )
191///
192/// # Safety
193/// Stack must have field1, field2, field3, and tag on top
194#[unsafe(no_mangle)]
195pub unsafe extern "C" fn patch_seq_make_variant_3(stack: Stack) -> Stack {
196    use crate::value::VariantData;
197
198    unsafe {
199        let (stack, tag_val) = pop(stack);
200        let tag = match tag_val {
201            Value::Int(t) => {
202                if t < 0 {
203                    panic!("make-variant-3: tag cannot be negative: {}", t);
204                }
205                t as u32
206            }
207            _ => panic!("make-variant-3: expected Int (tag), got {:?}", tag_val),
208        };
209
210        let (stack, field3) = pop(stack);
211        let (stack, field2) = pop(stack);
212        let (stack, field1) = pop(stack);
213        let variant = Value::Variant(Arc::new(VariantData::new(
214            tag,
215            vec![field1, field2, field3],
216        )));
217        push(stack, variant)
218    }
219}
220
221/// Create a variant with 4 fields
222///
223/// Stack effect: ( field1 field2 field3 field4 tag -- Variant )
224///
225/// # Safety
226/// Stack must have field1, field2, field3, field4, and tag on top
227#[unsafe(no_mangle)]
228pub unsafe extern "C" fn patch_seq_make_variant_4(stack: Stack) -> Stack {
229    use crate::value::VariantData;
230
231    unsafe {
232        let (stack, tag_val) = pop(stack);
233        let tag = match tag_val {
234            Value::Int(t) => {
235                if t < 0 {
236                    panic!("make-variant-4: tag cannot be negative: {}", t);
237                }
238                t as u32
239            }
240            _ => panic!("make-variant-4: expected Int (tag), got {:?}", tag_val),
241        };
242
243        let (stack, field4) = pop(stack);
244        let (stack, field3) = pop(stack);
245        let (stack, field2) = pop(stack);
246        let (stack, field1) = pop(stack);
247        let variant = Value::Variant(Arc::new(VariantData::new(
248            tag,
249            vec![field1, field2, field3, field4],
250        )));
251        push(stack, variant)
252    }
253}
254
255// Re-exports for internal use
256pub use patch_seq_make_variant_0 as make_variant_0;
257pub use patch_seq_make_variant_1 as make_variant_1;
258pub use patch_seq_make_variant_2 as make_variant_2;
259pub use patch_seq_make_variant_3 as make_variant_3;
260pub use patch_seq_make_variant_4 as make_variant_4;
261
262/// Append a value to a variant, returning a new variant
263///
264/// Stack effect: ( Variant Value -- Variant' )
265///
266/// Creates a new variant with the same tag as the input, but with
267/// the new value appended to its fields. The original variant is
268/// not modified (functional/immutable style).
269///
270/// Example: For arrays, `[1, 2] 3 variant-append` produces `[1, 2, 3]`
271/// Example: For objects, `{} "key" variant-append "val" variant-append` builds `{"key": "val"}`
272///
273/// # Safety
274/// Stack must have a Variant and a Value on top
275#[unsafe(no_mangle)]
276pub unsafe extern "C" fn patch_seq_variant_append(stack: Stack) -> Stack {
277    use crate::value::VariantData;
278
279    unsafe {
280        // Pop the value to append
281        let (stack, value) = pop(stack);
282
283        // Pop the variant
284        let (stack, variant_val) = pop(stack);
285
286        match variant_val {
287            Value::Variant(variant_data) => {
288                // Create new fields vector with the appended value
289                let mut new_fields = variant_data.fields.to_vec();
290                new_fields.push(value);
291
292                // Create new variant with same tag
293                let new_variant =
294                    Value::Variant(Arc::new(VariantData::new(variant_data.tag, new_fields)));
295
296                push(stack, new_variant)
297            }
298            _ => panic!("variant-append: expected Variant, got {:?}", variant_val),
299        }
300    }
301}
302
303/// Get the last field from a variant
304///
305/// Stack effect: ( Variant -- Value )
306///
307/// Returns a clone of the last field. Panics if the variant has no fields.
308/// This is the "peek" operation for using variants as stacks.
309///
310/// # Safety
311/// Stack must have a Variant on top
312#[unsafe(no_mangle)]
313pub unsafe extern "C" fn patch_seq_variant_last(stack: Stack) -> Stack {
314    unsafe {
315        let (stack, variant_val) = pop(stack);
316
317        match variant_val {
318            Value::Variant(variant_data) => {
319                if variant_data.fields.is_empty() {
320                    panic!("variant-last: variant has no fields");
321                }
322
323                let last = variant_data.fields.last().unwrap().clone();
324                push(stack, last)
325            }
326            _ => panic!("variant-last: expected Variant, got {:?}", variant_val),
327        }
328    }
329}
330
331/// Get all but the last field from a variant
332///
333/// Stack effect: ( Variant -- Variant' )
334///
335/// Returns a new variant with the same tag but without the last field.
336/// Panics if the variant has no fields.
337/// This is the "pop" operation for using variants as stacks (without returning the popped value).
338///
339/// # Safety
340/// Stack must have a Variant on top
341#[unsafe(no_mangle)]
342pub unsafe extern "C" fn patch_seq_variant_init(stack: Stack) -> Stack {
343    use crate::value::VariantData;
344
345    unsafe {
346        let (stack, variant_val) = pop(stack);
347
348        match variant_val {
349            Value::Variant(variant_data) => {
350                if variant_data.fields.is_empty() {
351                    panic!("variant-init: variant has no fields");
352                }
353
354                // Create new fields without the last element
355                let new_fields: Vec<Value> =
356                    variant_data.fields[..variant_data.fields.len() - 1].to_vec();
357
358                let new_variant =
359                    Value::Variant(Arc::new(VariantData::new(variant_data.tag, new_fields)));
360
361                push(stack, new_variant)
362            }
363            _ => panic!("variant-init: expected Variant, got {:?}", variant_val),
364        }
365    }
366}
367
368/// Unpack a variant's fields onto the stack
369///
370/// Takes a field count as parameter and:
371/// - Pops the variant from the stack
372/// - Pushes each field (0..field_count) in order
373///
374/// Stack effect: ( Variant -- field0 field1 ... fieldN-1 )
375///
376/// Used by match expression codegen to extract variant fields.
377///
378/// # Safety
379/// Stack must have a Variant on top with at least `field_count` fields
380#[unsafe(no_mangle)]
381pub unsafe extern "C" fn patch_seq_unpack_variant(stack: Stack, field_count: i64) -> Stack {
382    unsafe {
383        let (mut stack, variant_val) = pop(stack);
384
385        match variant_val {
386            Value::Variant(variant_data) => {
387                let count = field_count as usize;
388                if count > variant_data.fields.len() {
389                    panic!(
390                        "unpack-variant: requested {} fields but variant only has {}",
391                        count,
392                        variant_data.fields.len()
393                    );
394                }
395
396                // Push each field in order (field0 first, then field1, etc.)
397                for i in 0..count {
398                    stack = push(stack, variant_data.fields[i].clone());
399                }
400
401                stack
402            }
403            _ => panic!("unpack-variant: expected Variant, got {:?}", variant_val),
404        }
405    }
406}
407
408// Public re-exports with short names for internal use
409pub use patch_seq_unpack_variant as unpack_variant;
410pub use patch_seq_variant_append as variant_append;
411pub use patch_seq_variant_field_at as variant_field_at;
412pub use patch_seq_variant_field_count as variant_field_count;
413pub use patch_seq_variant_init as variant_init;
414pub use patch_seq_variant_last as variant_last;
415pub use patch_seq_variant_tag as variant_tag;
416
417#[cfg(test)]
418mod tests {
419    use super::*;
420    use crate::seqstring::global_string;
421    use crate::value::VariantData;
422
423    #[test]
424    fn test_variant_field_count() {
425        unsafe {
426            // Create a variant with 3 fields
427            let variant = Value::Variant(Arc::new(VariantData::new(
428                0,
429                vec![Value::Int(10), Value::Int(20), Value::Int(30)],
430            )));
431
432            let stack = crate::stack::alloc_test_stack();
433            let stack = push(stack, variant);
434            let stack = variant_field_count(stack);
435
436            let (_stack, result) = pop(stack);
437            assert_eq!(result, Value::Int(3));
438        }
439    }
440
441    #[test]
442    fn test_variant_tag() {
443        unsafe {
444            // Create a variant with tag 42
445            let variant = Value::Variant(Arc::new(VariantData::new(42, vec![Value::Int(10)])));
446
447            let stack = crate::stack::alloc_test_stack();
448            let stack = push(stack, variant);
449            let stack = variant_tag(stack);
450
451            let (_stack, result) = pop(stack);
452            assert_eq!(result, Value::Int(42));
453        }
454    }
455
456    #[test]
457    fn test_variant_field_at() {
458        unsafe {
459            let str1 = global_string("hello".to_string());
460            let str2 = global_string("world".to_string());
461
462            // Create a variant with mixed fields
463            let variant = Value::Variant(Arc::new(VariantData::new(
464                0,
465                vec![
466                    Value::String(str1.clone()),
467                    Value::Int(42),
468                    Value::String(str2.clone()),
469                ],
470            )));
471
472            // Test accessing field 0
473            let stack = crate::stack::alloc_test_stack();
474            let stack = push(stack, variant.clone());
475            let stack = push(stack, Value::Int(0));
476            let stack = variant_field_at(stack);
477
478            let (_stack, result) = pop(stack);
479            assert_eq!(result, Value::String(str1.clone()));
480
481            // Test accessing field 1
482            let stack = push(stack, variant.clone());
483            let stack = push(stack, Value::Int(1));
484            let stack = variant_field_at(stack);
485
486            let (_stack, result) = pop(stack);
487            assert_eq!(result, Value::Int(42));
488
489            // Test accessing field 2
490            let stack = push(stack, variant.clone());
491            let stack = push(stack, Value::Int(2));
492            let stack = variant_field_at(stack);
493
494            let (_stack, result) = pop(stack);
495            assert_eq!(result, Value::String(str2));
496        }
497    }
498
499    #[test]
500    fn test_variant_field_count_empty() {
501        unsafe {
502            // Create a variant with no fields
503            let variant = Value::Variant(Arc::new(VariantData::new(0, vec![])));
504
505            let stack = crate::stack::alloc_test_stack();
506            let stack = push(stack, variant);
507            let stack = variant_field_count(stack);
508
509            let (_stack, result) = pop(stack);
510            assert_eq!(result, Value::Int(0));
511        }
512    }
513
514    #[test]
515    fn test_make_variant_with_fields() {
516        unsafe {
517            // Create: 10 20 30 42 make-variant-3
518            // Should produce variant with tag 42 and fields [10, 20, 30]
519            let stack = crate::stack::alloc_test_stack();
520            let stack = push(stack, Value::Int(10)); // field 0
521            let stack = push(stack, Value::Int(20)); // field 1
522            let stack = push(stack, Value::Int(30)); // field 2
523            let stack = push(stack, Value::Int(42)); // tag
524
525            let stack = make_variant_3(stack);
526
527            let (_stack, result) = pop(stack);
528
529            match result {
530                Value::Variant(v) => {
531                    assert_eq!(v.tag, 42);
532                    assert_eq!(v.fields.len(), 3);
533                    assert_eq!(v.fields[0], Value::Int(10));
534                    assert_eq!(v.fields[1], Value::Int(20));
535                    assert_eq!(v.fields[2], Value::Int(30));
536                }
537                _ => panic!("Expected Variant"),
538            }
539        }
540    }
541
542    #[test]
543    fn test_make_variant_empty() {
544        unsafe {
545            // Create: 0 make-variant-0
546            // Should produce variant with tag 0 and no fields
547            let stack = crate::stack::alloc_test_stack();
548            let stack = push(stack, Value::Int(0)); // tag
549
550            let stack = make_variant_0(stack);
551
552            let (_stack, result) = pop(stack);
553
554            match result {
555                Value::Variant(v) => {
556                    assert_eq!(v.tag, 0);
557                    assert_eq!(v.fields.len(), 0);
558                }
559                _ => panic!("Expected Variant"),
560            }
561        }
562    }
563
564    #[test]
565    fn test_make_variant_with_mixed_types() {
566        unsafe {
567            let s = global_string("hello".to_string());
568
569            // Create variant with mixed field types using make-variant-3
570            let stack = crate::stack::alloc_test_stack();
571            let stack = push(stack, Value::Int(42));
572            let stack = push(stack, Value::String(s.clone()));
573            let stack = push(stack, Value::Float(3.5));
574            let stack = push(stack, Value::Int(1)); // tag
575
576            let stack = make_variant_3(stack);
577
578            let (_stack, result) = pop(stack);
579
580            match result {
581                Value::Variant(v) => {
582                    assert_eq!(v.tag, 1);
583                    assert_eq!(v.fields.len(), 3);
584                    assert_eq!(v.fields[0], Value::Int(42));
585                    assert_eq!(v.fields[1], Value::String(s));
586                    assert_eq!(v.fields[2], Value::Float(3.5));
587                }
588                _ => panic!("Expected Variant"),
589            }
590        }
591    }
592
593    #[test]
594    fn test_variant_append() {
595        unsafe {
596            // Create an empty variant (tag 4 for array)
597            let stack = crate::stack::alloc_test_stack();
598            let stack = push(stack, Value::Int(4)); // tag (array)
599            let stack = make_variant_0(stack);
600
601            // Append a value
602            let stack = push(stack, Value::Int(42));
603            let stack = variant_append(stack);
604
605            // Check result
606            let (_stack, result) = pop(stack);
607            match result {
608                Value::Variant(v) => {
609                    assert_eq!(v.tag, 4);
610                    assert_eq!(v.fields.len(), 1);
611                    assert_eq!(v.fields[0], Value::Int(42));
612                }
613                _ => panic!("Expected Variant"),
614            }
615        }
616    }
617
618    #[test]
619    fn test_variant_append_multiple() {
620        unsafe {
621            // Create an empty variant (tag 5 for object)
622            let stack = crate::stack::alloc_test_stack();
623            let stack = push(stack, Value::Int(5)); // tag (object)
624            let stack = make_variant_0(stack);
625
626            // Append key
627            let key = global_string("name".to_string());
628            let stack = push(stack, Value::String(key.clone()));
629            let stack = variant_append(stack);
630
631            // Append value
632            let val = global_string("John".to_string());
633            let stack = push(stack, Value::String(val.clone()));
634            let stack = variant_append(stack);
635
636            // Check result - should have 2 fields
637            let (_stack, result) = pop(stack);
638            match result {
639                Value::Variant(v) => {
640                    assert_eq!(v.tag, 5);
641                    assert_eq!(v.fields.len(), 2);
642                    assert_eq!(v.fields[0], Value::String(key));
643                    assert_eq!(v.fields[1], Value::String(val));
644                }
645                _ => panic!("Expected Variant"),
646            }
647        }
648    }
649
650    #[test]
651    fn test_variant_last() {
652        unsafe {
653            // Create a variant with 3 fields
654            let variant = Value::Variant(Arc::new(VariantData::new(
655                0,
656                vec![Value::Int(10), Value::Int(20), Value::Int(30)],
657            )));
658
659            let stack = crate::stack::alloc_test_stack();
660            let stack = push(stack, variant);
661            let stack = variant_last(stack);
662
663            let (_stack, result) = pop(stack);
664            assert_eq!(result, Value::Int(30));
665        }
666    }
667
668    #[test]
669    fn test_variant_init() {
670        unsafe {
671            // Create a variant with 3 fields
672            let variant = Value::Variant(Arc::new(VariantData::new(
673                42,
674                vec![Value::Int(10), Value::Int(20), Value::Int(30)],
675            )));
676
677            let stack = crate::stack::alloc_test_stack();
678            let stack = push(stack, variant);
679            let stack = variant_init(stack);
680
681            let (_stack, result) = pop(stack);
682            match result {
683                Value::Variant(v) => {
684                    assert_eq!(v.tag, 42); // tag preserved
685                    assert_eq!(v.fields.len(), 2);
686                    assert_eq!(v.fields[0], Value::Int(10));
687                    assert_eq!(v.fields[1], Value::Int(20));
688                }
689                _ => panic!("Expected Variant"),
690            }
691        }
692    }
693
694    #[test]
695    fn test_variant_stack_operations() {
696        // Test using variant as a stack: append, append, last, init, last
697        unsafe {
698            // Create empty "stack" variant (tag 99)
699            let stack = crate::stack::alloc_test_stack();
700            let stack = push(stack, Value::Int(99)); // tag
701            let stack = make_variant_0(stack);
702
703            // Append 10
704            let stack = push(stack, Value::Int(10));
705            let stack = variant_append(stack);
706
707            // Append 20
708            let stack = push(stack, Value::Int(20));
709            let stack = variant_append(stack);
710
711            // Now have variant with [10, 20] on stack
712            // Dup and get last (should be 20)
713            let (stack, variant) = pop(stack);
714            let stack = push(stack, variant.clone());
715            let stack = push(stack, variant);
716            let stack = variant_last(stack);
717            let (stack, top) = pop(stack);
718            assert_eq!(top, Value::Int(20));
719
720            // Now use init to remove last element
721            let stack = variant_init(stack);
722
723            // Dup and get last (should now be 10)
724            let (stack, variant) = pop(stack);
725            let stack = push(stack, variant.clone());
726            let stack = push(stack, variant);
727            let stack = variant_last(stack);
728            let (stack, top) = pop(stack);
729            assert_eq!(top, Value::Int(10));
730
731            // Verify remaining variant has 1 field
732            let (_stack, result) = pop(stack);
733            match result {
734                Value::Variant(v) => {
735                    assert_eq!(v.fields.len(), 1);
736                    assert_eq!(v.fields[0], Value::Int(10));
737                }
738                _ => panic!("Expected Variant"),
739            }
740        }
741    }
742
743    #[test]
744    fn test_variant_clone_is_o1() {
745        // Regression test: Ensure deeply nested variants clone in O(1) time
746        // This would have been O(2^n) with Box before the Arc change
747        let mut variant = Value::Variant(Arc::new(VariantData::new(0, vec![])));
748
749        // Build a deeply nested structure (100 levels)
750        for i in 0..100 {
751            variant = Value::Variant(Arc::new(VariantData::new(i, vec![variant.clone()])));
752        }
753
754        // Clone should be O(1) - just incrementing Arc refcount
755        let start = std::time::Instant::now();
756        for _ in 0..1000 {
757            let _copy = variant.clone();
758        }
759        let elapsed = start.elapsed();
760
761        // 1000 clones of a 100-deep structure should take < 1ms with Arc
762        // With Box it would take seconds or longer
763        assert!(
764            elapsed.as_millis() < 10,
765            "Clone took {:?} - should be O(1) with Arc",
766            elapsed
767        );
768    }
769
770    #[test]
771    fn test_variant_arc_sharing() {
772        // Test that Arc properly shares data (refcount increases, not deep copy)
773        let inner = Value::Variant(Arc::new(VariantData::new(0, vec![Value::Int(42)])));
774        let outer = Value::Variant(Arc::new(VariantData::new(1, vec![inner.clone()])));
775
776        // Clone should share the same Arc, not deep copy
777        let outer_clone = outer.clone();
778
779        // Both should have the same inner value
780        match (&outer, &outer_clone) {
781            (Value::Variant(a), Value::Variant(b)) => {
782                // Arc::ptr_eq would be ideal but fields are Box<[Value]>
783                // Instead verify the values are equal (they share the same data)
784                assert_eq!(a.tag, b.tag);
785                assert_eq!(a.fields.len(), b.fields.len());
786            }
787            _ => panic!("Expected Variants"),
788        }
789    }
790
791    #[test]
792    fn test_variant_thread_safe_sharing() {
793        // Test that variants can be safely shared between threads
794        // This validates the Send + Sync implementation
795        use std::sync::Arc as StdArc;
796        use std::thread;
797
798        let variant = Value::Variant(Arc::new(VariantData::new(
799            42,
800            vec![Value::Int(1), Value::Int(2), Value::Int(3)],
801        )));
802
803        // Wrap in Arc for thread sharing
804        let shared = StdArc::new(variant);
805
806        let handles: Vec<_> = (0..4)
807            .map(|_| {
808                let v = StdArc::clone(&shared);
809                thread::spawn(move || {
810                    // Access the variant from another thread
811                    match &*v {
812                        Value::Variant(data) => {
813                            assert_eq!(data.tag, 42);
814                            assert_eq!(data.fields.len(), 3);
815                        }
816                        _ => panic!("Expected Variant"),
817                    }
818                })
819            })
820            .collect();
821
822        for h in handles {
823            h.join().expect("Thread panicked");
824        }
825    }
826}