1use crate::stack::{Stack, pop, push};
7use crate::value::Value;
8use std::sync::Arc;
9
10#[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#[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#[unsafe(no_mangle)]
62pub unsafe extern "C" fn patch_seq_variant_field_at(stack: Stack) -> Stack {
63 unsafe {
64 let (stack, index_val) = pop(stack);
65 let index = match index_val {
66 Value::Int(i) => i,
67 _ => panic!(
68 "variant-field-at: expected Int (index), got {:?}",
69 index_val
70 ),
71 };
72
73 if index < 0 {
74 panic!("variant-field-at: index cannot be negative: {}", index);
75 }
76
77 let (stack, variant_val) = pop(stack);
78
79 match variant_val {
80 Value::Variant(variant_data) => {
81 let idx = index as usize;
82 if idx >= variant_data.fields.len() {
83 panic!(
84 "variant-field-at: index {} out of bounds (variant has {} fields)",
85 index,
86 variant_data.fields.len()
87 );
88 }
89
90 let field = variant_data.fields[idx].clone();
92 push(stack, field)
93 }
94 _ => panic!("variant-field-at: expected Variant, got {:?}", variant_val),
95 }
96 }
97}
98
99#[unsafe(no_mangle)]
110pub unsafe extern "C" fn patch_seq_make_variant_0(stack: Stack) -> Stack {
111 use crate::value::VariantData;
112
113 unsafe {
114 let (stack, tag_val) = pop(stack);
115 let tag = match tag_val {
116 Value::Int(t) => {
117 if t < 0 {
118 panic!("make-variant-0: tag cannot be negative: {}", t);
119 }
120 t as u32
121 }
122 _ => panic!("make-variant-0: expected Int (tag), got {:?}", tag_val),
123 };
124
125 let variant = Value::Variant(Arc::new(VariantData::new(tag, vec![])));
126 push(stack, variant)
127 }
128}
129
130#[unsafe(no_mangle)]
137pub unsafe extern "C" fn patch_seq_make_variant_1(stack: Stack) -> Stack {
138 use crate::value::VariantData;
139
140 unsafe {
141 let (stack, tag_val) = pop(stack);
142 let tag = match tag_val {
143 Value::Int(t) => {
144 if t < 0 {
145 panic!("make-variant-1: tag cannot be negative: {}", t);
146 }
147 t as u32
148 }
149 _ => panic!("make-variant-1: expected Int (tag), got {:?}", tag_val),
150 };
151
152 let (stack, field1) = pop(stack);
153 let variant = Value::Variant(Arc::new(VariantData::new(tag, vec![field1])));
154 push(stack, variant)
155 }
156}
157
158#[unsafe(no_mangle)]
165pub unsafe extern "C" fn patch_seq_make_variant_2(stack: Stack) -> Stack {
166 use crate::value::VariantData;
167
168 unsafe {
169 let (stack, tag_val) = pop(stack);
170 let tag = match tag_val {
171 Value::Int(t) => {
172 if t < 0 {
173 panic!("make-variant-2: tag cannot be negative: {}", t);
174 }
175 t as u32
176 }
177 _ => panic!("make-variant-2: expected Int (tag), got {:?}", tag_val),
178 };
179
180 let (stack, field2) = pop(stack);
181 let (stack, field1) = pop(stack);
182 let variant = Value::Variant(Arc::new(VariantData::new(tag, vec![field1, field2])));
183 push(stack, variant)
184 }
185}
186
187#[unsafe(no_mangle)]
194pub unsafe extern "C" fn patch_seq_make_variant_3(stack: Stack) -> Stack {
195 use crate::value::VariantData;
196
197 unsafe {
198 let (stack, tag_val) = pop(stack);
199 let tag = match tag_val {
200 Value::Int(t) => {
201 if t < 0 {
202 panic!("make-variant-3: tag cannot be negative: {}", t);
203 }
204 t as u32
205 }
206 _ => panic!("make-variant-3: expected Int (tag), got {:?}", tag_val),
207 };
208
209 let (stack, field3) = pop(stack);
210 let (stack, field2) = pop(stack);
211 let (stack, field1) = pop(stack);
212 let variant = Value::Variant(Arc::new(VariantData::new(
213 tag,
214 vec![field1, field2, field3],
215 )));
216 push(stack, variant)
217 }
218}
219
220#[unsafe(no_mangle)]
227pub unsafe extern "C" fn patch_seq_make_variant_4(stack: Stack) -> Stack {
228 use crate::value::VariantData;
229
230 unsafe {
231 let (stack, tag_val) = pop(stack);
232 let tag = match tag_val {
233 Value::Int(t) => {
234 if t < 0 {
235 panic!("make-variant-4: tag cannot be negative: {}", t);
236 }
237 t as u32
238 }
239 _ => panic!("make-variant-4: expected Int (tag), got {:?}", tag_val),
240 };
241
242 let (stack, field4) = pop(stack);
243 let (stack, field3) = pop(stack);
244 let (stack, field2) = pop(stack);
245 let (stack, field1) = pop(stack);
246 let variant = Value::Variant(Arc::new(VariantData::new(
247 tag,
248 vec![field1, field2, field3, field4],
249 )));
250 push(stack, variant)
251 }
252}
253
254pub use patch_seq_make_variant_0 as make_variant_0;
256pub use patch_seq_make_variant_1 as make_variant_1;
257pub use patch_seq_make_variant_2 as make_variant_2;
258pub use patch_seq_make_variant_3 as make_variant_3;
259pub use patch_seq_make_variant_4 as make_variant_4;
260
261#[unsafe(no_mangle)]
275pub unsafe extern "C" fn patch_seq_variant_append(stack: Stack) -> Stack {
276 use crate::value::VariantData;
277
278 unsafe {
279 let (stack, value) = pop(stack);
281
282 let (stack, variant_val) = pop(stack);
284
285 match variant_val {
286 Value::Variant(variant_data) => {
287 let mut new_fields = variant_data.fields.to_vec();
289 new_fields.push(value);
290
291 let new_variant =
293 Value::Variant(Arc::new(VariantData::new(variant_data.tag, new_fields)));
294
295 push(stack, new_variant)
296 }
297 _ => panic!("variant-append: expected Variant, got {:?}", variant_val),
298 }
299 }
300}
301
302#[unsafe(no_mangle)]
312pub unsafe extern "C" fn patch_seq_variant_last(stack: Stack) -> Stack {
313 unsafe {
314 let (stack, variant_val) = pop(stack);
315
316 match variant_val {
317 Value::Variant(variant_data) => {
318 if variant_data.fields.is_empty() {
319 panic!("variant-last: variant has no fields");
320 }
321
322 let last = variant_data.fields.last().unwrap().clone();
323 push(stack, last)
324 }
325 _ => panic!("variant-last: expected Variant, got {:?}", variant_val),
326 }
327 }
328}
329
330#[unsafe(no_mangle)]
341pub unsafe extern "C" fn patch_seq_variant_init(stack: Stack) -> Stack {
342 use crate::value::VariantData;
343
344 unsafe {
345 let (stack, variant_val) = pop(stack);
346
347 match variant_val {
348 Value::Variant(variant_data) => {
349 if variant_data.fields.is_empty() {
350 panic!("variant-init: variant has no fields");
351 }
352
353 let new_fields: Vec<Value> =
355 variant_data.fields[..variant_data.fields.len() - 1].to_vec();
356
357 let new_variant =
358 Value::Variant(Arc::new(VariantData::new(variant_data.tag, new_fields)));
359
360 push(stack, new_variant)
361 }
362 _ => panic!("variant-init: expected Variant, got {:?}", variant_val),
363 }
364 }
365}
366
367#[unsafe(no_mangle)]
380pub unsafe extern "C" fn patch_seq_unpack_variant(stack: Stack, field_count: i64) -> Stack {
381 unsafe {
382 let (mut stack, variant_val) = pop(stack);
383
384 match variant_val {
385 Value::Variant(variant_data) => {
386 let count = field_count as usize;
387 if count > variant_data.fields.len() {
388 panic!(
389 "unpack-variant: requested {} fields but variant only has {}",
390 count,
391 variant_data.fields.len()
392 );
393 }
394
395 for i in 0..count {
397 stack = push(stack, variant_data.fields[i].clone());
398 }
399
400 stack
401 }
402 _ => panic!("unpack-variant: expected Variant, got {:?}", variant_val),
403 }
404 }
405}
406
407pub use patch_seq_unpack_variant as unpack_variant;
409pub use patch_seq_variant_append as variant_append;
410pub use patch_seq_variant_field_at as variant_field_at;
411pub use patch_seq_variant_field_count as variant_field_count;
412pub use patch_seq_variant_init as variant_init;
413pub use patch_seq_variant_last as variant_last;
414pub use patch_seq_variant_tag as variant_tag;
415
416#[cfg(test)]
417mod tests {
418 use super::*;
419 use crate::seqstring::global_string;
420 use crate::value::VariantData;
421
422 #[test]
423 fn test_variant_field_count() {
424 unsafe {
425 let variant = Value::Variant(Arc::new(VariantData::new(
427 0,
428 vec![Value::Int(10), Value::Int(20), Value::Int(30)],
429 )));
430
431 let stack = crate::stack::alloc_test_stack();
432 let stack = push(stack, variant);
433 let stack = variant_field_count(stack);
434
435 let (_stack, result) = pop(stack);
436 assert_eq!(result, Value::Int(3));
437 }
438 }
439
440 #[test]
441 fn test_variant_tag() {
442 unsafe {
443 let variant = Value::Variant(Arc::new(VariantData::new(42, vec![Value::Int(10)])));
445
446 let stack = crate::stack::alloc_test_stack();
447 let stack = push(stack, variant);
448 let stack = variant_tag(stack);
449
450 let (_stack, result) = pop(stack);
451 assert_eq!(result, Value::Int(42));
452 }
453 }
454
455 #[test]
456 fn test_variant_field_at() {
457 unsafe {
458 let str1 = global_string("hello".to_string());
459 let str2 = global_string("world".to_string());
460
461 let variant = Value::Variant(Arc::new(VariantData::new(
463 0,
464 vec![
465 Value::String(str1.clone()),
466 Value::Int(42),
467 Value::String(str2.clone()),
468 ],
469 )));
470
471 let stack = crate::stack::alloc_test_stack();
473 let stack = push(stack, variant.clone());
474 let stack = push(stack, Value::Int(0));
475 let stack = variant_field_at(stack);
476
477 let (_stack, result) = pop(stack);
478 assert_eq!(result, Value::String(str1.clone()));
479
480 let stack = push(stack, variant.clone());
482 let stack = push(stack, Value::Int(1));
483 let stack = variant_field_at(stack);
484
485 let (_stack, result) = pop(stack);
486 assert_eq!(result, Value::Int(42));
487
488 let stack = push(stack, variant.clone());
490 let stack = push(stack, Value::Int(2));
491 let stack = variant_field_at(stack);
492
493 let (_stack, result) = pop(stack);
494 assert_eq!(result, Value::String(str2));
495 }
496 }
497
498 #[test]
499 fn test_variant_field_count_empty() {
500 unsafe {
501 let variant = Value::Variant(Arc::new(VariantData::new(0, vec![])));
503
504 let stack = crate::stack::alloc_test_stack();
505 let stack = push(stack, variant);
506 let stack = variant_field_count(stack);
507
508 let (_stack, result) = pop(stack);
509 assert_eq!(result, Value::Int(0));
510 }
511 }
512
513 #[test]
514 fn test_make_variant_with_fields() {
515 unsafe {
516 let stack = crate::stack::alloc_test_stack();
519 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::Int(42)); let stack = make_variant_3(stack);
525
526 let (_stack, result) = pop(stack);
527
528 match result {
529 Value::Variant(v) => {
530 assert_eq!(v.tag, 42);
531 assert_eq!(v.fields.len(), 3);
532 assert_eq!(v.fields[0], Value::Int(10));
533 assert_eq!(v.fields[1], Value::Int(20));
534 assert_eq!(v.fields[2], Value::Int(30));
535 }
536 _ => panic!("Expected Variant"),
537 }
538 }
539 }
540
541 #[test]
542 fn test_make_variant_empty() {
543 unsafe {
544 let stack = crate::stack::alloc_test_stack();
547 let stack = push(stack, Value::Int(0)); let stack = make_variant_0(stack);
550
551 let (_stack, result) = pop(stack);
552
553 match result {
554 Value::Variant(v) => {
555 assert_eq!(v.tag, 0);
556 assert_eq!(v.fields.len(), 0);
557 }
558 _ => panic!("Expected Variant"),
559 }
560 }
561 }
562
563 #[test]
564 fn test_make_variant_with_mixed_types() {
565 unsafe {
566 let s = global_string("hello".to_string());
567
568 let stack = crate::stack::alloc_test_stack();
570 let stack = push(stack, Value::Int(42));
571 let stack = push(stack, Value::String(s.clone()));
572 let stack = push(stack, Value::Float(3.5));
573 let stack = push(stack, Value::Int(1)); let stack = make_variant_3(stack);
576
577 let (_stack, result) = pop(stack);
578
579 match result {
580 Value::Variant(v) => {
581 assert_eq!(v.tag, 1);
582 assert_eq!(v.fields.len(), 3);
583 assert_eq!(v.fields[0], Value::Int(42));
584 assert_eq!(v.fields[1], Value::String(s));
585 assert_eq!(v.fields[2], Value::Float(3.5));
586 }
587 _ => panic!("Expected Variant"),
588 }
589 }
590 }
591
592 #[test]
593 fn test_variant_append() {
594 unsafe {
595 let stack = crate::stack::alloc_test_stack();
597 let stack = push(stack, Value::Int(4)); let stack = make_variant_0(stack);
599
600 let stack = push(stack, Value::Int(42));
602 let stack = variant_append(stack);
603
604 let (_stack, result) = pop(stack);
606 match result {
607 Value::Variant(v) => {
608 assert_eq!(v.tag, 4);
609 assert_eq!(v.fields.len(), 1);
610 assert_eq!(v.fields[0], Value::Int(42));
611 }
612 _ => panic!("Expected Variant"),
613 }
614 }
615 }
616
617 #[test]
618 fn test_variant_append_multiple() {
619 unsafe {
620 let stack = crate::stack::alloc_test_stack();
622 let stack = push(stack, Value::Int(5)); let stack = make_variant_0(stack);
624
625 let key = global_string("name".to_string());
627 let stack = push(stack, Value::String(key.clone()));
628 let stack = variant_append(stack);
629
630 let val = global_string("John".to_string());
632 let stack = push(stack, Value::String(val.clone()));
633 let stack = variant_append(stack);
634
635 let (_stack, result) = pop(stack);
637 match result {
638 Value::Variant(v) => {
639 assert_eq!(v.tag, 5);
640 assert_eq!(v.fields.len(), 2);
641 assert_eq!(v.fields[0], Value::String(key));
642 assert_eq!(v.fields[1], Value::String(val));
643 }
644 _ => panic!("Expected Variant"),
645 }
646 }
647 }
648
649 #[test]
650 fn test_variant_last() {
651 unsafe {
652 let variant = Value::Variant(Arc::new(VariantData::new(
654 0,
655 vec![Value::Int(10), Value::Int(20), Value::Int(30)],
656 )));
657
658 let stack = crate::stack::alloc_test_stack();
659 let stack = push(stack, variant);
660 let stack = variant_last(stack);
661
662 let (_stack, result) = pop(stack);
663 assert_eq!(result, Value::Int(30));
664 }
665 }
666
667 #[test]
668 fn test_variant_init() {
669 unsafe {
670 let variant = Value::Variant(Arc::new(VariantData::new(
672 42,
673 vec![Value::Int(10), Value::Int(20), Value::Int(30)],
674 )));
675
676 let stack = crate::stack::alloc_test_stack();
677 let stack = push(stack, variant);
678 let stack = variant_init(stack);
679
680 let (_stack, result) = pop(stack);
681 match result {
682 Value::Variant(v) => {
683 assert_eq!(v.tag, 42); assert_eq!(v.fields.len(), 2);
685 assert_eq!(v.fields[0], Value::Int(10));
686 assert_eq!(v.fields[1], Value::Int(20));
687 }
688 _ => panic!("Expected Variant"),
689 }
690 }
691 }
692
693 #[test]
694 fn test_variant_stack_operations() {
695 unsafe {
697 let stack = crate::stack::alloc_test_stack();
699 let stack = push(stack, Value::Int(99)); let stack = make_variant_0(stack);
701
702 let stack = push(stack, Value::Int(10));
704 let stack = variant_append(stack);
705
706 let stack = push(stack, Value::Int(20));
708 let stack = variant_append(stack);
709
710 let (stack, variant) = pop(stack);
713 let stack = push(stack, variant.clone());
714 let stack = push(stack, variant);
715 let stack = variant_last(stack);
716 let (stack, top) = pop(stack);
717 assert_eq!(top, Value::Int(20));
718
719 let stack = variant_init(stack);
721
722 let (stack, variant) = pop(stack);
724 let stack = push(stack, variant.clone());
725 let stack = push(stack, variant);
726 let stack = variant_last(stack);
727 let (stack, top) = pop(stack);
728 assert_eq!(top, Value::Int(10));
729
730 let (_stack, result) = pop(stack);
732 match result {
733 Value::Variant(v) => {
734 assert_eq!(v.fields.len(), 1);
735 assert_eq!(v.fields[0], Value::Int(10));
736 }
737 _ => panic!("Expected Variant"),
738 }
739 }
740 }
741
742 #[test]
743 fn test_variant_clone_is_o1() {
744 let mut variant = Value::Variant(Arc::new(VariantData::new(0, vec![])));
747
748 for i in 0..100 {
750 variant = Value::Variant(Arc::new(VariantData::new(i, vec![variant.clone()])));
751 }
752
753 let start = std::time::Instant::now();
755 for _ in 0..1000 {
756 let _copy = variant.clone();
757 }
758 let elapsed = start.elapsed();
759
760 assert!(
763 elapsed.as_millis() < 10,
764 "Clone took {:?} - should be O(1) with Arc",
765 elapsed
766 );
767 }
768
769 #[test]
770 fn test_variant_arc_sharing() {
771 let inner = Value::Variant(Arc::new(VariantData::new(0, vec![Value::Int(42)])));
773 let outer = Value::Variant(Arc::new(VariantData::new(1, vec![inner.clone()])));
774
775 let outer_clone = outer.clone();
777
778 match (&outer, &outer_clone) {
780 (Value::Variant(a), Value::Variant(b)) => {
781 assert_eq!(a.tag, b.tag);
784 assert_eq!(a.fields.len(), b.fields.len());
785 }
786 _ => panic!("Expected Variants"),
787 }
788 }
789
790 #[test]
791 fn test_variant_thread_safe_sharing() {
792 use std::sync::Arc as StdArc;
795 use std::thread;
796
797 let variant = Value::Variant(Arc::new(VariantData::new(
798 42,
799 vec![Value::Int(1), Value::Int(2), Value::Int(3)],
800 )));
801
802 let shared = StdArc::new(variant);
804
805 let handles: Vec<_> = (0..4)
806 .map(|_| {
807 let v = StdArc::clone(&shared);
808 thread::spawn(move || {
809 match &*v {
811 Value::Variant(data) => {
812 assert_eq!(data.tag, 42);
813 assert_eq!(data.fields.len(), 3);
814 }
815 _ => panic!("Expected Variant"),
816 }
817 })
818 })
819 .collect();
820
821 for h in handles {
822 h.join().expect("Thread panicked");
823 }
824 }
825}