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_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),
}
}
}