use crate::executor::VirtualMachine;
use shape_runtime::context::ExecutionContext;
use shape_value::heap_value::{HeapKind, RangeData};
use shape_value::iterator_state::{IteratorSource, IteratorState};
use shape_value::slot::ValueSlot;
use shape_value::v2::typed_array::TypedArray;
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 clone_range_arc(slot: &KindedSlot) -> Result<Arc<RangeData>, VMError> {
if !matches!(slot.kind, NativeKind::Ptr(HeapKind::Range)) {
return Err(type_error(format!(
"Range method receiver must be a Range (got kind {:?})",
slot.kind
)));
}
let bits = slot.slot.raw();
if bits == 0 {
return Err(type_error("Range method receiver slot bits null"));
}
let arc = unsafe { Arc::<RangeData>::from_raw(bits as *const RangeData) };
let cloned = Arc::clone(&arc);
let _ = Arc::into_raw(arc);
Ok(cloned)
}
#[inline]
fn as_int64_arg(slot: &KindedSlot, method: &str) -> Result<i64, VMError> {
match slot.kind {
NativeKind::Int64 => Ok(slot.slot.as_i64()),
other => Err(type_error(format!(
"Range.{}: argument must be int (got kind {:?})",
method, other
))),
}
}
pub fn range_contains(
_vm: &mut VirtualMachine,
args: &[KindedSlot],
_ctx: Option<&mut ExecutionContext>,
) -> Result<KindedSlot, VMError> {
if args.len() < 2 {
return Err(type_error(format!(
"Range.contains() expects 1 argument, got {}",
args.len().saturating_sub(1)
)));
}
let range = clone_range_arc(&args[0])?;
let value = as_int64_arg(&args[1], "contains")?;
Ok(KindedSlot::from_bool(range.contains(value)))
}
pub fn range_to_array(
_vm: &mut VirtualMachine,
args: &[KindedSlot],
_ctx: Option<&mut ExecutionContext>,
) -> Result<KindedSlot, VMError> {
if args.is_empty() {
return Err(type_error("Range.toArray(): missing receiver"));
}
let range = clone_range_arc(&args[0])?;
let vec = range.to_vec_i64();
let arr_ptr: *mut TypedArray<i64> = TypedArray::<i64>::from_slice(&vec);
let slot = ValueSlot::from_u64(arr_ptr as u64);
Ok(KindedSlot::new(
slot,
NativeKind::Ptr(HeapKind::TypedArray),
))
}
pub fn range_iter(
_vm: &mut VirtualMachine,
args: &[KindedSlot],
_ctx: Option<&mut ExecutionContext>,
) -> Result<KindedSlot, VMError> {
if args.is_empty() {
return Err(type_error("Range.iter(): missing receiver"));
}
let range = clone_range_arc(&args[0])?;
let source = IteratorSource::Range {
start: range.start,
end: range.end_exclusive(),
step: range.step,
};
let state = IteratorState::new(source);
Ok(KindedSlot::from_iterator(Arc::new(state)))
}
pub fn range_start(
_vm: &mut VirtualMachine,
args: &[KindedSlot],
_ctx: Option<&mut ExecutionContext>,
) -> Result<KindedSlot, VMError> {
let range = clone_range_arc(args.first().ok_or_else(|| {
type_error("Range.start: missing receiver")
})?)?;
Ok(KindedSlot::from_int(range.start))
}
pub fn range_end(
_vm: &mut VirtualMachine,
args: &[KindedSlot],
_ctx: Option<&mut ExecutionContext>,
) -> Result<KindedSlot, VMError> {
let range = clone_range_arc(args.first().ok_or_else(|| {
type_error("Range.end: missing receiver")
})?)?;
Ok(KindedSlot::from_int(range.end))
}
pub fn range_step(
_vm: &mut VirtualMachine,
args: &[KindedSlot],
_ctx: Option<&mut ExecutionContext>,
) -> Result<KindedSlot, VMError> {
let range = clone_range_arc(args.first().ok_or_else(|| {
type_error("Range.step: missing receiver")
})?)?;
Ok(KindedSlot::from_int(range.step))
}
pub fn range_length(
_vm: &mut VirtualMachine,
args: &[KindedSlot],
_ctx: Option<&mut ExecutionContext>,
) -> Result<KindedSlot, VMError> {
let range = clone_range_arc(args.first().ok_or_else(|| {
type_error("Range.length: missing receiver")
})?)?;
Ok(KindedSlot::from_int(range.len() as i64))
}
pub fn range_is_empty(
_vm: &mut VirtualMachine,
args: &[KindedSlot],
_ctx: Option<&mut ExecutionContext>,
) -> Result<KindedSlot, VMError> {
let range = clone_range_arc(args.first().ok_or_else(|| {
type_error("Range.isEmpty: missing receiver")
})?)?;
Ok(KindedSlot::from_bool(range.is_empty()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn clone_range_arc_preserves_receiver_share() {
let r = Arc::new(RangeData::exclusive(0, 10));
let weak = Arc::downgrade(&r);
let slot = KindedSlot::from_range(r);
assert_eq!(weak.strong_count(), 1, "slot owns the only strong share");
let cloned = clone_range_arc(&slot).expect("kind matches");
assert_eq!(weak.strong_count(), 2, "clone bumped one share");
assert_eq!(cloned.start, 0);
assert_eq!(cloned.end, 10);
drop(cloned);
assert_eq!(weak.strong_count(), 1, "clone dropped");
drop(slot);
assert_eq!(weak.strong_count(), 0, "slot dropped");
}
#[test]
fn clone_range_arc_rejects_wrong_kind() {
let int_slot = KindedSlot::from_int(42);
let err = clone_range_arc(&int_slot);
assert!(err.is_err());
}
#[test]
fn range_iter_produces_iterator_state_smoke_target() {
let r = Arc::new(RangeData::exclusive(0, 5));
let slot = KindedSlot::from_range(r);
let arc = clone_range_arc(&slot).expect("kind matches");
let source = IteratorSource::Range {
start: arc.start,
end: arc.end_exclusive(),
step: arc.step,
};
assert_eq!(source.len(), 5);
let state = IteratorState::new(source);
assert_eq!(state.transforms.len(), 0);
assert_eq!(state.cursor, 0);
}
#[test]
fn range_iter_inclusive_baked_into_iter_source() {
let r = Arc::new(RangeData::inclusive(0, 10));
let slot = KindedSlot::from_range(r);
let arc = clone_range_arc(&slot).expect("kind matches");
assert_eq!(arc.end_exclusive(), 11);
let source = IteratorSource::Range {
start: arc.start,
end: arc.end_exclusive(),
step: arc.step,
};
assert_eq!(source.len(), 11);
}
#[test]
fn range_data_contains_bound_logic() {
let exc = RangeData::exclusive(0, 10);
assert!(exc.contains(0));
assert!(exc.contains(5));
assert!(exc.contains(9));
assert!(!exc.contains(10), "exclusive end excludes 10");
assert!(!exc.contains(-1));
let inc = RangeData::inclusive(0, 10);
assert!(inc.contains(0));
assert!(inc.contains(10), "inclusive end includes 10");
assert!(!inc.contains(11));
}
#[test]
fn range_data_to_vec_i64_exclusive() {
let r = RangeData::exclusive(0, 5);
assert_eq!(r.to_vec_i64(), vec![0, 1, 2, 3, 4]);
}
#[test]
fn range_data_to_vec_i64_inclusive() {
let r = RangeData::inclusive(0, 5);
assert_eq!(r.to_vec_i64(), vec![0, 1, 2, 3, 4, 5]);
}
#[test]
fn range_data_to_vec_i64_empty() {
let r = RangeData::exclusive(10, 5);
assert!(r.to_vec_i64().is_empty());
}
#[test]
fn range_data_to_vec_i64_strided() {
let r = RangeData::new(0, 10, 3, false);
assert_eq!(r.to_vec_i64(), vec![0, 3, 6, 9]);
}
}