use crate::executor::VirtualMachine;
use shape_runtime::context::ExecutionContext;
use shape_value::heap_value::{DequeData, HeapKind, HeapValue};
use shape_value::{KindedSlot, NativeKind, VMError};
use std::sync::Arc;
#[inline]
fn type_error(msg: impl Into<String>) -> VMError {
VMError::RuntimeError(msg.into())
}
#[inline]
fn as_deque(slot: &KindedSlot) -> Result<Arc<DequeData>, VMError> {
if !matches!(slot.kind, NativeKind::Ptr(HeapKind::Deque)) {
return Err(type_error(format!(
"Deque method receiver must be a Deque (got kind {:?})",
slot.kind
)));
}
let bits = slot.slot.raw();
if bits == 0 {
return Err(type_error("Deque method receiver slot bits null"));
}
let arc = unsafe { Arc::<DequeData>::from_raw(bits as *const DequeData) };
let cloned = Arc::clone(&arc);
let _ = Arc::into_raw(arc);
Ok(cloned)
}
fn arg_slot_to_heap_value_arc(arg: &KindedSlot) -> Result<Arc<HeapValue>, VMError> {
match arg.kind {
NativeKind::Int64 => {
let i = arg.as_i64().ok_or_else(|| {
type_error("Deque element: Int64 slot bits not a valid integer")
})?;
Ok(Arc::new(HeapValue::BigInt(Arc::new(i))))
}
NativeKind::Float64 => Err(type_error(
"Deque element: Float64 cannot be heap-wrapped (no HeapValue::Number arm)",
)),
NativeKind::Bool => Err(type_error(
"Deque element: Bool cannot be heap-wrapped (no HeapValue::Bool arm)",
)),
NativeKind::String | NativeKind::Ptr(HeapKind::String) => {
let bits = arg.slot.raw();
if bits == 0 {
return Err(type_error("Deque element: String slot bits null"));
}
let arc = unsafe {
Arc::increment_strong_count(bits as *const String);
Arc::from_raw(bits as *const String)
};
Ok(Arc::new(HeapValue::String(arc)))
}
NativeKind::Ptr(_) => {
let hv: &HeapValue = arg.slot.as_heap_value();
Ok(Arc::new(hv.clone()))
}
other => Err(type_error(format!(
"Deque element: kind {:?} cannot be stored",
other
))),
}
}
fn heap_value_arc_to_slot(hv: &Arc<HeapValue>) -> KindedSlot {
match hv.as_ref() {
HeapValue::String(s) => KindedSlot::from_string_arc(Arc::clone(s)),
HeapValue::Decimal(d) => KindedSlot::from_decimal(Arc::clone(d)),
HeapValue::BigInt(b) => KindedSlot::from_bigint(Arc::clone(b)),
HeapValue::TypedObject(o) => KindedSlot::from_typed_object_raw(o.clone().into_raw()),
HeapValue::HashMap(m) => KindedSlot::from_hashmap(Arc::new(m.clone())),
HeapValue::Char(c) => KindedSlot::from_char(*c),
_ => KindedSlot::none(),
}
}
pub fn v2_size(
_vm: &mut VirtualMachine,
args: &[KindedSlot],
_ctx: Option<&mut ExecutionContext>,
) -> Result<KindedSlot, VMError> {
if args.len() != 1 {
return Err(type_error("Deque.size() takes no arguments"));
}
let d = as_deque(&args[0])?;
Ok(KindedSlot::from_int(d.len() as i64))
}
pub fn v2_is_empty(
_vm: &mut VirtualMachine,
args: &[KindedSlot],
_ctx: Option<&mut ExecutionContext>,
) -> Result<KindedSlot, VMError> {
if args.len() != 1 {
return Err(type_error("Deque.isEmpty() takes no arguments"));
}
let d = as_deque(&args[0])?;
Ok(KindedSlot::from_bool(d.is_empty()))
}
pub fn v2_peek_front(
_vm: &mut VirtualMachine,
args: &[KindedSlot],
_ctx: Option<&mut ExecutionContext>,
) -> Result<KindedSlot, VMError> {
if args.len() != 1 {
return Err(type_error("Deque.peekFront() takes no arguments"));
}
let d = as_deque(&args[0])?;
match d.peek_front() {
Some(arc) => Ok(heap_value_arc_to_slot(arc)),
None => Ok(KindedSlot::none()),
}
}
pub fn v2_peek_back(
_vm: &mut VirtualMachine,
args: &[KindedSlot],
_ctx: Option<&mut ExecutionContext>,
) -> Result<KindedSlot, VMError> {
if args.len() != 1 {
return Err(type_error("Deque.peekBack() takes no arguments"));
}
let d = as_deque(&args[0])?;
match d.peek_back() {
Some(arc) => Ok(heap_value_arc_to_slot(arc)),
None => Ok(KindedSlot::none()),
}
}
pub fn v2_get(
_vm: &mut VirtualMachine,
args: &[KindedSlot],
_ctx: Option<&mut ExecutionContext>,
) -> Result<KindedSlot, VMError> {
if args.len() != 2 {
return Err(type_error(
"Deque.get() requires exactly 1 argument (index)",
));
}
let d = as_deque(&args[0])?;
let idx = args[1].as_i64().ok_or_else(|| {
type_error(format!(
"Deque.get(): index must be int (got kind {:?})",
args[1].kind()
))
})?;
if idx < 0 {
return Ok(KindedSlot::none());
}
match d.get(idx as usize) {
Some(arc) => Ok(heap_value_arc_to_slot(arc)),
None => Ok(KindedSlot::none()),
}
}
pub fn v2_to_array(
_vm: &mut VirtualMachine,
args: &[KindedSlot],
_ctx: Option<&mut ExecutionContext>,
) -> Result<KindedSlot, VMError> {
if args.len() != 1 {
return Err(type_error("Deque.toArray() takes no arguments"));
}
let _d = as_deque(&args[0])?;
Err(VMError::NotImplemented(
"Deque.toArray: SURFACE — V3-S5 ckpt-3 consumer-cascade tier 2 \
surface (drive-by from ckpt-2 cross-module helper deletion). \
`TypedArrayData` enum DELETED at ckpt-1 (2026-05-15) per W12-\
typed-array-data-deletion audit §3.5 + ADR-006 §2.7.24 Q25.A \
SUPERSEDED. The previous call to \
`array_transform::build_specialized_array_from_heap_arcs` \
cascade-broke at the ckpt-2 cross-module helper deletion \
(that helper produced `TypedArrayData`; the type is gone). \
Post-deletion target is the v2-raw `TypedArray<T>` flat-struct \
carrier with per-T monomorphized construction over the deque's \
homogeneous-element-kind contents per audit §A.3 + §3.1 \
scalar recipe; monomorphization lands across ckpt-3 / 4 / 5 / 6. \
UNREACHABLE until ckpt-6 STRICT close. REFUSED ON SIGHT: \
TypedArrayData resurrection under any rename (Refusal #1, W12 \
audit §7)."
.to_string(),
))
}
pub fn v2_push_back(
_vm: &mut VirtualMachine,
args: &[KindedSlot],
_ctx: Option<&mut ExecutionContext>,
) -> Result<KindedSlot, VMError> {
if args.len() != 2 {
return Err(type_error(
"Deque.pushBack() requires exactly 1 argument (value)",
));
}
let value: Arc<HeapValue> = arg_slot_to_heap_value_arc(&args[1])?;
let mut dq: Arc<DequeData> = as_deque(&args[0])?;
Arc::make_mut(&mut dq).push_back(value);
Ok(KindedSlot::from_deque(dq))
}
pub fn v2_push_front(
_vm: &mut VirtualMachine,
args: &[KindedSlot],
_ctx: Option<&mut ExecutionContext>,
) -> Result<KindedSlot, VMError> {
if args.len() != 2 {
return Err(type_error(
"Deque.pushFront() requires exactly 1 argument (value)",
));
}
let value: Arc<HeapValue> = arg_slot_to_heap_value_arc(&args[1])?;
let mut dq: Arc<DequeData> = as_deque(&args[0])?;
Arc::make_mut(&mut dq).push_front(value);
Ok(KindedSlot::from_deque(dq))
}
pub fn v2_pop_back(
vm: &mut VirtualMachine,
args: &[KindedSlot],
_ctx: Option<&mut ExecutionContext>,
) -> Result<KindedSlot, VMError> {
if args.len() != 1 {
return Err(type_error("Deque.popBack() takes no arguments"));
}
let mut dq: Arc<DequeData> = as_deque(&args[0])?;
let popped = Arc::make_mut(&mut dq).pop_back();
let new_self_slot = KindedSlot::from_deque(dq);
vm.push_kinded(new_self_slot.raw(), new_self_slot.kind())?;
std::mem::forget(new_self_slot);
match popped {
Some(arc) => Ok(heap_value_arc_to_slot(&arc)),
None => Ok(KindedSlot::none()),
}
}
pub fn v2_pop_front(
vm: &mut VirtualMachine,
args: &[KindedSlot],
_ctx: Option<&mut ExecutionContext>,
) -> Result<KindedSlot, VMError> {
if args.len() != 1 {
return Err(type_error("Deque.popFront() takes no arguments"));
}
let mut dq: Arc<DequeData> = as_deque(&args[0])?;
let popped = Arc::make_mut(&mut dq).pop_front();
let new_self_slot = KindedSlot::from_deque(dq);
vm.push_kinded(new_self_slot.raw(), new_self_slot.kind())?;
std::mem::forget(new_self_slot);
match popped {
Some(arc) => Ok(heap_value_arc_to_slot(&arc)),
None => Ok(KindedSlot::none()),
}
}