use crate::module_exports::ModuleContext;
use crate::typed_module_exports::TypedReturn;
use shape_value::NativeKind;
use std::sync::Arc;
pub trait FromSlot: Sized {
const NATIVE_KIND: NativeKind;
fn from_slot(bits: u64) -> Self;
}
pub trait ToSlot {
const NATIVE_KIND: NativeKind;
fn to_slot(self) -> u64;
}
#[derive(Debug, Clone, PartialEq)]
pub enum MarshalError {
ArgCount { expected: usize, got: usize },
Body(String),
}
impl std::fmt::Display for MarshalError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MarshalError::ArgCount { expected, got } => {
write!(f, "expected {} arg(s), got {}", expected, got)
}
MarshalError::Body(msg) => f.write_str(msg),
}
}
}
impl std::error::Error for MarshalError {}
impl From<MarshalError> for String {
fn from(e: MarshalError) -> Self {
e.to_string()
}
}
impl FromSlot for i64 {
const NATIVE_KIND: NativeKind = NativeKind::Int64;
#[inline]
fn from_slot(bits: u64) -> Self {
bits as i64
}
}
impl FromSlot for f64 {
const NATIVE_KIND: NativeKind = NativeKind::Float64;
#[inline]
fn from_slot(bits: u64) -> Self {
f64::from_bits(bits)
}
}
impl FromSlot for Option<f64> {
const NATIVE_KIND: NativeKind = NativeKind::NullableFloat64;
#[inline]
fn from_slot(bits: u64) -> Self {
let v = f64::from_bits(bits);
if v.is_nan() {
None
} else {
Some(v)
}
}
}
impl FromSlot for bool {
const NATIVE_KIND: NativeKind = NativeKind::Bool;
#[inline]
fn from_slot(bits: u64) -> Self {
bits != 0
}
}
impl FromSlot for Arc<String> {
const NATIVE_KIND: NativeKind = NativeKind::String;
#[inline]
fn from_slot(bits: u64) -> Self {
let ptr = bits as *const String;
unsafe {
Arc::increment_strong_count(ptr);
Arc::from_raw(ptr)
}
}
}
impl ToSlot for i64 {
const NATIVE_KIND: NativeKind = NativeKind::Int64;
#[inline]
fn to_slot(self) -> u64 {
self as u64
}
}
impl ToSlot for f64 {
const NATIVE_KIND: NativeKind = NativeKind::Float64;
#[inline]
fn to_slot(self) -> u64 {
self.to_bits()
}
}
impl ToSlot for bool {
const NATIVE_KIND: NativeKind = NativeKind::Bool;
#[inline]
fn to_slot(self) -> u64 {
self as u64
}
}
impl ToSlot for Arc<String> {
const NATIVE_KIND: NativeKind = NativeKind::String;
#[inline]
fn to_slot(self) -> u64 {
Arc::into_raw(self) as u64
}
}
impl FromSlot for Arc<shape_value::DataTable>
where
Self: Sized,
{
const NATIVE_KIND: NativeKind =
NativeKind::Ptr(shape_value::HeapKind::DataTable);
#[inline]
fn from_slot(bits: u64) -> Self {
let ptr = bits as *const shape_value::HeapValue;
unsafe {
Arc::increment_strong_count(ptr);
let arc_hv = Arc::from_raw(ptr);
match &*arc_hv {
shape_value::HeapValue::DataTable(arc_dt) => Arc::clone(arc_dt),
other => panic!(
"FromSlot<Arc<DataTable>>: slot bits decoded to HeapValue::{:?}, \
not DataTable. Marshal kind contract violated by caller.",
other.kind()
),
}
}
}
}
impl ToSlot for Arc<shape_value::DataTable> {
const NATIVE_KIND: NativeKind =
NativeKind::Ptr(shape_value::HeapKind::DataTable);
#[inline]
fn to_slot(self) -> u64 {
let hv = Arc::new(shape_value::HeapValue::DataTable(self));
Arc::into_raw(hv) as u64
}
}
impl FromSlot for Arc<shape_value::heap_value::IoHandleData>
where
Self: Sized,
{
const NATIVE_KIND: NativeKind =
NativeKind::Ptr(shape_value::HeapKind::IoHandle);
#[inline]
fn from_slot(bits: u64) -> Self {
let ptr = bits as *const shape_value::HeapValue;
unsafe {
Arc::increment_strong_count(ptr);
let arc_hv = Arc::from_raw(ptr);
match &*arc_hv {
shape_value::HeapValue::IoHandle(arc_io) => Arc::clone(arc_io),
other => panic!(
"FromSlot<Arc<IoHandleData>>: slot bits decoded to HeapValue::{:?}, \
not IoHandle. Marshal kind contract violated by caller.",
other.kind()
),
}
}
}
}
impl ToSlot for Arc<shape_value::heap_value::IoHandleData> {
const NATIVE_KIND: NativeKind =
NativeKind::Ptr(shape_value::HeapKind::IoHandle);
#[inline]
fn to_slot(self) -> u64 {
let hv = Arc::new(shape_value::HeapValue::IoHandle(self));
Arc::into_raw(hv) as u64
}
}
impl FromSlot for Vec<u8> {
const NATIVE_KIND: NativeKind =
NativeKind::Ptr(shape_value::HeapKind::TypedArray);
#[inline]
fn from_slot(bits: u64) -> Self {
let arr = bits as usize as *const shape_value::v2::typed_array::TypedArray<u8>;
if arr.is_null() {
return Vec::new();
}
unsafe {
shape_value::v2::typed_array::TypedArray::<u8>::as_slice(arr).to_vec()
}
}
}
impl FromSlot for Vec<i64> {
const NATIVE_KIND: NativeKind =
NativeKind::Ptr(shape_value::HeapKind::TypedArray);
#[inline]
fn from_slot(bits: u64) -> Self {
let arr = bits as usize as *const shape_value::v2::typed_array::TypedArray<i64>;
if arr.is_null() {
return Vec::new();
}
unsafe {
shape_value::v2::typed_array::TypedArray::<i64>::as_slice(arr).to_vec()
}
}
}
impl FromSlot for Vec<Arc<String>> {
const NATIVE_KIND: NativeKind =
NativeKind::Ptr(shape_value::HeapKind::TypedArray);
#[inline]
fn from_slot(bits: u64) -> Self {
let arr = bits as usize
as *const shape_value::v2::typed_array::TypedArray<
*const shape_value::v2::string_obj::StringObj,
>;
if arr.is_null() {
return Vec::new();
}
unsafe {
let slice = shape_value::v2::typed_array::TypedArray::<
*const shape_value::v2::string_obj::StringObj,
>::as_slice(arr);
slice
.iter()
.map(|&p| {
Arc::new(
shape_value::v2::string_obj::StringObj::as_str(p).to_owned(),
)
})
.collect()
}
}
}
impl FromSlot for Vec<Arc<shape_value::heap_value::HeapValue>> {
const NATIVE_KIND: NativeKind =
NativeKind::Ptr(shape_value::HeapKind::TypedArray);
#[inline]
fn from_slot(_bits: u64) -> Self {
panic!(
"FromSlot<Vec<Arc<HeapValue>>>: V3-S5 ckpt-5-prime²c SURFACE — \
the polymorphic Vec<Arc<HeapValue>> marshal path needs a \
per-element-T dispatcher over the v2-raw *mut TypedArray<T> \
carrier. Round 2 `Vec<Arc<HeapValue>>` rewire follow-up \
(pairs with from_typed_array_<T> constructor wave). \
ADR-006 §2.7.24 Q25.A SUPERSEDED."
)
}
}
impl ToSlot for Vec<Arc<String>> {
const NATIVE_KIND: NativeKind =
NativeKind::Ptr(shape_value::HeapKind::TypedArray);
#[inline]
fn to_slot(self) -> u64 {
let elems: Vec<*const shape_value::v2::string_obj::StringObj> = self
.into_iter()
.map(|s| {
shape_value::v2::string_obj::StringObj::new(s.as_str())
as *const shape_value::v2::string_obj::StringObj
})
.collect();
let arr = shape_value::v2::typed_array::TypedArray::<
*const shape_value::v2::string_obj::StringObj,
>::from_slice(&elems);
arr as usize as u64
}
}
impl ToSlot for Vec<Arc<shape_value::heap_value::HeapValue>> {
const NATIVE_KIND: NativeKind =
NativeKind::Ptr(shape_value::HeapKind::TypedArray);
#[inline]
fn to_slot(self) -> u64 {
panic!(
"ToSlot<Vec<Arc<HeapValue>>>: V3-S5 ckpt-5-prime²c SURFACE — \
polymorphic Vec<Arc<HeapValue>> projection needs a per-element-T \
dispatcher over the v2-raw *mut TypedArray<T> carrier (mirror \
of the deleted build_specialized_from_heap_arcs). Round 2 \
`Vec<Arc<HeapValue>>` rewire follow-up. ADR-006 §2.7.24 Q25.A \
SUPERSEDED."
)
}
}
impl FromSlot for Vec<(Arc<String>, Arc<String>)> {
const NATIVE_KIND: NativeKind =
NativeKind::Ptr(shape_value::HeapKind::HashMap);
#[inline]
fn from_slot(bits: u64) -> Self {
let ptr = bits as *const shape_value::HeapValue;
unsafe {
Arc::increment_strong_count(ptr);
let arc_hv = Arc::from_raw(ptr);
match &*arc_hv {
shape_value::HeapValue::HashMap(kref) => {
use shape_value::heap_value::HashMapKindedRef;
match kref {
HashMapKindedRef::String(arc) => {
let n = arc.len();
let mut out: Vec<(Arc<String>, Arc<String>)> =
Vec::with_capacity(n);
for i in 0..n {
let key = unsafe {
let ptr = shape_value::v2::typed_array::TypedArray::get_unchecked(
arc.keys, i as u32,
);
Arc::new(
shape_value::v2::string_obj::StringObj::as_str(ptr)
.to_owned(),
)
};
let val = unsafe {
let v_ptr: *const shape_value::v2::string_obj::StringObj =
*(*arc.values).data.add(i);
Arc::new(
shape_value::v2::string_obj::StringObj::as_str(v_ptr)
.to_owned(),
)
};
out.push((key, val));
}
out
}
other => panic!(
"FromSlot<Vec<(Arc<String>, Arc<String>)>>: HashMap V \
variant {:?} not supported — marshal contract requires \
V=String. ADR-006 §2.7.24 Q25.B SUPERSEDED.",
other.values_kind()
),
}
}
other => panic!(
"FromSlot<Vec<(Arc<String>, Arc<String>)>>: slot bits decoded to \
HeapValue::{:?}, not HashMap. Marshal kind contract violated by caller.",
other.kind()
),
}
}
}
}
impl FromSlot for Vec<(Arc<String>, Arc<shape_value::heap_value::HeapValue>)> {
const NATIVE_KIND: NativeKind =
NativeKind::Ptr(shape_value::HeapKind::HashMap);
#[inline]
fn from_slot(bits: u64) -> Self {
let ptr = bits as *const shape_value::HeapValue;
unsafe {
Arc::increment_strong_count(ptr);
let arc_hv = Arc::from_raw(ptr);
match &*arc_hv {
shape_value::HeapValue::HashMap(kref) => {
use shape_value::heap_value::{HashMapKindedRef, HeapValue};
let n = kref.len();
let mut out: Vec<(Arc<String>, Arc<HeapValue>)> = Vec::with_capacity(n);
let keys_ptr = match kref {
HashMapKindedRef::I64(arc) => arc.keys,
HashMapKindedRef::F64(arc) => arc.keys,
HashMapKindedRef::Bool(arc) => arc.keys,
HashMapKindedRef::Char(arc) => arc.keys,
HashMapKindedRef::String(arc) => arc.keys,
HashMapKindedRef::Decimal(arc) => arc.keys,
HashMapKindedRef::TypedObject(arc) => arc.keys,
HashMapKindedRef::TraitObject(arc) => arc.keys,
HashMapKindedRef::HashMap(arc) => arc.keys,
};
for i in 0..n {
let key = unsafe {
let ptr = shape_value::v2::typed_array::TypedArray::get_unchecked(
keys_ptr, i as u32,
);
Arc::new(
shape_value::v2::string_obj::StringObj::as_str(ptr)
.to_owned(),
)
};
let value: Arc<HeapValue> = match kref {
HashMapKindedRef::I64(arc) => {
let v: i64 = unsafe { *(*arc.values).data.add(i) };
Arc::new(HeapValue::BigInt(Arc::new(v)))
}
HashMapKindedRef::F64(_) => {
panic!(
"FromSlot<Vec<(Arc<String>, Arc<HeapValue>)>>: \
HashMap<string, number> has no canonical \
HeapValue arm (number is inline-scalar). \
Marshal contract violation."
);
}
HashMapKindedRef::Bool(_) => {
panic!(
"FromSlot<Vec<(Arc<String>, Arc<HeapValue>)>>: \
HashMap<string, bool> has no canonical \
HeapValue arm (bool is inline-scalar). \
Marshal contract violation."
);
}
HashMapKindedRef::Char(arc) => {
let v: char = unsafe { *(*arc.values).data.add(i) };
Arc::new(HeapValue::Char(v))
}
HashMapKindedRef::String(arc) => {
let ptr: *const shape_value::v2::string_obj::StringObj =
unsafe { *(*arc.values).data.add(i) };
let s = unsafe {
shape_value::v2::string_obj::StringObj::as_str(ptr)
.to_owned()
};
Arc::new(HeapValue::String(Arc::new(s)))
}
HashMapKindedRef::Decimal(arc) => {
let ptr: *const shape_value::v2::decimal_obj::DecimalObj =
unsafe { *(*arc.values).data.add(i) };
let d = unsafe { (*ptr).value };
Arc::new(HeapValue::Decimal(Arc::new(d)))
}
HashMapKindedRef::TypedObject(arc) => {
let elem: &shape_value::heap_value::TypedObjectPtr =
unsafe { &*(*arc.values).data.add(i) };
Arc::new(HeapValue::TypedObject(elem.clone()))
}
HashMapKindedRef::TraitObject(_) => {
panic!(
"FromSlot<Vec<(Arc<String>, Arc<HeapValue>)>>: \
HashMap<string, TraitObject> marshal not yet \
wired (HeapValue::TraitObject arm exists but \
payload kind dispatch is its own cluster)."
);
}
HashMapKindedRef::HashMap(arc) => {
let inner_ref: &HashMapKindedRef =
&*(*arc.values).data.add(i);
Arc::new(HeapValue::HashMap(inner_ref.clone()))
}
};
out.push((key, value));
}
out
}
other => panic!(
"FromSlot<Vec<(Arc<String>, Arc<HeapValue>)>>: slot bits decoded to \
HeapValue::{:?}, not HashMap. Marshal kind contract violated by caller.",
other.kind()
),
}
}
}
}
impl FromSlot for Arc<Vec<f64>> {
const NATIVE_KIND: NativeKind =
NativeKind::Ptr(shape_value::HeapKind::TypedArray);
#[inline]
fn from_slot(bits: u64) -> Self {
let arr = bits as usize as *const shape_value::v2::typed_array::TypedArray<f64>;
if arr.is_null() {
return Arc::new(Vec::new());
}
unsafe {
Arc::new(
shape_value::v2::typed_array::TypedArray::<f64>::as_slice(arr).to_vec(),
)
}
}
}
impl ToSlot for Arc<Vec<f64>> {
const NATIVE_KIND: NativeKind =
NativeKind::Ptr(shape_value::HeapKind::TypedArray);
#[inline]
fn to_slot(self) -> u64 {
let arr = shape_value::v2::typed_array::TypedArray::<f64>::from_slice(self.as_slice());
arr as usize as u64
}
}
impl FromSlot for Arc<Vec<i64>> {
const NATIVE_KIND: NativeKind =
NativeKind::Ptr(shape_value::HeapKind::TypedArray);
#[inline]
fn from_slot(bits: u64) -> Self {
let arr = bits as usize as *const shape_value::v2::typed_array::TypedArray<i64>;
if arr.is_null() {
return Arc::new(Vec::new());
}
unsafe {
Arc::new(
shape_value::v2::typed_array::TypedArray::<i64>::as_slice(arr).to_vec(),
)
}
}
}
impl ToSlot for Arc<Vec<i64>> {
const NATIVE_KIND: NativeKind =
NativeKind::Ptr(shape_value::HeapKind::TypedArray);
#[inline]
fn to_slot(self) -> u64 {
let arr = shape_value::v2::typed_array::TypedArray::<i64>::from_slice(self.as_slice());
arr as usize as u64
}
}
impl FromSlot for Arc<Vec<u8>> {
const NATIVE_KIND: NativeKind =
NativeKind::Ptr(shape_value::HeapKind::TypedArray);
#[inline]
fn from_slot(bits: u64) -> Self {
let arr = bits as usize as *const shape_value::v2::typed_array::TypedArray<u8>;
if arr.is_null() {
return Arc::new(Vec::new());
}
unsafe {
Arc::new(
shape_value::v2::typed_array::TypedArray::<u8>::as_slice(arr).to_vec(),
)
}
}
}
impl ToSlot for Arc<Vec<u8>> {
const NATIVE_KIND: NativeKind =
NativeKind::Ptr(shape_value::HeapKind::TypedArray);
#[inline]
fn to_slot(self) -> u64 {
let arr = shape_value::v2::typed_array::TypedArray::<u8>::from_slice(self.as_slice());
arr as usize as u64
}
}
type TypedInvoke = Arc<
dyn for<'ctx> Fn(&[u64], &ModuleContext<'ctx>) -> Result<TypedReturn, String>
+ Send
+ Sync,
>;
pub fn register_typed_fn_0<F>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: for<'ctx> Fn(&ModuleContext<'ctx>) -> Result<TypedReturn, String>
+ Send
+ Sync
+ 'static,
{
let invoke: TypedInvoke = Arc::new(move |slots, ctx| {
if !slots.is_empty() {
return Err(MarshalError::ArgCount {
expected: 0,
got: slots.len(),
}
.into());
}
body(ctx)
});
install(module, name, description, vec![], return_type, vec![], invoke);
}
pub fn register_typed_fn_1<F, P0>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
param_name: impl Into<String>,
param_type_name: impl Into<String>,
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: for<'ctx> Fn(P0, &ModuleContext<'ctx>) -> Result<TypedReturn, String>
+ Send
+ Sync
+ 'static,
P0: FromSlot + Send + Sync + 'static,
{
let arg_kinds = vec![P0::NATIVE_KIND];
let invoke: TypedInvoke = Arc::new(move |slots, ctx| {
if slots.len() != 1 {
return Err(MarshalError::ArgCount {
expected: 1,
got: slots.len(),
}
.into());
}
let p0 = P0::from_slot(slots[0]);
body(p0, ctx)
});
let params = vec![crate::module_exports::ModuleParam {
name: param_name.into(),
type_name: param_type_name.into(),
required: true,
..Default::default()
}];
install(
module,
name,
description,
params,
return_type,
arg_kinds,
invoke,
);
}
pub fn register_typed_fn_2<F, P0, P1>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
param_names: [(&str, &str); 2],
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: for<'ctx> Fn(P0, P1, &ModuleContext<'ctx>) -> Result<TypedReturn, String>
+ Send
+ Sync
+ 'static,
P0: FromSlot + Send + Sync + 'static,
P1: FromSlot + Send + Sync + 'static,
{
let arg_kinds = vec![P0::NATIVE_KIND, P1::NATIVE_KIND];
let invoke: TypedInvoke = Arc::new(move |slots, ctx| {
if slots.len() != 2 {
return Err(MarshalError::ArgCount {
expected: 2,
got: slots.len(),
}
.into());
}
let p0 = P0::from_slot(slots[0]);
let p1 = P1::from_slot(slots[1]);
body(p0, p1, ctx)
});
let params = param_names
.iter()
.map(|(name, ty)| crate::module_exports::ModuleParam {
name: (*name).to_string(),
type_name: (*ty).to_string(),
required: true,
..Default::default()
})
.collect();
install(
module,
name,
description,
params,
return_type,
arg_kinds,
invoke,
);
}
pub fn register_typed_fn_3<F, P0, P1, P2>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
param_names: [(&str, &str); 3],
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: for<'ctx> Fn(P0, P1, P2, &ModuleContext<'ctx>) -> Result<TypedReturn, String>
+ Send
+ Sync
+ 'static,
P0: FromSlot + Send + Sync + 'static,
P1: FromSlot + Send + Sync + 'static,
P2: FromSlot + Send + Sync + 'static,
{
let arg_kinds = vec![P0::NATIVE_KIND, P1::NATIVE_KIND, P2::NATIVE_KIND];
let invoke: TypedInvoke = Arc::new(move |slots, ctx| {
if slots.len() != 3 {
return Err(MarshalError::ArgCount {
expected: 3,
got: slots.len(),
}
.into());
}
let p0 = P0::from_slot(slots[0]);
let p1 = P1::from_slot(slots[1]);
let p2 = P2::from_slot(slots[2]);
body(p0, p1, p2, ctx)
});
let params = param_names
.iter()
.map(|(name, ty)| crate::module_exports::ModuleParam {
name: (*name).to_string(),
type_name: (*ty).to_string(),
required: true,
..Default::default()
})
.collect();
install(
module,
name,
description,
params,
return_type,
arg_kinds,
invoke,
);
}
pub fn register_typed_fn_1_full<F, P0>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
params: [crate::module_exports::ModuleParam; 1],
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: for<'ctx> Fn(P0, &ModuleContext<'ctx>) -> Result<TypedReturn, String>
+ Send
+ Sync
+ 'static,
P0: FromSlot + Send + Sync + 'static,
{
let arg_kinds = vec![P0::NATIVE_KIND];
let invoke: TypedInvoke = Arc::new(move |slots, ctx| {
if slots.len() != 1 {
return Err(MarshalError::ArgCount {
expected: 1,
got: slots.len(),
}
.into());
}
let p0 = P0::from_slot(slots[0]);
body(p0, ctx)
});
install(
module,
name,
description,
params.into_iter().collect(),
return_type,
arg_kinds,
invoke,
);
}
pub fn register_typed_fn_2_full<F, P0, P1>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
params: [crate::module_exports::ModuleParam; 2],
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: for<'ctx> Fn(P0, P1, &ModuleContext<'ctx>) -> Result<TypedReturn, String>
+ Send
+ Sync
+ 'static,
P0: FromSlot + Send + Sync + 'static,
P1: FromSlot + Send + Sync + 'static,
{
let arg_kinds = vec![P0::NATIVE_KIND, P1::NATIVE_KIND];
let invoke: TypedInvoke = Arc::new(move |slots, ctx| {
if slots.len() != 2 {
return Err(MarshalError::ArgCount {
expected: 2,
got: slots.len(),
}
.into());
}
let p0 = P0::from_slot(slots[0]);
let p1 = P1::from_slot(slots[1]);
body(p0, p1, ctx)
});
install(
module,
name,
description,
params.into_iter().collect(),
return_type,
arg_kinds,
invoke,
);
}
pub fn register_typed_fn_3_full<F, P0, P1, P2>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
params: [crate::module_exports::ModuleParam; 3],
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: for<'ctx> Fn(P0, P1, P2, &ModuleContext<'ctx>) -> Result<TypedReturn, String>
+ Send
+ Sync
+ 'static,
P0: FromSlot + Send + Sync + 'static,
P1: FromSlot + Send + Sync + 'static,
P2: FromSlot + Send + Sync + 'static,
{
let arg_kinds = vec![P0::NATIVE_KIND, P1::NATIVE_KIND, P2::NATIVE_KIND];
let invoke: TypedInvoke = Arc::new(move |slots, ctx| {
if slots.len() != 3 {
return Err(MarshalError::ArgCount {
expected: 3,
got: slots.len(),
}
.into());
}
let p0 = P0::from_slot(slots[0]);
let p1 = P1::from_slot(slots[1]);
let p2 = P2::from_slot(slots[2]);
body(p0, p1, p2, ctx)
});
install(
module,
name,
description,
params.into_iter().collect(),
return_type,
arg_kinds,
invoke,
);
}
pub fn register_typed_fn_4<F, P0, P1, P2, P3>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
param_names: [(&str, &str); 4],
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: for<'ctx> Fn(P0, P1, P2, P3, &ModuleContext<'ctx>) -> Result<TypedReturn, String>
+ Send
+ Sync
+ 'static,
P0: FromSlot + Send + Sync + 'static,
P1: FromSlot + Send + Sync + 'static,
P2: FromSlot + Send + Sync + 'static,
P3: FromSlot + Send + Sync + 'static,
{
let arg_kinds = vec![
P0::NATIVE_KIND,
P1::NATIVE_KIND,
P2::NATIVE_KIND,
P3::NATIVE_KIND,
];
let invoke: TypedInvoke = Arc::new(move |slots, ctx| {
if slots.len() != 4 {
return Err(MarshalError::ArgCount {
expected: 4,
got: slots.len(),
}
.into());
}
let p0 = P0::from_slot(slots[0]);
let p1 = P1::from_slot(slots[1]);
let p2 = P2::from_slot(slots[2]);
let p3 = P3::from_slot(slots[3]);
body(p0, p1, p2, p3, ctx)
});
let params = param_names
.iter()
.map(|(name, ty)| crate::module_exports::ModuleParam {
name: (*name).to_string(),
type_name: (*ty).to_string(),
required: true,
..Default::default()
})
.collect();
install(
module,
name,
description,
params,
return_type,
arg_kinds,
invoke,
);
}
pub fn register_typed_fn_5<F, P0, P1, P2, P3, P4>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
param_names: [(&str, &str); 5],
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: for<'ctx> Fn(P0, P1, P2, P3, P4, &ModuleContext<'ctx>) -> Result<TypedReturn, String>
+ Send
+ Sync
+ 'static,
P0: FromSlot + Send + Sync + 'static,
P1: FromSlot + Send + Sync + 'static,
P2: FromSlot + Send + Sync + 'static,
P3: FromSlot + Send + Sync + 'static,
P4: FromSlot + Send + Sync + 'static,
{
let arg_kinds = vec![
P0::NATIVE_KIND,
P1::NATIVE_KIND,
P2::NATIVE_KIND,
P3::NATIVE_KIND,
P4::NATIVE_KIND,
];
let invoke: TypedInvoke = Arc::new(move |slots, ctx| {
if slots.len() != 5 {
return Err(MarshalError::ArgCount {
expected: 5,
got: slots.len(),
}
.into());
}
let p0 = P0::from_slot(slots[0]);
let p1 = P1::from_slot(slots[1]);
let p2 = P2::from_slot(slots[2]);
let p3 = P3::from_slot(slots[3]);
let p4 = P4::from_slot(slots[4]);
body(p0, p1, p2, p3, p4, ctx)
});
let params = param_names
.iter()
.map(|(name, ty)| crate::module_exports::ModuleParam {
name: (*name).to_string(),
type_name: (*ty).to_string(),
required: true,
..Default::default()
})
.collect();
install(
module,
name,
description,
params,
return_type,
arg_kinds,
invoke,
);
}
pub fn register_typed_fn_6<F, P0, P1, P2, P3, P4, P5>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
param_names: [(&str, &str); 6],
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: for<'ctx> Fn(P0, P1, P2, P3, P4, P5, &ModuleContext<'ctx>) -> Result<TypedReturn, String>
+ Send
+ Sync
+ 'static,
P0: FromSlot + Send + Sync + 'static,
P1: FromSlot + Send + Sync + 'static,
P2: FromSlot + Send + Sync + 'static,
P3: FromSlot + Send + Sync + 'static,
P4: FromSlot + Send + Sync + 'static,
P5: FromSlot + Send + Sync + 'static,
{
let arg_kinds = vec![
P0::NATIVE_KIND,
P1::NATIVE_KIND,
P2::NATIVE_KIND,
P3::NATIVE_KIND,
P4::NATIVE_KIND,
P5::NATIVE_KIND,
];
let invoke: TypedInvoke = Arc::new(move |slots, ctx| {
if slots.len() != 6 {
return Err(MarshalError::ArgCount {
expected: 6,
got: slots.len(),
}
.into());
}
let p0 = P0::from_slot(slots[0]);
let p1 = P1::from_slot(slots[1]);
let p2 = P2::from_slot(slots[2]);
let p3 = P3::from_slot(slots[3]);
let p4 = P4::from_slot(slots[4]);
let p5 = P5::from_slot(slots[5]);
body(p0, p1, p2, p3, p4, p5, ctx)
});
let params = param_names
.iter()
.map(|(name, ty)| crate::module_exports::ModuleParam {
name: (*name).to_string(),
type_name: (*ty).to_string(),
required: true,
..Default::default()
})
.collect();
install(
module,
name,
description,
params,
return_type,
arg_kinds,
invoke,
);
}
pub fn register_typed_fn_4_full<F, P0, P1, P2, P3>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
params: [crate::module_exports::ModuleParam; 4],
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: for<'ctx> Fn(P0, P1, P2, P3, &ModuleContext<'ctx>) -> Result<TypedReturn, String>
+ Send
+ Sync
+ 'static,
P0: FromSlot + Send + Sync + 'static,
P1: FromSlot + Send + Sync + 'static,
P2: FromSlot + Send + Sync + 'static,
P3: FromSlot + Send + Sync + 'static,
{
let arg_kinds = vec![
P0::NATIVE_KIND,
P1::NATIVE_KIND,
P2::NATIVE_KIND,
P3::NATIVE_KIND,
];
let invoke: TypedInvoke = Arc::new(move |slots, ctx| {
if slots.len() != 4 {
return Err(MarshalError::ArgCount {
expected: 4,
got: slots.len(),
}
.into());
}
let p0 = P0::from_slot(slots[0]);
let p1 = P1::from_slot(slots[1]);
let p2 = P2::from_slot(slots[2]);
let p3 = P3::from_slot(slots[3]);
body(p0, p1, p2, p3, ctx)
});
install(
module,
name,
description,
params.into_iter().collect(),
return_type,
arg_kinds,
invoke,
);
}
pub fn register_typed_fn_5_full<F, P0, P1, P2, P3, P4>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
params: [crate::module_exports::ModuleParam; 5],
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: for<'ctx> Fn(P0, P1, P2, P3, P4, &ModuleContext<'ctx>) -> Result<TypedReturn, String>
+ Send
+ Sync
+ 'static,
P0: FromSlot + Send + Sync + 'static,
P1: FromSlot + Send + Sync + 'static,
P2: FromSlot + Send + Sync + 'static,
P3: FromSlot + Send + Sync + 'static,
P4: FromSlot + Send + Sync + 'static,
{
let arg_kinds = vec![
P0::NATIVE_KIND,
P1::NATIVE_KIND,
P2::NATIVE_KIND,
P3::NATIVE_KIND,
P4::NATIVE_KIND,
];
let invoke: TypedInvoke = Arc::new(move |slots, ctx| {
if slots.len() != 5 {
return Err(MarshalError::ArgCount {
expected: 5,
got: slots.len(),
}
.into());
}
let p0 = P0::from_slot(slots[0]);
let p1 = P1::from_slot(slots[1]);
let p2 = P2::from_slot(slots[2]);
let p3 = P3::from_slot(slots[3]);
let p4 = P4::from_slot(slots[4]);
body(p0, p1, p2, p3, p4, ctx)
});
install(
module,
name,
description,
params.into_iter().collect(),
return_type,
arg_kinds,
invoke,
);
}
pub fn register_typed_fn_6_full<F, P0, P1, P2, P3, P4, P5>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
params: [crate::module_exports::ModuleParam; 6],
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: for<'ctx> Fn(P0, P1, P2, P3, P4, P5, &ModuleContext<'ctx>) -> Result<TypedReturn, String>
+ Send
+ Sync
+ 'static,
P0: FromSlot + Send + Sync + 'static,
P1: FromSlot + Send + Sync + 'static,
P2: FromSlot + Send + Sync + 'static,
P3: FromSlot + Send + Sync + 'static,
P4: FromSlot + Send + Sync + 'static,
P5: FromSlot + Send + Sync + 'static,
{
let arg_kinds = vec![
P0::NATIVE_KIND,
P1::NATIVE_KIND,
P2::NATIVE_KIND,
P3::NATIVE_KIND,
P4::NATIVE_KIND,
P5::NATIVE_KIND,
];
let invoke: TypedInvoke = Arc::new(move |slots, ctx| {
if slots.len() != 6 {
return Err(MarshalError::ArgCount {
expected: 6,
got: slots.len(),
}
.into());
}
let p0 = P0::from_slot(slots[0]);
let p1 = P1::from_slot(slots[1]);
let p2 = P2::from_slot(slots[2]);
let p3 = P3::from_slot(slots[3]);
let p4 = P4::from_slot(slots[4]);
let p5 = P5::from_slot(slots[5]);
body(p0, p1, p2, p3, p4, p5, ctx)
});
install(
module,
name,
description,
params.into_iter().collect(),
return_type,
arg_kinds,
invoke,
);
}
fn install(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
params: Vec<crate::module_exports::ModuleParam>,
return_type: crate::typed_module_exports::ConcreteType,
arg_kinds: Vec<NativeKind>,
invoke: TypedInvoke,
) {
use crate::module_exports::ModuleFunction;
use crate::typed_module_exports::TypedModuleFunction;
let name = name.into();
let arg_types: Vec<String> = params.iter().map(|p| p.type_name.clone()).collect();
let return_type_str = return_type.shape_type_name();
module.add_schema_only(
name.clone(),
ModuleFunction {
description: description.into(),
params,
return_type: Some(return_type_str),
},
);
module.typed_exports_mut().functions.insert(
name,
TypedModuleFunction {
invoke,
return_type,
arg_types,
arg_kinds,
},
);
}
type TypedAsyncInvoke = Arc<
dyn Fn(
Vec<u64>,
)
-> std::pin::Pin<Box<dyn std::future::Future<Output = Result<TypedReturn, String>> + Send>>
+ Send
+ Sync,
>;
pub fn register_typed_async_fn_1<F, Fut, P0>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
param_name: impl Into<String>,
param_type_name: impl Into<String>,
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: Fn(P0) -> Fut + Send + Sync + Clone + 'static,
Fut: std::future::Future<Output = Result<TypedReturn, String>> + Send + 'static,
P0: FromSlot + Send + Sync + 'static,
{
let arg_kinds = vec![P0::NATIVE_KIND];
let invoke: TypedAsyncInvoke = Arc::new(move |slots: Vec<u64>| {
if slots.len() != 1 {
let err = MarshalError::ArgCount {
expected: 1,
got: slots.len(),
};
return Box::pin(async move { Err(err.into()) });
}
let p0 = P0::from_slot(slots[0]);
let body = body.clone();
Box::pin(async move { body(p0).await })
});
let params = vec![crate::module_exports::ModuleParam {
name: param_name.into(),
type_name: param_type_name.into(),
required: true,
..Default::default()
}];
install_async(module, name, description, params, return_type, arg_kinds, invoke);
}
pub fn register_typed_async_fn_2<F, Fut, P0, P1>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
param_names: [(&str, &str); 2],
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: Fn(P0, P1) -> Fut + Send + Sync + Clone + 'static,
Fut: std::future::Future<Output = Result<TypedReturn, String>> + Send + 'static,
P0: FromSlot + Send + Sync + 'static,
P1: FromSlot + Send + Sync + 'static,
{
let arg_kinds = vec![P0::NATIVE_KIND, P1::NATIVE_KIND];
let invoke: TypedAsyncInvoke = Arc::new(move |slots: Vec<u64>| {
if slots.len() != 2 {
let err = MarshalError::ArgCount {
expected: 2,
got: slots.len(),
};
return Box::pin(async move { Err(err.into()) });
}
let p0 = P0::from_slot(slots[0]);
let p1 = P1::from_slot(slots[1]);
let body = body.clone();
Box::pin(async move { body(p0, p1).await })
});
let params = param_names
.iter()
.map(|(name, ty)| crate::module_exports::ModuleParam {
name: (*name).to_string(),
type_name: (*ty).to_string(),
required: true,
..Default::default()
})
.collect();
install_async(module, name, description, params, return_type, arg_kinds, invoke);
}
pub fn register_typed_async_fn_3<F, Fut, P0, P1, P2>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
param_names: [(&str, &str); 3],
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: Fn(P0, P1, P2) -> Fut + Send + Sync + Clone + 'static,
Fut: std::future::Future<Output = Result<TypedReturn, String>> + Send + 'static,
P0: FromSlot + Send + Sync + 'static,
P1: FromSlot + Send + Sync + 'static,
P2: FromSlot + Send + Sync + 'static,
{
let arg_kinds = vec![P0::NATIVE_KIND, P1::NATIVE_KIND, P2::NATIVE_KIND];
let invoke: TypedAsyncInvoke = Arc::new(move |slots: Vec<u64>| {
if slots.len() != 3 {
let err = MarshalError::ArgCount {
expected: 3,
got: slots.len(),
};
return Box::pin(async move { Err(err.into()) });
}
let p0 = P0::from_slot(slots[0]);
let p1 = P1::from_slot(slots[1]);
let p2 = P2::from_slot(slots[2]);
let body = body.clone();
Box::pin(async move { body(p0, p1, p2).await })
});
let params = param_names
.iter()
.map(|(name, ty)| crate::module_exports::ModuleParam {
name: (*name).to_string(),
type_name: (*ty).to_string(),
required: true,
..Default::default()
})
.collect();
install_async(module, name, description, params, return_type, arg_kinds, invoke);
}
pub fn register_typed_async_fn_1_full<F, Fut, P0>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
params: [crate::module_exports::ModuleParam; 1],
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: Fn(P0) -> Fut + Send + Sync + Clone + 'static,
Fut: std::future::Future<Output = Result<TypedReturn, String>> + Send + 'static,
P0: FromSlot + Send + Sync + 'static,
{
let arg_kinds = vec![P0::NATIVE_KIND];
let invoke: TypedAsyncInvoke = Arc::new(move |slots: Vec<u64>| {
if slots.len() != 1 {
let err = MarshalError::ArgCount {
expected: 1,
got: slots.len(),
};
return Box::pin(async move { Err(err.into()) });
}
let p0 = P0::from_slot(slots[0]);
let body = body.clone();
Box::pin(async move { body(p0).await })
});
install_async(
module,
name,
description,
params.into_iter().collect(),
return_type,
arg_kinds,
invoke,
);
}
pub fn register_typed_async_fn_2_full<F, Fut, P0, P1>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
params: [crate::module_exports::ModuleParam; 2],
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: Fn(P0, P1) -> Fut + Send + Sync + Clone + 'static,
Fut: std::future::Future<Output = Result<TypedReturn, String>> + Send + 'static,
P0: FromSlot + Send + Sync + 'static,
P1: FromSlot + Send + Sync + 'static,
{
let arg_kinds = vec![P0::NATIVE_KIND, P1::NATIVE_KIND];
let invoke: TypedAsyncInvoke = Arc::new(move |slots: Vec<u64>| {
if slots.len() != 2 {
let err = MarshalError::ArgCount {
expected: 2,
got: slots.len(),
};
return Box::pin(async move { Err(err.into()) });
}
let p0 = P0::from_slot(slots[0]);
let p1 = P1::from_slot(slots[1]);
let body = body.clone();
Box::pin(async move { body(p0, p1).await })
});
install_async(
module,
name,
description,
params.into_iter().collect(),
return_type,
arg_kinds,
invoke,
);
}
pub fn register_typed_async_fn_3_full<F, Fut, P0, P1, P2>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
params: [crate::module_exports::ModuleParam; 3],
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: Fn(P0, P1, P2) -> Fut + Send + Sync + Clone + 'static,
Fut: std::future::Future<Output = Result<TypedReturn, String>> + Send + 'static,
P0: FromSlot + Send + Sync + 'static,
P1: FromSlot + Send + Sync + 'static,
P2: FromSlot + Send + Sync + 'static,
{
let arg_kinds = vec![P0::NATIVE_KIND, P1::NATIVE_KIND, P2::NATIVE_KIND];
let invoke: TypedAsyncInvoke = Arc::new(move |slots: Vec<u64>| {
if slots.len() != 3 {
let err = MarshalError::ArgCount {
expected: 3,
got: slots.len(),
};
return Box::pin(async move { Err(err.into()) });
}
let p0 = P0::from_slot(slots[0]);
let p1 = P1::from_slot(slots[1]);
let p2 = P2::from_slot(slots[2]);
let body = body.clone();
Box::pin(async move { body(p0, p1, p2).await })
});
install_async(
module,
name,
description,
params.into_iter().collect(),
return_type,
arg_kinds,
invoke,
);
}
fn install_async(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
params: Vec<crate::module_exports::ModuleParam>,
return_type: crate::typed_module_exports::ConcreteType,
arg_kinds: Vec<NativeKind>,
invoke: TypedAsyncInvoke,
) {
use crate::module_exports::ModuleFunction;
use crate::typed_module_exports::TypedModuleAsyncFunction;
let name = name.into();
let arg_types: Vec<String> = params.iter().map(|p| p.type_name.clone()).collect();
let return_type_str = return_type.shape_type_name();
module.add_schema_only(
name.clone(),
ModuleFunction {
description: description.into(),
params,
return_type: Some(return_type_str),
},
);
module.typed_exports_mut().async_functions.insert(
name,
TypedModuleAsyncFunction {
invoke,
return_type,
arg_types,
arg_kinds,
},
);
}
use crate::typed_module_exports::TypedModuleFunction;
use shape_value::KindedSlot;
pub type VariadicTypedBody = dyn for<'ctx> Fn(
&[KindedSlot],
&ModuleContext<'ctx>,
) -> Result<TypedReturn, String>
+ Send
+ Sync;
pub fn register_typed_function<F>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
params: Vec<crate::module_exports::ModuleParam>,
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: for<'ctx> Fn(&[KindedSlot], &ModuleContext<'ctx>) -> Result<TypedReturn, String>
+ Send
+ Sync
+ 'static,
{
use crate::module_exports::ModuleFunction;
let name = name.into();
let arg_types: Vec<String> = params.iter().map(|p| p.type_name.clone()).collect();
let arg_kinds: Vec<NativeKind> = params.iter().map(|_| NativeKind::Bool).collect();
let return_type_str = return_type.shape_type_name();
let body = Arc::new(body);
let invoke: TypedInvoke = Arc::new(move |slots, ctx| {
let kinded: Vec<KindedSlot> = slots
.iter()
.map(|&bits| {
KindedSlot::new(
shape_value::ValueSlot::from_raw(bits),
NativeKind::Bool,
)
})
.collect();
body(&kinded, ctx)
});
module.add_schema_only(
name.clone(),
ModuleFunction {
description: description.into(),
params,
return_type: Some(return_type_str),
},
);
module.typed_exports_mut().functions.insert(
name,
TypedModuleFunction {
invoke,
return_type,
arg_types,
arg_kinds,
},
);
}
pub type VariadicTypedAsyncBody<Fut> =
dyn Fn(Vec<KindedSlot>) -> Fut + Send + Sync;
pub fn register_typed_async_function<F, Fut>(
module: &mut crate::module_exports::ModuleExports,
name: impl Into<String>,
description: impl Into<String>,
params: Vec<crate::module_exports::ModuleParam>,
return_type: crate::typed_module_exports::ConcreteType,
body: F,
) where
F: Fn(Vec<KindedSlot>) -> Fut + Send + Sync + Clone + 'static,
Fut: std::future::Future<Output = Result<TypedReturn, String>> + Send + 'static,
{
use crate::module_exports::ModuleFunction;
use crate::typed_module_exports::TypedModuleAsyncFunction;
let name = name.into();
let arg_types: Vec<String> = params.iter().map(|p| p.type_name.clone()).collect();
let arg_kinds: Vec<NativeKind> = params.iter().map(|_| NativeKind::Bool).collect();
let return_type_str = return_type.shape_type_name();
let invoke: TypedAsyncInvoke = Arc::new(move |slots: Vec<u64>| {
let kinded: Vec<KindedSlot> = slots
.into_iter()
.map(|bits| {
KindedSlot::new(
shape_value::ValueSlot::from_raw(bits),
NativeKind::Bool,
)
})
.collect();
let body = body.clone();
Box::pin(async move { body(kinded).await })
});
module.add_schema_only(
name.clone(),
ModuleFunction {
description: description.into(),
params,
return_type: Some(return_type_str),
},
);
module.typed_exports_mut().async_functions.insert(
name,
TypedModuleAsyncFunction {
invoke,
return_type,
arg_types,
arg_kinds,
},
);
}