use crate::context::ExecutionContext;
use parking_lot::RwLock;
use shape_ast::error::{Result, ShapeError};
use shape_value::KindedSlot;
use std::collections::HashMap;
use std::sync::Arc;
pub mod array_transforms;
pub mod convolution;
pub mod distributions;
pub mod fft;
pub mod math;
pub mod matrix;
pub mod matrix_kernels;
pub mod random;
pub mod recurrence;
pub mod rolling;
pub mod statistical;
pub mod stochastic;
pub mod vector;
pub type IntrinsicFn = fn(&[KindedSlot], &mut ExecutionContext) -> Result<KindedSlot>;
#[derive(Clone)]
pub struct IntrinsicsRegistry {
functions: Arc<RwLock<HashMap<String, IntrinsicFn>>>,
}
impl std::fmt::Debug for IntrinsicsRegistry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("IntrinsicsRegistry")
.field("num_intrinsics", &self.functions.read().len())
.finish()
}
}
impl IntrinsicsRegistry {
pub fn new() -> Self {
let mut functions = HashMap::new();
Self::register_math_intrinsics(&mut functions);
Self::register_rolling_intrinsics(&mut functions);
Self::register_series_intrinsics(&mut functions);
Self::register_recurrence_intrinsics(&mut functions);
Self {
functions: Arc::new(RwLock::new(functions)),
}
}
pub fn register(&self, name: &str, func: IntrinsicFn) {
let full_name = if name.starts_with("__intrinsic_") {
name.to_string()
} else {
format!("__intrinsic_{}", name)
};
self.functions.write().insert(full_name, func);
}
pub fn call(
&self,
name: &str,
args: &[KindedSlot],
ctx: &mut ExecutionContext,
) -> Result<KindedSlot> {
let functions = self.functions.read();
let func = functions
.get(name)
.ok_or_else(|| ShapeError::RuntimeError {
message: format!(
"Unknown intrinsic: {}. Available intrinsics: {:?}",
name,
functions.keys().take(5).collect::<Vec<_>>()
),
location: None,
})?;
func(args, ctx)
}
pub fn is_intrinsic(&self, name: &str) -> bool {
self.functions.read().contains_key(name)
}
pub fn list_intrinsics(&self) -> Vec<String> {
self.functions.read().keys().cloned().collect()
}
fn register_math_intrinsics(functions: &mut HashMap<String, IntrinsicFn>) {
functions.insert("__intrinsic_min".to_string(), math::intrinsic_min);
functions.insert("__intrinsic_max".to_string(), math::intrinsic_max);
functions.insert(
"__intrinsic_char_code".to_string(),
math::intrinsic_char_code,
);
functions.insert(
"__intrinsic_bspline2_3d_batch".to_string(),
math::intrinsic_bspline2_3d_batch,
);
}
fn register_rolling_intrinsics(functions: &mut HashMap<String, IntrinsicFn>) {
functions.insert(
"__intrinsic_rolling_sum".to_string(),
rolling::intrinsic_rolling_sum,
);
functions.insert(
"__intrinsic_rolling_min".to_string(),
rolling::intrinsic_rolling_min,
);
functions.insert(
"__intrinsic_rolling_max".to_string(),
rolling::intrinsic_rolling_max,
);
}
fn register_series_intrinsics(functions: &mut HashMap<String, IntrinsicFn>) {
functions.insert(
"__intrinsic_diff".to_string(),
array_transforms::intrinsic_diff,
);
functions.insert(
"__intrinsic_cumsum".to_string(),
array_transforms::intrinsic_cumsum,
);
}
fn register_recurrence_intrinsics(functions: &mut HashMap<String, IntrinsicFn>) {
functions.insert(
"__intrinsic_linear_recurrence".to_string(),
recurrence::intrinsic_linear_recurrence,
);
}
}
impl Default for IntrinsicsRegistry {
fn default() -> Self {
Self::new()
}
}
fn deferred(label: &str) -> ShapeError {
ShapeError::RuntimeError {
message: format!(
"{}: pending Phase 2c intrinsic kind threading — see ADR-006 §2.7.4",
label
),
location: None,
}
}
pub fn extract_f64(slot: &KindedSlot, _label: &str) -> Result<f64> {
Ok(slot.slot().as_f64())
}
pub fn extract_usize(slot: &KindedSlot, _label: &str) -> Result<usize> {
Ok(slot.slot().as_i64().max(0) as usize)
}
pub fn extract_f64_array(_slot: &KindedSlot, label: &str) -> Result<Vec<f64>> {
Err(deferred(&format!("{} (extract_f64_array)", label)))
}
pub fn extract_str<'a>(_slot: &'a KindedSlot, label: &str) -> Result<&'a str> {
Err(deferred(&format!("{} (extract_str)", label)))
}
pub fn f64_vec_to_nb_array(_data: Vec<f64>) -> KindedSlot {
KindedSlot::none()
}
pub fn f64_vec_to_float_array(_data: Vec<f64>) -> KindedSlot {
KindedSlot::none()
}
pub fn i64_vec_to_nb_int_array(_data: Vec<i64>) -> KindedSlot {
KindedSlot::none()
}
pub fn try_extract_i64_slice(_slot: &KindedSlot) -> Option<&[i64]> {
None
}
pub fn option_i64_vec_to_nb(_data: Vec<Option<i64>>) -> KindedSlot {
KindedSlot::none()
}