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 push(stack, Value::Symbol(variant_data.tag.clone()))
46 }
47 _ => panic!("variant-tag: expected Variant, got {:?}", value),
48 }
49 }
50}
51
52#[unsafe(no_mangle)]
64pub unsafe extern "C" fn patch_seq_symbol_eq_cstr(stack: Stack, c_str: *const i8) -> Stack {
65 use std::ffi::CStr;
66
67 unsafe {
68 let (stack, value) = pop(stack);
69 let symbol_str = match value {
70 Value::Symbol(s) => s,
71 _ => panic!("symbol_eq_cstr: expected Symbol, got {:?}", value),
72 };
73
74 let expected = CStr::from_ptr(c_str)
75 .to_str()
76 .expect("Invalid UTF-8 in variant name");
77
78 let is_equal = symbol_str.as_str() == expected;
79 push(stack, Value::Bool(is_equal))
80 }
81}
82
83#[unsafe(no_mangle)]
94pub unsafe extern "C" fn patch_seq_variant_field_at(stack: Stack) -> Stack {
95 unsafe {
96 let (stack, index_val) = pop(stack);
97 let index = match index_val {
98 Value::Int(i) => i,
99 _ => panic!(
100 "variant-field-at: expected Int (index), got {:?}",
101 index_val
102 ),
103 };
104
105 if index < 0 {
106 panic!("variant-field-at: index cannot be negative: {}", index);
107 }
108
109 let (stack, variant_val) = pop(stack);
110
111 match variant_val {
112 Value::Variant(variant_data) => {
113 let idx = index as usize;
114 if idx >= variant_data.fields.len() {
115 panic!(
116 "variant-field-at: index {} out of bounds (variant has {} fields)",
117 index,
118 variant_data.fields.len()
119 );
120 }
121
122 let field = variant_data.fields[idx].clone();
124 push(stack, field)
125 }
126 _ => panic!("variant-field-at: expected Variant, got {:?}", variant_val),
127 }
128 }
129}
130
131#[unsafe(no_mangle)]
143pub unsafe extern "C" fn patch_seq_make_variant_0(stack: Stack) -> Stack {
144 use crate::value::VariantData;
145
146 unsafe {
147 let (stack, tag_val) = pop(stack);
148 let tag = match tag_val {
149 Value::Symbol(s) => s,
150 _ => panic!("make-variant-0: expected Symbol (tag), got {:?}", tag_val),
151 };
152
153 let variant = Value::Variant(Arc::new(VariantData::new(tag, vec![])));
154 push(stack, variant)
155 }
156}
157
158#[unsafe(no_mangle)]
165pub unsafe extern "C" fn patch_seq_make_variant_1(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::Symbol(s) => s,
172 _ => panic!("make-variant-1: expected Symbol (tag), got {:?}", tag_val),
173 };
174
175 let (stack, field1) = pop(stack);
176 let variant = Value::Variant(Arc::new(VariantData::new(tag, vec![field1])));
177 push(stack, variant)
178 }
179}
180
181#[unsafe(no_mangle)]
188pub unsafe extern "C" fn patch_seq_make_variant_2(stack: Stack) -> Stack {
189 use crate::value::VariantData;
190
191 unsafe {
192 let (stack, tag_val) = pop(stack);
193 let tag = match tag_val {
194 Value::Symbol(s) => s,
195 _ => panic!("make-variant-2: expected Symbol (tag), got {:?}", tag_val),
196 };
197
198 let (stack, field2) = pop(stack);
199 let (stack, field1) = pop(stack);
200 let variant = Value::Variant(Arc::new(VariantData::new(tag, vec![field1, field2])));
201 push(stack, variant)
202 }
203}
204
205#[unsafe(no_mangle)]
212pub unsafe extern "C" fn patch_seq_make_variant_3(stack: Stack) -> Stack {
213 use crate::value::VariantData;
214
215 unsafe {
216 let (stack, tag_val) = pop(stack);
217 let tag = match tag_val {
218 Value::Symbol(s) => s,
219 _ => panic!("make-variant-3: expected Symbol (tag), got {:?}", tag_val),
220 };
221
222 let (stack, field3) = pop(stack);
223 let (stack, field2) = pop(stack);
224 let (stack, field1) = pop(stack);
225 let variant = Value::Variant(Arc::new(VariantData::new(
226 tag,
227 vec![field1, field2, field3],
228 )));
229 push(stack, variant)
230 }
231}
232
233#[unsafe(no_mangle)]
240pub unsafe extern "C" fn patch_seq_make_variant_4(stack: Stack) -> Stack {
241 use crate::value::VariantData;
242
243 unsafe {
244 let (stack, tag_val) = pop(stack);
245 let tag = match tag_val {
246 Value::Symbol(s) => s,
247 _ => panic!("make-variant-4: expected Symbol (tag), got {:?}", tag_val),
248 };
249
250 let (stack, field4) = pop(stack);
251 let (stack, field3) = pop(stack);
252 let (stack, field2) = pop(stack);
253 let (stack, field1) = pop(stack);
254 let variant = Value::Variant(Arc::new(VariantData::new(
255 tag,
256 vec![field1, field2, field3, field4],
257 )));
258 push(stack, variant)
259 }
260}
261
262pub use patch_seq_make_variant_0 as make_variant_0;
264pub use patch_seq_make_variant_1 as make_variant_1;
265pub use patch_seq_make_variant_2 as make_variant_2;
266pub use patch_seq_make_variant_3 as make_variant_3;
267pub use patch_seq_make_variant_4 as make_variant_4;
268
269#[unsafe(no_mangle)]
283pub unsafe extern "C" fn patch_seq_variant_append(stack: Stack) -> Stack {
284 use crate::value::VariantData;
285
286 unsafe {
287 let (stack, value) = pop(stack);
289
290 let (stack, variant_val) = pop(stack);
292
293 match variant_val {
294 Value::Variant(variant_data) => {
295 let mut new_fields = variant_data.fields.to_vec();
297 new_fields.push(value);
298
299 let new_variant = Value::Variant(Arc::new(VariantData::new(
301 variant_data.tag.clone(),
302 new_fields,
303 )));
304
305 push(stack, new_variant)
306 }
307 _ => panic!("variant-append: expected Variant, got {:?}", variant_val),
308 }
309 }
310}
311
312#[unsafe(no_mangle)]
322pub unsafe extern "C" fn patch_seq_variant_last(stack: Stack) -> Stack {
323 unsafe {
324 let (stack, variant_val) = pop(stack);
325
326 match variant_val {
327 Value::Variant(variant_data) => {
328 if variant_data.fields.is_empty() {
329 panic!("variant-last: variant has no fields");
330 }
331
332 let last = variant_data.fields.last().unwrap().clone();
333 push(stack, last)
334 }
335 _ => panic!("variant-last: expected Variant, got {:?}", variant_val),
336 }
337 }
338}
339
340#[unsafe(no_mangle)]
351pub unsafe extern "C" fn patch_seq_variant_init(stack: Stack) -> Stack {
352 use crate::value::VariantData;
353
354 unsafe {
355 let (stack, variant_val) = pop(stack);
356
357 match variant_val {
358 Value::Variant(variant_data) => {
359 if variant_data.fields.is_empty() {
360 panic!("variant-init: variant has no fields");
361 }
362
363 let new_fields: Vec<Value> =
365 variant_data.fields[..variant_data.fields.len() - 1].to_vec();
366
367 let new_variant = Value::Variant(Arc::new(VariantData::new(
368 variant_data.tag.clone(),
369 new_fields,
370 )));
371
372 push(stack, new_variant)
373 }
374 _ => panic!("variant-init: expected Variant, got {:?}", variant_val),
375 }
376 }
377}
378
379#[unsafe(no_mangle)]
392pub unsafe extern "C" fn patch_seq_unpack_variant(stack: Stack, field_count: i64) -> Stack {
393 unsafe {
394 let (mut stack, variant_val) = pop(stack);
395
396 match variant_val {
397 Value::Variant(variant_data) => {
398 let count = field_count as usize;
399 if count > variant_data.fields.len() {
400 panic!(
401 "unpack-variant: requested {} fields but variant only has {}",
402 count,
403 variant_data.fields.len()
404 );
405 }
406
407 for i in 0..count {
409 stack = push(stack, variant_data.fields[i].clone());
410 }
411
412 stack
413 }
414 _ => panic!("unpack-variant: expected Variant, got {:?}", variant_val),
415 }
416 }
417}
418
419pub use patch_seq_unpack_variant as unpack_variant;
421pub use patch_seq_variant_append as variant_append;
422pub use patch_seq_variant_field_at as variant_field_at;
423pub use patch_seq_variant_field_count as variant_field_count;
424pub use patch_seq_variant_init as variant_init;
425pub use patch_seq_variant_last as variant_last;
426pub use patch_seq_variant_tag as variant_tag;
427
428#[cfg(test)]
429mod tests {
430 use super::*;
431 use crate::seqstring::global_string;
432 use crate::value::VariantData;
433
434 #[test]
435 fn test_variant_field_count() {
436 unsafe {
437 let variant = Value::Variant(Arc::new(VariantData::new(
439 global_string("TestTag".to_string()),
440 vec![Value::Int(10), Value::Int(20), Value::Int(30)],
441 )));
442
443 let stack = crate::stack::alloc_test_stack();
444 let stack = push(stack, variant);
445 let stack = variant_field_count(stack);
446
447 let (_stack, result) = pop(stack);
448 assert_eq!(result, Value::Int(3));
449 }
450 }
451
452 #[test]
453 fn test_variant_tag() {
454 unsafe {
455 let variant = Value::Variant(Arc::new(VariantData::new(
457 global_string("MyTag".to_string()),
458 vec![Value::Int(10)],
459 )));
460
461 let stack = crate::stack::alloc_test_stack();
462 let stack = push(stack, variant);
463 let stack = variant_tag(stack);
464
465 let (_stack, result) = pop(stack);
466 assert_eq!(result, Value::Symbol(global_string("MyTag".to_string())));
467 }
468 }
469
470 #[test]
471 fn test_variant_field_at() {
472 unsafe {
473 let str1 = global_string("hello".to_string());
474 let str2 = global_string("world".to_string());
475
476 let variant = Value::Variant(Arc::new(VariantData::new(
478 global_string("TestTag".to_string()),
479 vec![
480 Value::String(str1.clone()),
481 Value::Int(42),
482 Value::String(str2.clone()),
483 ],
484 )));
485
486 let stack = crate::stack::alloc_test_stack();
488 let stack = push(stack, variant.clone());
489 let stack = push(stack, Value::Int(0));
490 let stack = variant_field_at(stack);
491
492 let (_stack, result) = pop(stack);
493 assert_eq!(result, Value::String(str1.clone()));
494
495 let stack = push(stack, variant.clone());
497 let stack = push(stack, Value::Int(1));
498 let stack = variant_field_at(stack);
499
500 let (_stack, result) = pop(stack);
501 assert_eq!(result, Value::Int(42));
502
503 let stack = push(stack, variant.clone());
505 let stack = push(stack, Value::Int(2));
506 let stack = variant_field_at(stack);
507
508 let (_stack, result) = pop(stack);
509 assert_eq!(result, Value::String(str2));
510 }
511 }
512
513 #[test]
514 fn test_variant_field_count_empty() {
515 unsafe {
516 let variant = Value::Variant(Arc::new(VariantData::new(
518 global_string("Empty".to_string()),
519 vec![],
520 )));
521
522 let stack = crate::stack::alloc_test_stack();
523 let stack = push(stack, variant);
524 let stack = variant_field_count(stack);
525
526 let (_stack, result) = pop(stack);
527 assert_eq!(result, Value::Int(0));
528 }
529 }
530
531 #[test]
532 fn test_make_variant_with_fields() {
533 unsafe {
534 let stack = crate::stack::alloc_test_stack();
537 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);
543
544 let (_stack, result) = pop(stack);
545
546 match result {
547 Value::Variant(v) => {
548 assert_eq!(v.tag.as_str(), "Tag");
549 assert_eq!(v.fields.len(), 3);
550 assert_eq!(v.fields[0], Value::Int(10));
551 assert_eq!(v.fields[1], Value::Int(20));
552 assert_eq!(v.fields[2], Value::Int(30));
553 }
554 _ => panic!("Expected Variant"),
555 }
556 }
557 }
558
559 #[test]
560 fn test_make_variant_empty() {
561 unsafe {
562 let stack = crate::stack::alloc_test_stack();
565 let stack = push(stack, Value::Symbol(global_string("None".to_string()))); let stack = make_variant_0(stack);
568
569 let (_stack, result) = pop(stack);
570
571 match result {
572 Value::Variant(v) => {
573 assert_eq!(v.tag.as_str(), "None");
574 assert_eq!(v.fields.len(), 0);
575 }
576 _ => panic!("Expected Variant"),
577 }
578 }
579 }
580
581 #[test]
582 fn test_make_variant_with_mixed_types() {
583 unsafe {
584 let s = global_string("hello".to_string());
585
586 let stack = crate::stack::alloc_test_stack();
588 let stack = push(stack, Value::Int(42));
589 let stack = push(stack, Value::String(s.clone()));
590 let stack = push(stack, Value::Float(3.5));
591 let stack = push(stack, Value::Symbol(global_string("Mixed".to_string()))); let stack = make_variant_3(stack);
594
595 let (_stack, result) = pop(stack);
596
597 match result {
598 Value::Variant(v) => {
599 assert_eq!(v.tag.as_str(), "Mixed");
600 assert_eq!(v.fields.len(), 3);
601 assert_eq!(v.fields[0], Value::Int(42));
602 assert_eq!(v.fields[1], Value::String(s));
603 assert_eq!(v.fields[2], Value::Float(3.5));
604 }
605 _ => panic!("Expected Variant"),
606 }
607 }
608 }
609
610 #[test]
611 fn test_variant_append() {
612 unsafe {
613 let stack = crate::stack::alloc_test_stack();
615 let stack = push(stack, Value::Symbol(global_string("Array".to_string()))); let stack = make_variant_0(stack);
617
618 let stack = push(stack, Value::Int(42));
620 let stack = variant_append(stack);
621
622 let (_stack, result) = pop(stack);
624 match result {
625 Value::Variant(v) => {
626 assert_eq!(v.tag.as_str(), "Array");
627 assert_eq!(v.fields.len(), 1);
628 assert_eq!(v.fields[0], Value::Int(42));
629 }
630 _ => panic!("Expected Variant"),
631 }
632 }
633 }
634
635 #[test]
636 fn test_variant_append_multiple() {
637 unsafe {
638 let stack = crate::stack::alloc_test_stack();
640 let stack = push(stack, Value::Symbol(global_string("Object".to_string()))); let stack = make_variant_0(stack);
642
643 let key = global_string("name".to_string());
645 let stack = push(stack, Value::String(key.clone()));
646 let stack = variant_append(stack);
647
648 let val = global_string("John".to_string());
650 let stack = push(stack, Value::String(val.clone()));
651 let stack = variant_append(stack);
652
653 let (_stack, result) = pop(stack);
655 match result {
656 Value::Variant(v) => {
657 assert_eq!(v.tag.as_str(), "Object");
658 assert_eq!(v.fields.len(), 2);
659 assert_eq!(v.fields[0], Value::String(key));
660 assert_eq!(v.fields[1], Value::String(val));
661 }
662 _ => panic!("Expected Variant"),
663 }
664 }
665 }
666
667 #[test]
668 fn test_variant_last() {
669 unsafe {
670 let variant = Value::Variant(Arc::new(VariantData::new(
672 global_string("List".to_string()),
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_last(stack);
679
680 let (_stack, result) = pop(stack);
681 assert_eq!(result, Value::Int(30));
682 }
683 }
684
685 #[test]
686 fn test_variant_init() {
687 unsafe {
688 let variant = Value::Variant(Arc::new(VariantData::new(
690 global_string("Custom".to_string()),
691 vec![Value::Int(10), Value::Int(20), Value::Int(30)],
692 )));
693
694 let stack = crate::stack::alloc_test_stack();
695 let stack = push(stack, variant);
696 let stack = variant_init(stack);
697
698 let (_stack, result) = pop(stack);
699 match result {
700 Value::Variant(v) => {
701 assert_eq!(v.tag.as_str(), "Custom"); assert_eq!(v.fields.len(), 2);
703 assert_eq!(v.fields[0], Value::Int(10));
704 assert_eq!(v.fields[1], Value::Int(20));
705 }
706 _ => panic!("Expected Variant"),
707 }
708 }
709 }
710
711 #[test]
712 fn test_variant_stack_operations() {
713 unsafe {
715 let stack = crate::stack::alloc_test_stack();
717 let stack = push(stack, Value::Symbol(global_string("Stack".to_string()))); let stack = make_variant_0(stack);
719
720 let stack = push(stack, Value::Int(10));
722 let stack = variant_append(stack);
723
724 let stack = push(stack, Value::Int(20));
726 let stack = variant_append(stack);
727
728 let (stack, variant) = pop(stack);
731 let stack = push(stack, variant.clone());
732 let stack = push(stack, variant);
733 let stack = variant_last(stack);
734 let (stack, top) = pop(stack);
735 assert_eq!(top, Value::Int(20));
736
737 let stack = variant_init(stack);
739
740 let (stack, variant) = pop(stack);
742 let stack = push(stack, variant.clone());
743 let stack = push(stack, variant);
744 let stack = variant_last(stack);
745 let (stack, top) = pop(stack);
746 assert_eq!(top, Value::Int(10));
747
748 let (_stack, result) = pop(stack);
750 match result {
751 Value::Variant(v) => {
752 assert_eq!(v.fields.len(), 1);
753 assert_eq!(v.fields[0], Value::Int(10));
754 }
755 _ => panic!("Expected Variant"),
756 }
757 }
758 }
759
760 #[test]
761 fn test_variant_clone_is_o1() {
762 let mut variant = Value::Variant(Arc::new(VariantData::new(
765 global_string("Level0".to_string()),
766 vec![],
767 )));
768
769 for i in 0..100 {
771 variant = Value::Variant(Arc::new(VariantData::new(
772 global_string(format!("Level{}", i)),
773 vec![variant.clone()],
774 )));
775 }
776
777 let start = std::time::Instant::now();
779 for _ in 0..1000 {
780 let _copy = variant.clone();
781 }
782 let elapsed = start.elapsed();
783
784 assert!(
787 elapsed.as_millis() < 10,
788 "Clone took {:?} - should be O(1) with Arc",
789 elapsed
790 );
791 }
792
793 #[test]
794 fn test_variant_arc_sharing() {
795 let inner = Value::Variant(Arc::new(VariantData::new(
797 global_string("Inner".to_string()),
798 vec![Value::Int(42)],
799 )));
800 let outer = Value::Variant(Arc::new(VariantData::new(
801 global_string("Outer".to_string()),
802 vec![inner.clone()],
803 )));
804
805 let outer_clone = outer.clone();
807
808 match (&outer, &outer_clone) {
810 (Value::Variant(a), Value::Variant(b)) => {
811 assert_eq!(a.tag, b.tag);
814 assert_eq!(a.fields.len(), b.fields.len());
815 }
816 _ => panic!("Expected Variants"),
817 }
818 }
819
820 #[test]
821 fn test_variant_thread_safe_sharing() {
822 use std::sync::Arc as StdArc;
825 use std::thread;
826
827 let variant = Value::Variant(Arc::new(VariantData::new(
828 global_string("ThreadSafe".to_string()),
829 vec![Value::Int(1), Value::Int(2), Value::Int(3)],
830 )));
831
832 let shared = StdArc::new(variant);
834
835 let handles: Vec<_> = (0..4)
836 .map(|_| {
837 let v = StdArc::clone(&shared);
838 thread::spawn(move || {
839 match &*v {
841 Value::Variant(data) => {
842 assert_eq!(data.tag.as_str(), "ThreadSafe");
843 assert_eq!(data.fields.len(), 3);
844 }
845 _ => panic!("Expected Variant"),
846 }
847 })
848 })
849 .collect();
850
851 for h in handles {
852 h.join().expect("Thread panicked");
853 }
854 }
855}