use super::jit_kinds::*;
use super::value_ffi::*;
pub extern "C" fn jit_typeof(value_bits: u64) -> u64 {
let type_str = if is_number(value_bits) {
"number"
} else if value_bits == TAG_NULL {
"null"
} else if value_bits == TAG_BOOL_TRUE || value_bits == TAG_BOOL_FALSE {
"boolean"
} else if is_ok_tag(value_bits) || is_err_tag(value_bits) {
"result"
} else if is_inline_function(value_bits) {
"function"
} else {
match heap_kind(value_bits) {
Some(HK_STRING) => "string",
Some(HK_ARRAY) => "array",
Some(HK_JIT_OBJECT) | Some(HK_TYPED_OBJECT) => "object",
Some(HK_CLOSURE) => "function",
Some(HK_RANGE) => "range",
Some(HK_COLUMN_REF) => "series",
Some(HK_JIT_TABLE_REF) => "series_ref",
Some(HK_DURATION) => "duration",
Some(HK_TIME) => "time",
Some(HK_TIMEFRAME) => "timeframe",
_ => "unknown",
}
};
jit_box(HK_STRING, type_str.to_string())
}
pub extern "C" fn jit_to_string(value_bits: u64) -> u64 {
let s = if is_number(value_bits) {
format!("{}", unbox_number(value_bits))
} else if value_bits == TAG_NULL {
"null".to_string()
} else if value_bits == TAG_BOOL_TRUE {
"true".to_string()
} else if value_bits == TAG_BOOL_FALSE {
"false".to_string()
} else {
match heap_kind(value_bits) {
Some(HK_STRING) => {
let s = unsafe { jit_unbox::<String>(value_bits) };
s.clone()
}
Some(HK_ARRAY) => "[array]".to_string(),
Some(HK_JIT_OBJECT) | Some(HK_TYPED_OBJECT) => "[object]".to_string(),
_ => "[unknown]".to_string(),
}
};
jit_box(HK_STRING, s)
}
pub extern "C" fn jit_type_check(value_bits: u64, type_name_bits: u64) -> u64 {
let type_name = unsafe {
if !is_heap_kind(type_name_bits, HK_STRING) {
return TAG_BOOL_FALSE;
}
jit_unbox::<String>(type_name_bits).clone()
};
let matches = check_type_recursive(value_bits, &type_name);
if matches {
TAG_BOOL_TRUE
} else {
TAG_BOOL_FALSE
}
}
fn check_type_recursive(value_bits: u64, type_spec: &str) -> bool {
if let Some((prefix, rest)) = type_spec.split_once(':') {
match prefix {
"basic" => check_basic_type(value_bits, rest),
"optional" => {
value_bits == TAG_NULL || check_type_recursive(value_bits, rest)
}
"array" => {
let _ = rest;
is_heap_kind(value_bits, HK_ARRAY)
}
"tuple" => {
let _ = rest;
is_heap_kind(value_bits, HK_ARRAY)
}
"generic" => {
match rest {
"Array" => is_heap_kind(value_bits, HK_ARRAY),
"Series" => is_heap_kind(value_bits, HK_COLUMN_REF),
_ => false,
}
}
"ref" => {
false
}
"dyn" => {
false
}
_ => false,
}
} else {
match type_spec {
"function" => is_inline_function(value_bits) || is_heap_kind(value_bits, HK_CLOSURE),
"object" => is_heap_kind(value_bits, HK_TYPED_OBJECT),
"any" => true,
"void" => value_bits == TAG_UNIT,
"never" => false,
"null" => value_bits == TAG_NULL,
"undefined" => value_bits == TAG_NULL || value_bits == TAG_UNIT,
"unknown" => false,
_ => check_basic_type(value_bits, type_spec),
}
}
}
fn check_basic_type(value_bits: u64, type_name: &str) -> bool {
if is_number(value_bits) {
return type_name == "number";
}
if value_bits == TAG_NULL {
return type_name == "null";
}
if value_bits == TAG_BOOL_TRUE || value_bits == TAG_BOOL_FALSE {
return type_name == "boolean" || type_name == "bool";
}
if value_bits == TAG_UNIT {
return type_name == "void" || type_name == "unit";
}
if is_inline_function(value_bits) {
return type_name == "function";
}
if is_data_row(value_bits) {
return type_name == "data_row";
}
if is_ok_tag(value_bits) || is_err_tag(value_bits) {
return type_name == "result";
}
match heap_kind(value_bits) {
Some(HK_STRING) => type_name == "string",
Some(HK_ARRAY) => type_name == "array",
Some(HK_JIT_OBJECT) | Some(HK_TYPED_OBJECT) => type_name == "object",
Some(HK_CLOSURE) => type_name == "function",
Some(HK_COLUMN_REF) => type_name == "series",
Some(HK_TIME) => type_name == "time",
Some(HK_DURATION) => type_name == "duration",
Some(HK_TIMEFRAME) => type_name == "timeframe",
Some(HK_RANGE) => type_name == "range",
_ => false,
}
}
pub(crate) fn format_value_word(value_bits: u64) -> String {
if is_number(value_bits) {
let n = unbox_number(value_bits);
if n.is_finite() && n == n.trunc() && n.abs() < 1e15 {
format!("{}", n as i64)
} else {
format!("{}", n)
}
} else if value_bits == TAG_BOOL_TRUE {
"true".to_string()
} else if value_bits == TAG_BOOL_FALSE {
"false".to_string()
} else if value_bits == TAG_NULL {
"null".to_string()
} else {
match heap_kind(value_bits) {
Some(HK_STRING) => {
let s = unsafe { jit_unbox::<String>(value_bits) };
s.clone()
}
Some(HK_ARRAY) => {
"[<array>]".to_string()
}
Some(HK_OK) => {
let inner = unsafe { *jit_unbox::<u64>(value_bits) };
format!("Ok({})", format_value_word(inner))
}
Some(HK_ERR) => {
let inner = unsafe { *jit_unbox::<u64>(value_bits) };
format!("Err({})", format_value_word(inner))
}
Some(HK_SOME) => {
let inner = unsafe { *jit_unbox::<u64>(value_bits) };
format!("Some({})", format_value_word(inner))
}
_ => "[object]".to_string(),
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_i64(value: i64) {
println!("{}", value);
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_u64(value: u64) {
println!("{}", value);
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_f64(value: f64) {
let registry = std::sync::Arc::new(
shape_runtime::type_schema::TypeSchemaRegistry::default(),
);
let formatter = shape_vm::executor::printing::ValueFormatter::new(®istry);
let kinded = shape_value::KindedSlot::from_number(value);
println!("{}", formatter.format_kinded(&kinded));
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_bool(value: u8) {
println!("{}", value != 0);
}
fn registry_from_ctx(
ctx_ptr: *const crate::context::JITContext,
) -> std::sync::Arc<shape_runtime::type_schema::TypeSchemaRegistry> {
if ctx_ptr.is_null() {
return std::sync::Arc::new(
shape_runtime::type_schema::TypeSchemaRegistry::default(),
);
}
let ctx = unsafe { &*ctx_ptr };
if ctx.exec_context_ptr.is_null() {
return std::sync::Arc::new(
shape_runtime::type_schema::TypeSchemaRegistry::default(),
);
}
let exec_ctx = unsafe {
&*(ctx.exec_context_ptr as *const shape_runtime::context::ExecutionContext)
};
std::sync::Arc::clone(exec_ctx.type_schema_registry())
}
#[inline]
fn is_jit_null_sentinel(bits: u64) -> bool {
super::value_ffi::is_none_tag(bits)
}
fn print_kinded_inner(
ctx_ptr: *const crate::context::JITContext,
bits: u64,
kind: shape_value::NativeKind,
) {
if is_jit_null_sentinel(bits) {
println!("None");
return;
}
let registry = registry_from_ctx(ctx_ptr);
let formatter = shape_vm::executor::printing::ValueFormatter::new(®istry);
let slot = shape_value::ValueSlot::from_raw(bits);
let kinded = shape_value::KindedSlot::new(slot, kind);
let rendered = formatter.format_kinded(&kinded);
std::mem::forget(kinded);
println!("{}", rendered);
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_str(
ctx_ptr: *const crate::context::JITContext,
bits: u64,
) {
print_kinded_inner(ctx_ptr, bits, shape_value::NativeKind::String);
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_typed_object(
ctx_ptr: *const crate::context::JITContext,
bits: u64,
) {
use shape_value::heap_value::HeapKind;
print_kinded_inner(
ctx_ptr,
bits,
shape_value::NativeKind::Ptr(HeapKind::TypedObject),
);
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_option(
ctx_ptr: *const crate::context::JITContext,
bits: u64,
) {
use shape_value::heap_value::HeapKind;
print_kinded_inner(
ctx_ptr,
bits,
shape_value::NativeKind::Ptr(HeapKind::Option),
);
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_result(
ctx_ptr: *const crate::context::JITContext,
bits: u64,
) {
use shape_value::heap_value::HeapKind;
print_kinded_inner(
ctx_ptr,
bits,
shape_value::NativeKind::Ptr(HeapKind::Result),
);
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_char(value: u32) {
match char::from_u32(value) {
Some(c) => println!("{}", c),
None => println!("<invalid-char:0x{:x}>", value),
}
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_mutex(
ctx_ptr: *const crate::context::JITContext,
bits: u64,
) {
use shape_value::heap_value::HeapKind;
print_kinded_inner(
ctx_ptr,
bits,
shape_value::NativeKind::Ptr(HeapKind::Mutex),
);
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_atomic(
ctx_ptr: *const crate::context::JITContext,
bits: u64,
) {
use shape_value::heap_value::HeapKind;
print_kinded_inner(
ctx_ptr,
bits,
shape_value::NativeKind::Ptr(HeapKind::Atomic),
);
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_lazy(
ctx_ptr: *const crate::context::JITContext,
bits: u64,
) {
use shape_value::heap_value::HeapKind;
print_kinded_inner(
ctx_ptr,
bits,
shape_value::NativeKind::Ptr(HeapKind::Lazy),
);
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_channel(
ctx_ptr: *const crate::context::JITContext,
bits: u64,
) {
use shape_value::heap_value::HeapKind;
print_kinded_inner(
ctx_ptr,
bits,
shape_value::NativeKind::Ptr(HeapKind::Channel),
);
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_hashmap(
ctx_ptr: *const crate::context::JITContext,
bits: u64,
) {
use shape_value::heap_value::HeapKind;
print_kinded_inner(
ctx_ptr,
bits,
shape_value::NativeKind::Ptr(HeapKind::HashMap),
);
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_hashset(
ctx_ptr: *const crate::context::JITContext,
bits: u64,
) {
use shape_value::heap_value::HeapKind;
print_kinded_inner(
ctx_ptr,
bits,
shape_value::NativeKind::Ptr(HeapKind::HashSet),
);
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_deque(
ctx_ptr: *const crate::context::JITContext,
bits: u64,
) {
use shape_value::heap_value::HeapKind;
print_kinded_inner(
ctx_ptr,
bits,
shape_value::NativeKind::Ptr(HeapKind::Deque),
);
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_priority_queue(
ctx_ptr: *const crate::context::JITContext,
bits: u64,
) {
use shape_value::heap_value::HeapKind;
print_kinded_inner(
ctx_ptr,
bits,
shape_value::NativeKind::Ptr(HeapKind::PriorityQueue),
);
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_range(
ctx_ptr: *const crate::context::JITContext,
bits: u64,
) {
use shape_value::heap_value::HeapKind;
print_kinded_inner(
ctx_ptr,
bits,
shape_value::NativeKind::Ptr(HeapKind::Range),
);
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_iterator(
ctx_ptr: *const crate::context::JITContext,
bits: u64,
) {
use shape_value::heap_value::HeapKind;
print_kinded_inner(
ctx_ptr,
bits,
shape_value::NativeKind::Ptr(HeapKind::Iterator),
);
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_print_typed_array(
ctx_ptr: *const crate::context::JITContext,
bits: u64,
) {
if bits == 0 {
println!("None");
return;
}
let registry = registry_from_ctx(ctx_ptr);
let formatter = shape_vm::executor::printing::ValueFormatter::new(®istry);
let slot = shape_value::ValueSlot::from_raw(bits);
let kinded = shape_value::KindedSlot::new(
slot,
shape_value::NativeKind::Ptr(shape_value::HeapKind::TypedArray),
);
let rendered = formatter.format_kinded(&kinded);
std::mem::forget(kinded);
println!("{}", rendered);
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_string_concat(
a_bits: u64,
a_kind_code: u8,
b_bits: u64,
b_kind_code: u8,
) -> u64 {
use super::stack_kind_code;
use shape_value::NativeKind;
use std::sync::Arc;
fn consume_operand(bits: u64, kind_code: u8, func_name: &str) -> String {
match stack_kind_code::decode(kind_code) {
Some(NativeKind::String) => {
if bits == 0 {
return String::new();
}
let arc = unsafe { Arc::<String>::from_raw(bits as *const String) };
let out = (*arc).clone();
drop(arc);
out
}
Some(NativeKind::Int64) | Some(NativeKind::UInt64)
| Some(NativeKind::IntSize) | Some(NativeKind::UIntSize) => {
format!("{}", bits as i64)
}
Some(NativeKind::Int32) | Some(NativeKind::UInt32) => {
format!("{}", bits as i32)
}
Some(NativeKind::Int16) | Some(NativeKind::UInt16) => {
format!("{}", bits as i16)
}
Some(NativeKind::Int8) | Some(NativeKind::UInt8) => {
format!("{}", bits as i8)
}
Some(NativeKind::Float64) => {
let n = f64::from_bits(bits);
if n.is_finite() && n == n.trunc() && n.abs() < 1e15 {
format!("{}", n as i64)
} else {
format!("{}", n)
}
}
Some(NativeKind::Float32) => {
let n = f32::from_bits(bits as u32);
format!("{}", n)
}
Some(NativeKind::Bool) => {
if (bits as u8) != 0 { "true".to_string() } else { "false".to_string() }
}
Some(NativeKind::Char) => {
let cp = bits as u32;
match char::from_u32(cp) {
Some(c) => c.to_string(),
None => String::new(),
}
}
Some(other) => {
tracing::debug!(
target: "shape_jit",
func_name,
kind_code,
?other,
"SURFACE: jit_string_concat operand kind is non-scalar / non-String. \
ADR-006 \u{a7}2.7.7 #9 \u{2014} MIR f-string interpolation does not \
yet format heap-arm operands. W15.2-LANG-7-FUP territory.",
);
format!("<{:?}>", other)
}
None => {
tracing::debug!(
target: "shape_jit",
func_name,
kind_code,
"SURFACE: jit_string_concat operand kind code is sentinel/unknown. \
ADR-006 \u{a7}2.7.7 #9 \u{2014} producer-site MIR kind classification gap.",
);
String::new()
}
}
}
let mut out = consume_operand(a_bits, a_kind_code, "jit_string_concat[a]");
out.push_str(&consume_operand(b_bits, b_kind_code, "jit_string_concat[b]"));
Arc::into_raw(Arc::new(out)) as u64
}
pub extern "C" fn jit_to_number(value_bits: u64) -> u64 {
if is_number(value_bits) {
return value_bits;
}
if value_bits == TAG_NULL {
return box_number(0.0);
}
if value_bits == TAG_BOOL_TRUE {
return box_number(1.0);
}
if value_bits == TAG_BOOL_FALSE {
return box_number(0.0);
}
let num = match heap_kind(value_bits) {
Some(HK_STRING) => {
let s = unsafe { jit_unbox::<String>(value_bits) };
s.parse::<f64>().unwrap_or(f64::NAN)
}
_ => f64::NAN,
};
box_number(num)
}
#[cfg(test)]
mod heap_arm_print_tests {
use super::*;
use shape_value::heap_value::{HeapKind, OptionData, ResultData, TypedObjectStorage};
use shape_value::{KindedSlot, NativeKind, ValueSlot};
use std::sync::Arc;
fn null_ctx() -> *const crate::context::JITContext {
std::ptr::null()
}
unsafe fn drop_arc_result(bits: u64) {
if bits != 0 {
let _ = unsafe { Arc::<ResultData>::from_raw(bits as *const ResultData) };
}
}
unsafe fn drop_arc_option(bits: u64) {
if bits != 0 {
let _ = unsafe { Arc::<OptionData>::from_raw(bits as *const OptionData) };
}
}
unsafe fn drop_arc_typed_object(bits: u64) {
if bits != 0 {
let _ = unsafe {
Arc::<TypedObjectStorage>::from_raw(bits as *const TypedObjectStorage)
};
}
}
unsafe fn drop_arc_string(bits: u64) {
if bits != 0 {
let _ = unsafe { Arc::<String>::from_raw(bits as *const String) };
}
}
fn vm_format(bits: u64, kind: NativeKind) -> String {
let registry = shape_runtime::type_schema::TypeSchemaRegistry::default();
let formatter = shape_vm::executor::printing::ValueFormatter::new(®istry);
let slot = ValueSlot::from_raw(bits);
let kinded = KindedSlot::new(slot, kind);
let out = formatter.format_kinded(&kinded);
std::mem::forget(kinded);
out
}
#[test]
fn print_option_some_int_payload_matches_vm() {
let payload = KindedSlot::new(ValueSlot::from_int(7), NativeKind::Int64);
let arc = Arc::new(OptionData::some(payload));
let bits = Arc::into_raw(arc) as u64;
let vm_render = vm_format(bits, NativeKind::Ptr(HeapKind::Option));
assert_eq!(vm_render, "Some(7)");
jit_print_option(null_ctx(), bits);
unsafe { drop_arc_option(bits) };
}
#[test]
fn print_option_none_matches_vm() {
let arc = Arc::new(OptionData::none());
let bits = Arc::into_raw(arc) as u64;
let vm_render = vm_format(bits, NativeKind::Ptr(HeapKind::Option));
assert_eq!(vm_render, "None");
jit_print_option(null_ctx(), bits);
unsafe { drop_arc_option(bits) };
}
#[test]
fn print_result_ok_int_payload_matches_vm() {
let payload = KindedSlot::new(ValueSlot::from_int(42), NativeKind::Int64);
let arc = Arc::new(ResultData::ok(payload));
let bits = Arc::into_raw(arc) as u64;
let vm_render = vm_format(bits, NativeKind::Ptr(HeapKind::Result));
assert_eq!(vm_render, "Ok(42)");
jit_print_result(null_ctx(), bits);
unsafe { drop_arc_result(bits) };
}
#[test]
fn print_result_err_int_payload_matches_vm() {
let payload = KindedSlot::new(ValueSlot::from_int(-1), NativeKind::Int64);
let arc = Arc::new(ResultData::err(payload));
let bits = Arc::into_raw(arc) as u64;
let vm_render = vm_format(bits, NativeKind::Ptr(HeapKind::Result));
assert_eq!(vm_render, "Err(-1)");
jit_print_result(null_ctx(), bits);
unsafe { drop_arc_result(bits) };
}
#[test]
fn print_str_arc_carrier_matches_vm() {
let arc = Arc::new("hello".to_string());
let bits = Arc::into_raw(arc) as u64;
let vm_render = vm_format(bits, NativeKind::String);
assert_eq!(vm_render, "hello");
jit_print_str(null_ctx(), bits);
unsafe { drop_arc_string(bits) };
}
#[test]
fn print_typed_object_arc_carrier_no_schema_renders_positional() {
let slots: Box<[ValueSlot]> =
vec![ValueSlot::from_int(3), ValueSlot::from_int(4)].into_boxed_slice();
let field_kinds: Arc<[NativeKind]> =
Arc::from(vec![NativeKind::Int64, NativeKind::Int64]);
let storage = TypedObjectStorage::new(
0xffff_ffff_ffff_ffff,
slots,
0,
field_kinds,
);
let arc = Arc::new(storage);
let bits = Arc::into_raw(arc) as u64;
let vm_render = vm_format(bits, NativeKind::Ptr(HeapKind::TypedObject));
assert_eq!(vm_render, "{_0: 3, _1: 4}");
jit_print_typed_object(null_ctx(), bits);
unsafe { drop_arc_typed_object(bits) };
}
#[test]
fn print_kinded_inner_null_ctx_uses_empty_registry() {
let slots: Box<[ValueSlot]> = vec![ValueSlot::from_bool(true)].into_boxed_slice();
let field_kinds: Arc<[NativeKind]> = Arc::from(vec![NativeKind::Bool]);
let storage = TypedObjectStorage::new(
0xdead_beef,
slots,
0,
field_kinds,
);
let arc = Arc::new(storage);
let bits = Arc::into_raw(arc) as u64;
jit_print_typed_object(null_ctx(), bits);
unsafe { drop_arc_typed_object(bits) };
}
#[test]
fn print_char_scalar_matches_vm() {
let codepoint: u32 = 'A' as u32;
let scalar_slot = ValueSlot::from_char('A');
let scalar_kinded = KindedSlot::new(scalar_slot, NativeKind::Char);
let registry = shape_runtime::type_schema::TypeSchemaRegistry::default();
let formatter = shape_vm::executor::printing::ValueFormatter::new(®istry);
let scalar_render = formatter.format_kinded(&scalar_kinded);
assert_eq!(scalar_render, "A");
let heap_slot = ValueSlot::from_char('A');
let heap_kinded =
KindedSlot::new(heap_slot, NativeKind::Ptr(HeapKind::Char));
let heap_render = formatter.format_kinded(&heap_kinded);
assert_eq!(heap_render, "A");
jit_print_char(codepoint);
}
#[test]
fn print_char_invalid_codepoint_renders_fallback() {
jit_print_char(0xD800);
}
#[test]
fn print_mutex_arc_carrier_matches_vm() {
use shape_value::heap_value::MutexData;
let inner_payload = KindedSlot::new(ValueSlot::from_int(42), NativeKind::Int64);
let arc = Arc::new(MutexData::new(inner_payload));
let bits = Arc::into_raw(arc) as u64;
let vm_render = vm_format(bits, NativeKind::Ptr(HeapKind::Mutex));
assert_eq!(vm_render, "<mutex>");
jit_print_mutex(null_ctx(), bits);
unsafe {
let _ = Arc::<MutexData>::from_raw(bits as *const MutexData);
}
}
#[test]
fn print_atomic_arc_carrier_matches_vm() {
use shape_value::heap_value::AtomicData;
let arc = Arc::new(AtomicData::new(7));
let bits = Arc::into_raw(arc) as u64;
let vm_render = vm_format(bits, NativeKind::Ptr(HeapKind::Atomic));
assert_eq!(vm_render, "<atomic:7>");
jit_print_atomic(null_ctx(), bits);
unsafe {
let _ = Arc::<AtomicData>::from_raw(bits as *const AtomicData);
}
}
#[test]
fn print_lazy_arc_carrier_pending_matches_vm() {
use shape_value::heap_value::LazyData;
let closure_kinded =
KindedSlot::new(ValueSlot::from_int(0), NativeKind::Int64);
let arc = Arc::new(LazyData::new(closure_kinded));
let bits = Arc::into_raw(arc) as u64;
let vm_render = vm_format(bits, NativeKind::Ptr(HeapKind::Lazy));
assert_eq!(vm_render, "<lazy:pending>");
jit_print_lazy(null_ctx(), bits);
unsafe {
let _ = Arc::<LazyData>::from_raw(bits as *const LazyData);
}
}
#[test]
fn print_channel_arc_carrier_matches_vm() {
use shape_value::heap_value::ChannelData;
let arc = Arc::new(ChannelData::new());
let bits = Arc::into_raw(arc) as u64;
let vm_render = vm_format(bits, NativeKind::Ptr(HeapKind::Channel));
assert_eq!(vm_render, "<channel:open:0>");
jit_print_channel(null_ctx(), bits);
unsafe {
let _ = Arc::<ChannelData>::from_raw(bits as *const ChannelData);
}
}
#[test]
fn print_hashmap_arc_carrier_empty_matches_vm() {
use shape_value::heap_value::{HashMapData, HashMapKindedRef};
let inner: HashMapData<i64> = HashMapData::new();
let kref = HashMapKindedRef::I64(Arc::new(inner));
let arc = Arc::new(kref);
let bits = Arc::into_raw(arc) as u64;
let vm_render = vm_format(bits, NativeKind::Ptr(HeapKind::HashMap));
assert_eq!(vm_render, "{}");
jit_print_hashmap(null_ctx(), bits);
unsafe {
let _ = Arc::<HashMapKindedRef>::from_raw(
bits as *const HashMapKindedRef,
);
}
}
#[test]
fn print_hashset_arc_carrier_matches_vm() {
use shape_value::heap_value::HashSetData;
let keys = vec![Arc::new("a".to_string()), Arc::new("b".to_string())];
let arc = Arc::new(HashSetData::from_keys(keys));
let bits = Arc::into_raw(arc) as u64;
let vm_render = vm_format(bits, NativeKind::Ptr(HeapKind::HashSet));
assert_eq!(vm_render, "{\"a\", \"b\"}");
jit_print_hashset(null_ctx(), bits);
unsafe {
let _ = Arc::<HashSetData>::from_raw(bits as *const HashSetData);
}
}
#[test]
fn print_deque_arc_carrier_empty_matches_vm() {
use shape_value::heap_value::DequeData;
let arc = Arc::new(DequeData::new());
let bits = Arc::into_raw(arc) as u64;
let vm_render = vm_format(bits, NativeKind::Ptr(HeapKind::Deque));
assert_eq!(vm_render, "Deque[]");
jit_print_deque(null_ctx(), bits);
unsafe {
let _ = Arc::<DequeData>::from_raw(bits as *const DequeData);
}
}
#[test]
fn print_priority_queue_arc_carrier_matches_vm() {
use shape_value::heap_value::PriorityQueueData;
let mut pq = PriorityQueueData::new();
pq.push(3);
pq.push(1);
pq.push(2);
let arc = Arc::new(pq);
let bits = Arc::into_raw(arc) as u64;
let vm_render =
vm_format(bits, NativeKind::Ptr(HeapKind::PriorityQueue));
assert_eq!(vm_render, "PriorityQueue[1, 3, 2]");
jit_print_priority_queue(null_ctx(), bits);
unsafe {
let _ = Arc::<PriorityQueueData>::from_raw(
bits as *const PriorityQueueData,
);
}
}
#[test]
fn print_range_arc_carrier_exclusive_matches_vm() {
use shape_value::heap_value::RangeData;
let arc = Arc::new(RangeData::exclusive(0, 10));
let bits = Arc::into_raw(arc) as u64;
let vm_render = vm_format(bits, NativeKind::Ptr(HeapKind::Range));
assert_eq!(vm_render, "0..10");
jit_print_range(null_ctx(), bits);
unsafe {
let _ = Arc::<RangeData>::from_raw(bits as *const RangeData);
}
}
#[test]
fn print_range_arc_carrier_inclusive_matches_vm() {
use shape_value::heap_value::RangeData;
let arc = Arc::new(RangeData::inclusive(0, 5));
let bits = Arc::into_raw(arc) as u64;
let vm_render = vm_format(bits, NativeKind::Ptr(HeapKind::Range));
assert_eq!(vm_render, "0..=5");
jit_print_range(null_ctx(), bits);
unsafe {
let _ = Arc::<RangeData>::from_raw(bits as *const RangeData);
}
}
#[test]
fn print_iterator_arc_carrier_matches_vm() {
use shape_value::iterator_state::{IteratorSource, IteratorState};
let src = IteratorSource::Range {
start: 0,
end: 10,
step: 1,
};
let arc = Arc::new(IteratorState::new(src));
let bits = Arc::into_raw(arc) as u64;
let vm_render = vm_format(bits, NativeKind::Ptr(HeapKind::Iterator));
assert_eq!(vm_render, "<iterator>");
jit_print_iterator(null_ctx(), bits);
unsafe {
let _ = Arc::<IteratorState>::from_raw(
bits as *const IteratorState,
);
}
}
}
#[cfg(test)]
mod jit_string_concat_w15_2_lang_7_tests {
use super::*;
use crate::ffi::stack_kind_code;
use std::sync::Arc;
fn make_string_arc_bits(s: &str) -> u64 {
Arc::into_raw(Arc::new(s.to_string())) as u64
}
unsafe fn adopt_string_arc_bits(bits: u64) -> String {
assert!(bits != 0, "expected non-null Arc<String> bits");
let arc = unsafe { Arc::<String>::from_raw(bits as *const String) };
let out = (*arc).clone();
drop(arc);
out
}
#[test]
fn string_plus_string_book_reproducer() {
let a = make_string_arc_bits("path: ");
let b = make_string_arc_bits("events.csv");
let result = jit_string_concat(
a,
stack_kind_code::C_STRING,
b,
stack_kind_code::C_STRING,
);
let out = unsafe { adopt_string_arc_bits(result) };
assert_eq!(out, "path: events.csv");
}
#[test]
fn returns_arc_string_carrier_shape_not_nanbox() {
let a = make_string_arc_bits("hello");
let b = make_string_arc_bits(" world");
let result = jit_string_concat(
a,
stack_kind_code::C_STRING,
b,
stack_kind_code::C_STRING,
);
let out = unsafe { adopt_string_arc_bits(result) };
assert_eq!(out, "hello world");
}
#[test]
fn empty_strings_concat_to_empty() {
let a = make_string_arc_bits("");
let b = make_string_arc_bits("");
let result = jit_string_concat(
a,
stack_kind_code::C_STRING,
b,
stack_kind_code::C_STRING,
);
let out = unsafe { adopt_string_arc_bits(result) };
assert_eq!(out, "");
}
#[test]
fn string_plus_int64_formats_int_inline() {
let a = make_string_arc_bits("x=");
let b_bits: u64 = 42i64 as u64;
let result = jit_string_concat(
a,
stack_kind_code::C_STRING,
b_bits,
stack_kind_code::C_INT64,
);
let out = unsafe { adopt_string_arc_bits(result) };
assert_eq!(out, "x=42");
}
#[test]
fn string_plus_bool_formats_bool_inline() {
let a = make_string_arc_bits("active=");
let b_bits: u64 = 1; let result = jit_string_concat(
a,
stack_kind_code::C_STRING,
b_bits,
stack_kind_code::C_BOOL,
);
let out = unsafe { adopt_string_arc_bits(result) };
assert_eq!(out, "active=true");
}
}
#[cfg(test)]
mod jit_print_f64_gamma_cp1_tests {
use super::*;
fn jit_render_f64(value: f64) -> String {
let registry = shape_runtime::type_schema::TypeSchemaRegistry::default();
let formatter = shape_vm::executor::printing::ValueFormatter::new(®istry);
let kinded = shape_value::KindedSlot::from_number(value);
formatter.format_kinded(&kinded)
}
#[test]
fn integer_valued_float_keeps_decimal_point() {
assert_eq!(jit_render_f64(3.0), "3.0");
assert_eq!(jit_render_f64(1.0), "1.0");
assert_eq!(jit_render_f64(100.0), "100.0");
jit_print_f64(3.0);
}
#[test]
fn fractional_float_renders_fraction() {
assert_eq!(jit_render_f64(3.5), "3.5");
assert_eq!(jit_render_f64(3.14), "3.14");
jit_print_f64(3.5);
}
#[test]
fn negative_integer_valued_float_keeps_decimal_point() {
assert_eq!(jit_render_f64(-2.0), "-2.0");
assert_eq!(jit_render_f64(-5.0), "-5.0");
jit_print_f64(-2.0);
}
#[test]
fn negative_fractional_float_renders_fraction() {
assert_eq!(jit_render_f64(-2.5), "-2.5");
jit_print_f64(-2.5);
}
#[test]
fn zero_renders_with_decimal_point() {
assert_eq!(jit_render_f64(0.0), "0.0");
jit_print_f64(0.0);
}
#[test]
fn very_large_float_renders_via_to_string() {
assert_eq!(jit_render_f64(1e20), 1e20_f64.to_string());
jit_print_f64(1e20);
}
#[test]
fn infinity_renders_word_form() {
assert_eq!(jit_render_f64(f64::INFINITY), "Infinity");
assert_eq!(jit_render_f64(f64::NEG_INFINITY), "-Infinity");
jit_print_f64(f64::INFINITY);
jit_print_f64(f64::NEG_INFINITY);
}
#[test]
fn nan_renders_word_form() {
assert_eq!(jit_render_f64(f64::NAN), "NaN");
jit_print_f64(f64::NAN);
}
}