1use crate::seqstring::global_string;
36use crate::stack::{Stack, pop, push};
37use crate::value::{MapKey, Value, VariantData};
38use std::sync::Arc;
39
40#[unsafe(no_mangle)]
47pub unsafe extern "C" fn patch_seq_make_map(stack: Stack) -> Stack {
48 unsafe { push(stack, Value::Map(Box::default())) }
49}
50
51#[unsafe(no_mangle)]
62pub unsafe extern "C" fn patch_seq_map_get(stack: Stack) -> Stack {
63 unsafe {
64 let (stack, key_val) = pop(stack);
66 let key = MapKey::from_value(&key_val).unwrap_or_else(|| {
67 panic!(
68 "map-get: key must be Int, String, or Bool, got {:?}",
69 key_val
70 )
71 });
72
73 let (stack, map_val) = pop(stack);
75 let map = match map_val {
76 Value::Map(m) => m,
77 _ => panic!("map-get: expected Map, got {:?}", map_val),
78 };
79
80 match map.get(&key) {
82 Some(value) => {
83 let stack = push(stack, value.clone());
84 push(stack, Value::Bool(true))
85 }
86 None => {
87 let stack = push(stack, Value::Int(0)); push(stack, Value::Bool(false)) }
90 }
91 }
92}
93
94#[unsafe(no_mangle)]
104pub unsafe extern "C" fn patch_seq_map_set(stack: Stack) -> Stack {
105 unsafe {
106 let (stack, value) = pop(stack);
108
109 let (stack, key_val) = pop(stack);
111 let key = MapKey::from_value(&key_val).unwrap_or_else(|| {
112 panic!(
113 "map-set: key must be Int, String, or Bool, got {:?}",
114 key_val
115 )
116 });
117
118 let (stack, map_val) = pop(stack);
120 let mut map = match map_val {
121 Value::Map(m) => *m,
122 _ => panic!("map-set: expected Map, got {:?}", map_val),
123 };
124
125 map.insert(key, value);
127
128 push(stack, Value::Map(Box::new(map)))
129 }
130}
131
132#[unsafe(no_mangle)]
142pub unsafe extern "C" fn patch_seq_map_has(stack: Stack) -> Stack {
143 unsafe {
144 let (stack, key_val) = pop(stack);
146 let key = MapKey::from_value(&key_val).unwrap_or_else(|| {
147 panic!(
148 "map-has?: key must be Int, String, or Bool, got {:?}",
149 key_val
150 )
151 });
152
153 let (stack, map_val) = pop(stack);
155 let map = match map_val {
156 Value::Map(m) => m,
157 _ => panic!("map-has?: expected Map, got {:?}", map_val),
158 };
159
160 let has_key = map.contains_key(&key);
161 push(stack, Value::Bool(has_key))
162 }
163}
164
165#[unsafe(no_mangle)]
176pub unsafe extern "C" fn patch_seq_map_remove(stack: Stack) -> Stack {
177 unsafe {
178 let (stack, key_val) = pop(stack);
180 let key = MapKey::from_value(&key_val).unwrap_or_else(|| {
181 panic!(
182 "map-remove: key must be Int, String, or Bool, got {:?}",
183 key_val
184 )
185 });
186
187 let (stack, map_val) = pop(stack);
189 let mut map = match map_val {
190 Value::Map(m) => *m,
191 _ => panic!("map-remove: expected Map, got {:?}", map_val),
192 };
193
194 map.remove(&key);
196
197 push(stack, Value::Map(Box::new(map)))
198 }
199}
200
201#[unsafe(no_mangle)]
211pub unsafe extern "C" fn patch_seq_map_keys(stack: Stack) -> Stack {
212 unsafe {
213 let (stack, map_val) = pop(stack);
214 let map = match map_val {
215 Value::Map(m) => m,
216 _ => panic!("map-keys: expected Map, got {:?}", map_val),
217 };
218
219 let keys: Vec<Value> = map.keys().map(|k| k.to_value()).collect();
220 let variant = Value::Variant(Arc::new(VariantData::new(
221 global_string("List".to_string()),
222 keys,
223 )));
224 push(stack, variant)
225 }
226}
227
228#[unsafe(no_mangle)]
238pub unsafe extern "C" fn patch_seq_map_values(stack: Stack) -> Stack {
239 unsafe {
240 let (stack, map_val) = pop(stack);
241 let map = match map_val {
242 Value::Map(m) => m,
243 _ => panic!("map-values: expected Map, got {:?}", map_val),
244 };
245
246 let values: Vec<Value> = map.values().cloned().collect();
247 let variant = Value::Variant(Arc::new(VariantData::new(
248 global_string("List".to_string()),
249 values,
250 )));
251 push(stack, variant)
252 }
253}
254
255#[unsafe(no_mangle)]
262pub unsafe extern "C" fn patch_seq_map_size(stack: Stack) -> Stack {
263 unsafe {
264 let (stack, map_val) = pop(stack);
265 let map = match map_val {
266 Value::Map(m) => m,
267 _ => panic!("map-size: expected Map, got {:?}", map_val),
268 };
269
270 push(stack, Value::Int(map.len() as i64))
271 }
272}
273
274#[unsafe(no_mangle)]
283pub unsafe extern "C" fn patch_seq_map_empty(stack: Stack) -> Stack {
284 unsafe {
285 let (stack, map_val) = pop(stack);
286 let map = match map_val {
287 Value::Map(m) => m,
288 _ => panic!("map-empty?: expected Map, got {:?}", map_val),
289 };
290
291 let is_empty = map.is_empty();
292 push(stack, Value::Bool(is_empty))
293 }
294}
295
296pub use patch_seq_make_map as make_map;
298pub use patch_seq_map_empty as map_empty;
299pub use patch_seq_map_get as map_get;
300pub use patch_seq_map_has as map_has;
301pub use patch_seq_map_keys as map_keys;
302pub use patch_seq_map_remove as map_remove;
303pub use patch_seq_map_set as map_set;
304pub use patch_seq_map_size as map_size;
305pub use patch_seq_map_values as map_values;
306
307#[cfg(test)]
308mod tests {
309 use super::*;
310
311 #[test]
312 fn test_make_map() {
313 unsafe {
314 let stack = crate::stack::alloc_test_stack();
315 let stack = make_map(stack);
316
317 let (_stack, result) = pop(stack);
318 match result {
319 Value::Map(m) => assert!(m.is_empty()),
320 _ => panic!("Expected Map"),
321 }
322 }
323 }
324
325 #[test]
326 fn test_map_set_and_get() {
327 unsafe {
328 let stack = crate::stack::alloc_test_stack();
329 let stack = make_map(stack);
330 let stack = push(stack, Value::String("name".into()));
331 let stack = push(stack, Value::String("Alice".into()));
332 let stack = map_set(stack);
333
334 let stack = push(stack, Value::String("name".into()));
336 let stack = map_get(stack);
337
338 let (stack, flag) = pop(stack);
340 assert_eq!(flag, Value::Bool(true));
341 let (_stack, result) = pop(stack);
342 match result {
343 Value::String(s) => assert_eq!(s.as_str(), "Alice"),
344 _ => panic!("Expected String"),
345 }
346 }
347 }
348
349 #[test]
350 fn test_map_set_with_int_key() {
351 unsafe {
352 let stack = crate::stack::alloc_test_stack();
353 let stack = make_map(stack);
354 let stack = push(stack, Value::Int(42));
355 let stack = push(stack, Value::String("answer".into()));
356 let stack = map_set(stack);
357
358 let stack = push(stack, Value::Int(42));
359 let stack = map_get(stack);
360
361 let (stack, flag) = pop(stack);
363 assert_eq!(flag, Value::Bool(true));
364 let (_stack, result) = pop(stack);
365 match result {
366 Value::String(s) => assert_eq!(s.as_str(), "answer"),
367 _ => panic!("Expected String"),
368 }
369 }
370 }
371
372 #[test]
373 fn test_map_has() {
374 unsafe {
375 let stack = crate::stack::alloc_test_stack();
376 let stack = make_map(stack);
377 let stack = push(stack, Value::String("key".into()));
378 let stack = push(stack, Value::Int(100));
379 let stack = map_set(stack);
380
381 let stack = crate::stack::dup(stack);
383 let stack = push(stack, Value::String("key".into()));
384 let stack = map_has(stack);
385 let (stack, result) = pop(stack);
386 assert_eq!(result, Value::Bool(true));
387
388 let stack = push(stack, Value::String("missing".into()));
390 let stack = map_has(stack);
391 let (_stack, result) = pop(stack);
392 assert_eq!(result, Value::Bool(false));
393 }
394 }
395
396 #[test]
397 fn test_map_remove() {
398 unsafe {
399 let stack = crate::stack::alloc_test_stack();
400 let stack = make_map(stack);
401 let stack = push(stack, Value::String("a".into()));
402 let stack = push(stack, Value::Int(1));
403 let stack = map_set(stack);
404 let stack = push(stack, Value::String("b".into()));
405 let stack = push(stack, Value::Int(2));
406 let stack = map_set(stack);
407
408 let stack = push(stack, Value::String("a".into()));
410 let stack = map_remove(stack);
411
412 let stack = crate::stack::dup(stack);
414 let stack = push(stack, Value::String("a".into()));
415 let stack = map_has(stack);
416 let (stack, result) = pop(stack);
417 assert_eq!(result, Value::Bool(false));
418
419 let stack = push(stack, Value::String("b".into()));
421 let stack = map_has(stack);
422 let (_stack, result) = pop(stack);
423 assert_eq!(result, Value::Bool(true));
424 }
425 }
426
427 #[test]
428 fn test_map_size() {
429 unsafe {
430 let stack = crate::stack::alloc_test_stack();
431 let stack = make_map(stack);
432
433 let stack = map_size(stack);
435 let (stack, result) = pop(stack);
436 assert_eq!(result, Value::Int(0));
437
438 let stack = make_map(stack);
440 let stack = push(stack, Value::String("a".into()));
441 let stack = push(stack, Value::Int(1));
442 let stack = map_set(stack);
443 let stack = push(stack, Value::String("b".into()));
444 let stack = push(stack, Value::Int(2));
445 let stack = map_set(stack);
446
447 let stack = map_size(stack);
448 let (_stack, result) = pop(stack);
449 assert_eq!(result, Value::Int(2));
450 }
451 }
452
453 #[test]
454 fn test_map_empty() {
455 unsafe {
456 let stack = crate::stack::alloc_test_stack();
457 let stack = make_map(stack);
458
459 let stack = map_empty(stack);
460 let (stack, result) = pop(stack);
461 assert_eq!(result, Value::Bool(true));
462
463 let stack = make_map(stack);
465 let stack = push(stack, Value::String("key".into()));
466 let stack = push(stack, Value::Int(1));
467 let stack = map_set(stack);
468
469 let stack = map_empty(stack);
470 let (_stack, result) = pop(stack);
471 assert_eq!(result, Value::Bool(false));
472 }
473 }
474
475 #[test]
476 fn test_map_keys_and_values() {
477 unsafe {
478 let stack = crate::stack::alloc_test_stack();
479 let stack = make_map(stack);
480 let stack = push(stack, Value::String("x".into()));
481 let stack = push(stack, Value::Int(10));
482 let stack = map_set(stack);
483 let stack = push(stack, Value::String("y".into()));
484 let stack = push(stack, Value::Int(20));
485 let stack = map_set(stack);
486
487 let stack = crate::stack::dup(stack); let stack = map_keys(stack);
490 let (stack, keys_result) = pop(stack);
491 match keys_result {
492 Value::Variant(v) => {
493 assert_eq!(v.fields.len(), 2);
494 }
496 _ => panic!("Expected Variant"),
497 }
498
499 let stack = map_values(stack);
501 let (_stack, values_result) = pop(stack);
502 match values_result {
503 Value::Variant(v) => {
504 assert_eq!(v.fields.len(), 2);
505 }
507 _ => panic!("Expected Variant"),
508 }
509 }
510 }
511
512 #[test]
513 fn test_map_get_found() {
514 unsafe {
515 let stack = crate::stack::alloc_test_stack();
516 let stack = make_map(stack);
517 let stack = push(stack, Value::String("key".into()));
518 let stack = push(stack, Value::Int(42));
519 let stack = map_set(stack);
520
521 let stack = push(stack, Value::String("key".into()));
522 let stack = map_get(stack);
523
524 let (stack, flag) = pop(stack);
525 let (_stack, value) = pop(stack);
526 assert_eq!(flag, Value::Bool(true));
527 assert_eq!(value, Value::Int(42));
528 }
529 }
530
531 #[test]
532 fn test_map_get_not_found() {
533 unsafe {
534 let stack = crate::stack::alloc_test_stack();
535 let stack = make_map(stack);
536
537 let stack = push(stack, Value::String("missing".into()));
538 let stack = map_get(stack);
539
540 let (stack, flag) = pop(stack);
541 let (_stack, _value) = pop(stack); assert_eq!(flag, Value::Bool(false));
543 }
544 }
545
546 #[test]
547 fn test_map_with_bool_key() {
548 unsafe {
549 let stack = crate::stack::alloc_test_stack();
550 let stack = make_map(stack);
551 let stack = push(stack, Value::Bool(true));
552 let stack = push(stack, Value::String("yes".into()));
553 let stack = map_set(stack);
554 let stack = push(stack, Value::Bool(false));
555 let stack = push(stack, Value::String("no".into()));
556 let stack = map_set(stack);
557
558 let stack = push(stack, Value::Bool(true));
559 let stack = map_get(stack);
560 let (stack, flag) = pop(stack);
562 assert_eq!(flag, Value::Bool(true));
563 let (_stack, result) = pop(stack);
564 match result {
565 Value::String(s) => assert_eq!(s.as_str(), "yes"),
566 _ => panic!("Expected String"),
567 }
568 }
569 }
570
571 #[test]
572 fn test_map_key_overwrite() {
573 unsafe {
575 let stack = crate::stack::alloc_test_stack();
576 let stack = make_map(stack);
577
578 let stack = push(stack, Value::String("key".into()));
580 let stack = push(stack, Value::Int(100));
581 let stack = map_set(stack);
582
583 let stack = push(stack, Value::String("key".into()));
585 let stack = push(stack, Value::Int(200));
586 let stack = map_set(stack);
587
588 let stack = crate::stack::dup(stack);
590 let stack = map_size(stack);
591 let (stack, size) = pop(stack);
592 assert_eq!(size, Value::Int(1));
593
594 let stack = push(stack, Value::String("key".into()));
596 let stack = map_get(stack);
597 let (stack, flag) = pop(stack);
599 assert_eq!(flag, Value::Bool(true));
600 let (_stack, result) = pop(stack);
601 assert_eq!(result, Value::Int(200));
602 }
603 }
604
605 #[test]
606 fn test_map_mixed_key_types() {
607 unsafe {
609 let stack = crate::stack::alloc_test_stack();
610 let stack = make_map(stack);
611
612 let stack = push(stack, Value::String("name".into()));
614 let stack = push(stack, Value::String("Alice".into()));
615 let stack = map_set(stack);
616
617 let stack = push(stack, Value::Int(42));
619 let stack = push(stack, Value::String("answer".into()));
620 let stack = map_set(stack);
621
622 let stack = push(stack, Value::Bool(true));
624 let stack = push(stack, Value::String("yes".into()));
625 let stack = map_set(stack);
626
627 let stack = crate::stack::dup(stack);
629 let stack = map_size(stack);
630 let (stack, size) = pop(stack);
631 assert_eq!(size, Value::Int(3));
632
633 let stack = crate::stack::dup(stack);
636 let stack = push(stack, Value::String("name".into()));
637 let stack = map_get(stack);
638 let (stack, flag) = pop(stack);
639 assert_eq!(flag, Value::Bool(true));
640 let (stack, result) = pop(stack);
641 match result {
642 Value::String(s) => assert_eq!(s.as_str(), "Alice"),
643 _ => panic!("Expected String for name key"),
644 }
645
646 let stack = crate::stack::dup(stack);
647 let stack = push(stack, Value::Int(42));
648 let stack = map_get(stack);
649 let (stack, flag) = pop(stack);
650 assert_eq!(flag, Value::Bool(true));
651 let (stack, result) = pop(stack);
652 match result {
653 Value::String(s) => assert_eq!(s.as_str(), "answer"),
654 _ => panic!("Expected String for int key"),
655 }
656
657 let stack = push(stack, Value::Bool(true));
658 let stack = map_get(stack);
659 let (stack, flag) = pop(stack);
660 assert_eq!(flag, Value::Bool(true));
661 let (_stack, result) = pop(stack);
662 match result {
663 Value::String(s) => assert_eq!(s.as_str(), "yes"),
664 _ => panic!("Expected String for bool key"),
665 }
666 }
667 }
668}