use crate::context::JITContext;
use crate::ffi::jit_kinds::*;
use crate::ffi::value_ffi::*;
pub extern "C" fn jit_intrinsic_sum(series_bits: u64) -> u64 {
unsafe {
if let Some(data) = extract_column(series_bits) {
box_number(shape_runtime::columnar_aggregations::sum_f64_slice(data))
} else {
box_number(f64::NAN)
}
}
}
pub extern "C" fn jit_intrinsic_mean(series_bits: u64) -> u64 {
unsafe {
if let Some(data) = extract_column(series_bits) {
box_number(shape_runtime::columnar_aggregations::mean_f64_slice(data))
} else {
box_number(f64::NAN)
}
}
}
pub extern "C" fn jit_intrinsic_min(series_bits: u64) -> u64 {
unsafe {
if let Some(data) = extract_column(series_bits) {
box_number(shape_runtime::columnar_aggregations::min_f64_slice(data))
} else {
box_number(f64::NAN)
}
}
}
pub extern "C" fn jit_intrinsic_max(series_bits: u64) -> u64 {
unsafe {
if let Some(data) = extract_column(series_bits) {
box_number(shape_runtime::columnar_aggregations::max_f64_slice(data))
} else {
box_number(f64::NAN)
}
}
}
pub extern "C" fn jit_intrinsic_variance(series_bits: u64) -> u64 {
unsafe {
if let Some(data) = extract_column(series_bits) {
let mean = shape_runtime::columnar_aggregations::mean_f64_slice(data);
let n = data.len() as f64;
if n < 2.0 {
return box_number(f64::NAN);
}
let sum_sq: f64 = data.iter().map(|&x| (x - mean) * (x - mean)).sum();
box_number(sum_sq / (n - 1.0))
} else {
box_number(f64::NAN)
}
}
}
pub extern "C" fn jit_intrinsic_std(series_bits: u64) -> u64 {
let var_bits = jit_intrinsic_variance(series_bits);
if is_number(var_bits) {
let var = unbox_number(var_bits);
box_number(var.sqrt())
} else {
box_number(f64::NAN)
}
}
pub extern "C" fn jit_intrinsic_median(series_bits: u64) -> u64 {
unsafe {
if let Some(data) = extract_column(series_bits) {
let mut sorted: Vec<f64> = data.to_vec();
sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
let n = sorted.len();
if n == 0 {
return box_number(f64::NAN);
}
let median = if n % 2 == 0 {
(sorted[n / 2 - 1] + sorted[n / 2]) / 2.0
} else {
sorted[n / 2]
};
box_number(median)
} else {
box_number(f64::NAN)
}
}
}
pub extern "C" fn jit_intrinsic_percentile(series_bits: u64, percentile_bits: u64) -> u64 {
unsafe {
if let Some(data) = extract_column(series_bits) {
let pct = if is_number(percentile_bits) {
unbox_number(percentile_bits)
} else {
return box_number(f64::NAN);
};
let mut sorted: Vec<f64> = data.to_vec();
sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
let n = sorted.len();
if n == 0 {
return box_number(f64::NAN);
}
let idx = (pct / 100.0 * (n - 1) as f64).round() as usize;
let idx = idx.min(n - 1);
box_number(sorted[idx])
} else {
box_number(f64::NAN)
}
}
}
pub extern "C" fn jit_intrinsic_correlation(a_bits: u64, b_bits: u64) -> u64 {
unsafe {
if let (Some(a), Some(b)) = (extract_column(a_bits), extract_column(b_bits)) {
if a.len() != b.len() || a.is_empty() {
return box_number(f64::NAN);
}
box_number(shape_runtime::simd_statistics::correlation(a, b))
} else {
box_number(f64::NAN)
}
}
}
pub extern "C" fn jit_intrinsic_covariance(a_bits: u64, b_bits: u64) -> u64 {
unsafe {
if let (Some(a), Some(b)) = (extract_column(a_bits), extract_column(b_bits)) {
if a.len() != b.len() || a.is_empty() {
return box_number(f64::NAN);
}
box_number(shape_runtime::simd_statistics::covariance(a, b))
} else {
box_number(f64::NAN)
}
}
}
pub extern "C" fn jit_series_rolling_min(series_bits: u64, window_bits: u64) -> u64 {
unsafe {
if let Some(data) = extract_column(series_bits) {
let window = if is_number(window_bits) {
unbox_number(window_bits) as usize
} else {
return TAG_NULL;
};
let result = shape_runtime::simd_rolling::rolling_min_deque(data, window);
box_column_result(result)
} else {
TAG_NULL
}
}
}
pub extern "C" fn jit_series_rolling_max(series_bits: u64, window_bits: u64) -> u64 {
unsafe {
if let Some(data) = extract_column(series_bits) {
let window = if is_number(window_bits) {
unbox_number(window_bits) as usize
} else {
return TAG_NULL;
};
let result = shape_runtime::simd_rolling::rolling_max_deque(data, window);
box_column_result(result)
} else {
TAG_NULL
}
}
}
pub extern "C" fn jit_series_ema(series_bits: u64, period_bits: u64) -> u64 {
unsafe {
if let Some(data) = extract_column(series_bits) {
let period = if is_number(period_bits) {
unbox_number(period_bits) as usize
} else {
return TAG_NULL;
};
if period == 0 || data.is_empty() {
return TAG_NULL;
}
let alpha = 2.0 / (period as f64 + 1.0);
let mut result = Vec::with_capacity(data.len());
result.push(data[0]);
for i in 1..data.len() {
let ema = alpha * data[i] + (1.0 - alpha) * result[i - 1];
result.push(ema);
}
box_column_result(result)
} else {
TAG_NULL
}
}
}
pub extern "C" fn jit_series_diff(series_bits: u64, _periods_bits: u64) -> u64 {
unsafe {
if let Some(data) = extract_column(series_bits) {
let result = shape_runtime::simd_rolling::diff(data);
box_column_result(result)
} else {
TAG_NULL
}
}
}
pub extern "C" fn jit_series_pct_change(series_bits: u64, _periods_bits: u64) -> u64 {
unsafe {
if let Some(data) = extract_column(series_bits) {
let result = shape_runtime::simd_rolling::pct_change(data);
box_column_result(result)
} else {
TAG_NULL
}
}
}
pub extern "C" fn jit_series_cumprod(series_bits: u64) -> u64 {
unsafe {
if let Some(data) = extract_column(series_bits) {
let mut result = Vec::with_capacity(data.len());
let mut acc = 1.0;
for &v in data {
acc *= v;
result.push(acc);
}
box_column_result(result)
} else {
TAG_NULL
}
}
}
pub extern "C" fn jit_series_clip(series_bits: u64, min_bits: u64, max_bits: u64) -> u64 {
unsafe {
if let Some(data) = extract_column(series_bits) {
let min_val = if is_number(min_bits) {
unbox_number(min_bits)
} else {
return TAG_NULL;
};
let max_val = if is_number(max_bits) {
unbox_number(max_bits)
} else {
return TAG_NULL;
};
let mut result = data.to_vec();
shape_runtime::simd_rolling::clip(&mut result, min_val, max_val);
box_column_result(result)
} else {
TAG_NULL
}
}
}
pub extern "C" fn jit_series_broadcast(value_bits: u64, len_bits: u64) -> u64 {
let value = if is_number(value_bits) {
unbox_number(value_bits)
} else {
return TAG_NULL;
};
let len = if is_number(len_bits) {
unbox_number(len_bits) as usize
} else {
return TAG_NULL;
};
let result = vec![value; len];
box_column_result(result)
}
pub extern "C" fn jit_series_highest_index(series_bits: u64) -> u64 {
unsafe {
if let Some(data) = extract_column(series_bits) {
if data.is_empty() {
return TAG_NULL;
}
let mut max_idx = 0;
let mut max_val = f64::NEG_INFINITY;
for (i, &v) in data.iter().enumerate() {
if v > max_val {
max_val = v;
max_idx = i;
}
}
box_number(max_idx as f64)
} else {
TAG_NULL
}
}
}
pub extern "C" fn jit_series_lowest_index(series_bits: u64) -> u64 {
unsafe {
if let Some(data) = extract_column(series_bits) {
if data.is_empty() {
return TAG_NULL;
}
let mut min_idx = 0;
let mut min_val = f64::INFINITY;
for (i, &v) in data.iter().enumerate() {
if v < min_val {
min_val = v;
min_idx = i;
}
}
box_number(min_idx as f64)
} else {
TAG_NULL
}
}
}
pub extern "C" fn jit_time_current_time(ctx: *mut JITContext) -> u64 {
unsafe {
if ctx.is_null() {
return TAG_NULL;
}
let ctx_ref = &*ctx;
if !ctx_ref.timestamps_ptr.is_null() && ctx_ref.current_row < ctx_ref.row_count {
let ts_micros = *ctx_ref.timestamps_ptr.add(ctx_ref.current_row);
if ts_micros != 0 {
let ts_seconds = ts_micros / 1_000_000;
return unified_box(HK_TIME, ts_seconds);
}
}
if !ctx_ref.exec_context_ptr.is_null() {
use shape_runtime::context::ExecutionContext;
let exec_ctx = &*(ctx_ref.exec_context_ptr as *const ExecutionContext);
if let Some(ref_dt) = exec_ctx.get_reference_datetime() {
let ts = ref_dt.timestamp();
return unified_box(HK_TIME, ts);
}
}
TAG_NULL
}
}
pub extern "C" fn jit_time_symbol(ctx: *mut JITContext) -> u64 {
unsafe {
if ctx.is_null() {
return TAG_NULL;
}
let ctx_ref = &*ctx;
if !ctx_ref.exec_context_ptr.is_null() {
use shape_runtime::context::ExecutionContext;
let exec_ctx = &*(ctx_ref.exec_context_ptr as *const ExecutionContext);
if let Ok(id) = exec_ctx.get_current_id() {
return box_string(id);
}
}
TAG_NULL
}
}
pub extern "C" fn jit_time_last_row(ctx: *mut JITContext) -> u64 {
unsafe {
if ctx.is_null() {
return TAG_NULL;
}
let ctx_ref = &*ctx;
if ctx_ref.row_count > 0 && !ctx_ref.column_ptrs.is_null() {
let last_idx = ctx_ref.row_count - 1;
return box_data_row(last_idx);
}
TAG_NULL
}
}
pub extern "C" fn jit_time_range(_start_bits: u64, _end_bits: u64, _step_bits: u64) -> u64 {
todo!(
"phase-2c §2.7.4 / W10 jit-playbook §5: JitArray rebuild — \
jit_time_range. Result allocation needs `TypedArray<...>` \
of HeapKind::Time elements per ADR-006 §2.7.6/Q8."
)
}