Skip to main content

vm/
native.rs

1use super::FnVariant;
2use crate::JITRunTime;
3use crate::RwLock;
4use crate::memory::{alloc_dynamic, alloc_struct_bytes, take_dynamic_return};
5use anyhow::{Result, anyhow};
6use cranelift::prelude::AbiParam;
7use cranelift_module::{Linkage, Module};
8use dynamic::{Dynamic, Type};
9use parser::{BinaryOp, Expr, ExprKind, Span};
10use rand::RngExt;
11use std::borrow::Cow;
12use std::collections::BTreeMap;
13use std::fmt::Write as _;
14use std::sync::Weak;
15
16#[derive(Clone, Debug)]
17pub struct ZustCallback {
18    pub fn_ptr: usize,
19    pub ret_ty: Type,
20    pub explicit_arg_len: usize,
21    pub captures: Vec<Dynamic>,
22}
23
24impl ZustCallback {
25    pub fn new(fn_ptr: usize, ret_ty: Type, captures: Vec<Dynamic>) -> Self {
26        Self { fn_ptr, ret_ty, explicit_arg_len: usize::MAX, captures }
27    }
28
29    pub fn new_with_arg_len(fn_ptr: usize, ret_ty: Type, explicit_arg_len: usize, captures: Vec<Dynamic>) -> Self {
30        Self { fn_ptr, ret_ty, explicit_arg_len, captures }
31    }
32
33    pub fn call0(&self) -> Result<Dynamic> {
34        if matches!(self.explicit_arg_len, usize::MAX | 0) {
35            return self.call_with_arg_ptrs(&[]);
36        }
37        self.call(Vec::new())
38    }
39
40    pub fn call1(&self, arg: Dynamic) -> Result<Dynamic> {
41        match self.explicit_arg_len {
42            0 => self.call0(),
43            usize::MAX | 1 => {
44                let mut ptrs = Vec::with_capacity(1 + self.captures.len());
45                ptrs.push(&arg as *const Dynamic);
46                self.call_with_arg_ptrs(&ptrs)
47            }
48            _ => self.call(vec![arg]),
49        }
50    }
51
52    pub fn call(&self, mut args: Vec<Dynamic>) -> Result<Dynamic> {
53        if self.explicit_arg_len != usize::MAX {
54            args.truncate(self.explicit_arg_len);
55            while args.len() < self.explicit_arg_len {
56                args.push(Dynamic::Null);
57            }
58        }
59        let ptrs: Vec<*const Dynamic> = args.iter().map(|arg| arg as *const Dynamic).collect();
60        self.call_with_arg_ptrs(&ptrs)
61    }
62
63    fn call_with_arg_ptrs(&self, args: &[*const Dynamic]) -> Result<Dynamic> {
64        let mut ptrs = Vec::with_capacity(args.len() + self.captures.len());
65        ptrs.extend_from_slice(args);
66        ptrs.extend(self.captures.iter().map(|value| value as *const Dynamic));
67        call_jit_isolated(|| unsafe { call_callback(self.fn_ptr as *const u8, &self.ret_ty, &ptrs) })
68    }
69}
70
71extern "C" fn any_clone(addr: *const Dynamic) -> *const Dynamic {
72    //在堆上分配内存 复制 addr 到内存中
73    unsafe {
74        let cloned_value = (*addr).deep_clone();
75        alloc_dynamic(cloned_value)
76    }
77}
78
79extern "C" fn any_null() -> *const Dynamic {
80    //在堆上分配内存 复制 addr 到内存中
81    alloc_dynamic(Dynamic::Null)
82}
83
84extern "C" fn print(addr: *const Dynamic) {
85    if !addr.is_null() {
86        unsafe {
87            println!("{}", (*addr).to_string());
88        }
89    }
90}
91
92extern "C" fn sqrt(value: f64) -> f64 {
93    value.sqrt()
94}
95
96extern "C" fn sleep(ms: i64) {
97    std::thread::sleep(std::time::Duration::from_millis(ms.max(0) as u64));
98}
99
100extern "C" fn log_any(addr: *const Dynamic) {
101    if addr.is_null() {
102        log::debug!("{:?}", Dynamic::Null);
103    } else {
104        log::debug!("{:?}", unsafe { &*addr });
105    }
106}
107
108extern "C" fn any_is_map(addr: *const Dynamic) -> bool {
109    !addr.is_null() && unsafe { (*addr).is_map() }
110}
111
112extern "C" fn any_is_list(addr: *const Dynamic) -> bool {
113    !addr.is_null() && unsafe { (*addr).is_list() }
114}
115
116extern "C" fn any_is_string(addr: *const Dynamic) -> bool {
117    !addr.is_null() && unsafe { (*addr).is_str() }
118}
119
120extern "C" fn any_is_null(addr: *const Dynamic) -> bool {
121    addr.is_null() || unsafe { (*addr).is_null() }
122}
123
124extern "C" fn random(start: *const Dynamic, stop: *const Dynamic) -> *const Dynamic {
125    if !start.is_null() && !stop.is_null() {
126        let mut rng = rand::rng();
127        unsafe {
128            if (&*start).is_int() {
129                let start = (*start).as_int().unwrap_or(0);
130                let stop = (*stop).as_int().unwrap_or(100);
131                return alloc_dynamic(Dynamic::I64(rng.random_range(start..stop)));
132            } else if (&*start).is_f32() || (&*start).is_f64() {
133                let start = (*start).as_float().unwrap_or(0.0);
134                let stop = (*stop).as_float().unwrap_or(1.0);
135                return alloc_dynamic(Dynamic::F64(rng.random_range(start..stop)));
136            }
137        }
138    }
139    alloc_dynamic(Dynamic::Null)
140}
141
142extern "C" fn uuid() -> *const Dynamic {
143    alloc_dynamic(uuid::Uuid::new_v4().to_string().into())
144}
145
146pub(crate) extern "C" fn struct_alloc(size: i64) -> *mut u8 {
147    let size = size.max(0) as usize;
148    let ptr = alloc_struct_bytes(size);
149    unsafe {
150        std::ptr::write_bytes(ptr, 0, size);
151    }
152    ptr
153}
154
155pub(crate) extern "C" fn repeat_fill(dst: *mut u8, pattern: u64, width: i64, len: i64) {
156    if dst.is_null() || width <= 0 || len <= 0 {
157        return;
158    }
159    let width = width as usize;
160    let len = len as usize;
161    let bytes = pattern.to_le_bytes();
162    unsafe {
163        if width == 1 {
164            std::ptr::write_bytes(dst, bytes[0], len);
165            return;
166        }
167        if !matches!(width, 2 | 4 | 8) {
168            return;
169        }
170        for idx in 0..len {
171            std::ptr::copy_nonoverlapping(bytes.as_ptr(), dst.add(idx * width), width);
172        }
173    }
174}
175
176pub(crate) extern "C" fn strcat(left: *const Dynamic, right: *const Dynamic) -> *const Dynamic {
177    let left = if left.is_null() { "" } else { unsafe { (&*left).as_str() } };
178    let right = if right.is_null() { "" } else { unsafe { (&*right).as_str() } };
179    let mut out = String::with_capacity(left.len() + right.len());
180    out.push_str(left);
181    out.push_str(right);
182    alloc_dynamic(Dynamic::StringBuf(out))
183}
184
185pub(crate) extern "C" fn strcat_i64(left: *const Dynamic, right: i64) -> *const Dynamic {
186    let left = if left.is_null() { "" } else { unsafe { (&*left).as_str() } };
187    let mut out = String::with_capacity(left.len() + 20);
188    out.push_str(left);
189    let _ = write!(&mut out, "{right}");
190    alloc_dynamic(Dynamic::StringBuf(out))
191}
192
193pub(crate) extern "C" fn strcat_assign(left: *mut Dynamic, right: *const Dynamic) -> *const Dynamic {
194    if left.is_null() {
195        return strcat(left, right);
196    }
197    let suffix = if right.is_null() {
198        Cow::Borrowed("")
199    } else if std::ptr::eq(left as *const Dynamic, right) {
200        Cow::Owned(unsafe { (&*right).to_string() })
201    } else {
202        let right = unsafe { &*right };
203        if right.is_str() { Cow::Borrowed(right.as_str()) } else { Cow::Owned(right.to_string()) }
204    };
205    unsafe {
206        match &mut *left {
207            Dynamic::StringBuf(text) => text.push_str(suffix.as_ref()),
208            Dynamic::String(text) => {
209                let mut out = String::with_capacity(text.len() + suffix.len());
210                out.push_str(text.as_str());
211                out.push_str(suffix.as_ref());
212                *left = Dynamic::StringBuf(out);
213            }
214            value => {
215                let prefix = value.to_string();
216                let mut out = String::with_capacity(prefix.len() + suffix.len());
217                out.push_str(&prefix);
218                out.push_str(suffix.as_ref());
219                *value = Dynamic::StringBuf(out);
220            }
221        }
222    }
223    left
224}
225
226pub(crate) extern "C" fn struct_from_ptr(addr: i64, ty: i64) -> *const Dynamic {
227    let ty = unsafe { (&*(ty as *const Type)).clone() };
228    alloc_dynamic(Dynamic::owned_struct_from_ptr(addr as usize, ty))
229}
230
231pub(crate) extern "C" fn array_from_ptr(addr: i64, ty: i64) -> *const Dynamic {
232    if addr == 0 || ty == 0 {
233        return alloc_dynamic(Dynamic::Null);
234    }
235    let ty = unsafe { &*(ty as *const Type) };
236    alloc_dynamic(dynamic_from_ptr(addr as *const u8, ty))
237}
238
239pub(crate) extern "C" fn array_to_ptr(dst: *mut u8, value: *const Dynamic, ty: i64) {
240    if dst.is_null() || value.is_null() || ty == 0 {
241        return;
242    }
243    let ty = unsafe { &*(ty as *const Type) };
244    write_dynamic_to_ptr(dst, unsafe { &*value }, ty);
245}
246
247fn dynamic_from_ptr(addr: *const u8, ty: &Type) -> Dynamic {
248    if addr.is_null() {
249        return Dynamic::Null;
250    }
251    match ty {
252        Type::Bool => Dynamic::Bool(unsafe { std::ptr::read_unaligned(addr) } != 0),
253        Type::I8 => Dynamic::I8(unsafe { std::ptr::read_unaligned(addr as *const i8) }),
254        Type::U8 => Dynamic::U8(unsafe { std::ptr::read_unaligned(addr) }),
255        Type::I16 => Dynamic::I16(unsafe { std::ptr::read_unaligned(addr as *const i16) }),
256        Type::U16 => Dynamic::U16(unsafe { std::ptr::read_unaligned(addr as *const u16) }),
257        Type::I32 => Dynamic::I32(unsafe { std::ptr::read_unaligned(addr as *const i32) }),
258        Type::U32 => Dynamic::U32(unsafe { std::ptr::read_unaligned(addr as *const u32) }),
259        Type::I64 => Dynamic::I64(unsafe { std::ptr::read_unaligned(addr as *const i64) }),
260        Type::U64 => Dynamic::U64(unsafe { std::ptr::read_unaligned(addr as *const u64) }),
261        Type::F32 => Dynamic::F32(unsafe { std::ptr::read_unaligned(addr as *const f32) }),
262        Type::F64 => Dynamic::F64(unsafe { std::ptr::read_unaligned(addr as *const f64) }),
263        Type::Array(elem_ty, len) => {
264            let width = elem_ty.storage_width() as usize;
265            let values = (0..*len as usize).map(|idx| unsafe { dynamic_from_ptr(addr.add(idx * width), elem_ty) }).collect();
266            Dynamic::list(values)
267        }
268        Type::Struct { fields, .. } => {
269            let mut map = BTreeMap::new();
270            let (_, offsets) = Type::struct_layout(fields);
271            for ((name, field_ty), offset) in fields.iter().zip(offsets) {
272                let value = unsafe { dynamic_from_ptr(addr.add(offset as usize), field_ty) };
273                map.insert(name.clone(), value);
274            }
275            Dynamic::map(map)
276        }
277        _ => {
278            let ptr = unsafe { std::ptr::read_unaligned(addr as *const *const Dynamic) };
279            if ptr.is_null() { Dynamic::Null } else { unsafe { (&*ptr).deep_clone() } }
280        }
281    }
282}
283
284fn write_dynamic_to_ptr(dst: *mut u8, value: &Dynamic, ty: &Type) {
285    if dst.is_null() {
286        return;
287    }
288    match ty {
289        Type::Bool => unsafe { std::ptr::write_unaligned(dst, if value.is_true() { 1 } else { 0 }) },
290        Type::I8 => unsafe { std::ptr::write_unaligned(dst as *mut i8, value.clone().try_into().unwrap_or_default()) },
291        Type::U8 => unsafe { std::ptr::write_unaligned(dst, value.clone().try_into().unwrap_or_default()) },
292        Type::I16 => unsafe { std::ptr::write_unaligned(dst as *mut i16, value.clone().try_into().unwrap_or_default()) },
293        Type::U16 => unsafe { std::ptr::write_unaligned(dst as *mut u16, value.clone().try_into().unwrap_or_default()) },
294        Type::I32 => unsafe { std::ptr::write_unaligned(dst as *mut i32, value.clone().try_into().unwrap_or_default()) },
295        Type::U32 => unsafe { std::ptr::write_unaligned(dst as *mut u32, value.clone().try_into().unwrap_or_default()) },
296        Type::I64 => unsafe { std::ptr::write_unaligned(dst as *mut i64, value.clone().try_into().unwrap_or_default()) },
297        Type::U64 => unsafe { std::ptr::write_unaligned(dst as *mut u64, value.clone().try_into().unwrap_or_default()) },
298        Type::F32 => unsafe { std::ptr::write_unaligned(dst as *mut f32, f32::try_from(value.clone()).unwrap_or_default()) },
299        Type::F64 => unsafe { std::ptr::write_unaligned(dst as *mut f64, value.clone().try_into().unwrap_or_default()) },
300        Type::Array(elem_ty, len) => {
301            let width = elem_ty.storage_width() as usize;
302            for idx in 0..*len as usize {
303                let item = value.get_idx(idx).unwrap_or(Dynamic::Null);
304                unsafe { write_dynamic_to_ptr(dst.add(idx * width), &item, elem_ty) };
305            }
306        }
307        Type::Struct { fields, .. } => {
308            let (_, offsets) = Type::struct_layout(fields);
309            for ((name, field_ty), offset) in fields.iter().zip(offsets) {
310                let item = value.get_dynamic(name.as_str()).unwrap_or(Dynamic::Null);
311                unsafe { write_dynamic_to_ptr(dst.add(offset as usize), &item, field_ty) };
312            }
313        }
314        _ => {
315            let ptr = alloc_dynamic(value.deep_clone());
316            unsafe { std::ptr::write_unaligned(dst as *mut usize, ptr as usize) };
317        }
318    }
319}
320
321pub(crate) extern "C" fn import_with_vm(context: *const Weak<RwLock<JITRunTime>>, addr: *const Dynamic, path: *const Dynamic) -> bool {
322    if addr.is_null() || path.is_null() {
323        return false;
324    }
325    super::with_native_context(context, |jit| {
326        let name = unsafe { &*addr }.as_str();
327        let path = unsafe { &*path }.as_str();
328        jit.import(name, path)
329    })
330    .map_err(|e| log::error!("import failed: {e:#}"))
331    .is_ok()
332}
333
334pub(crate) extern "C" fn spawn_with_vm(context: *const Weak<RwLock<JITRunTime>>, fn_name: *const Dynamic, args: *const Dynamic) -> bool {
335    if context.is_null() || fn_name.is_null() {
336        return false;
337    }
338    let fn_name = unsafe { (&*fn_name).as_str().to_string() };
339    if fn_name.is_empty() {
340        return false;
341    }
342    let args = if args.is_null() { Dynamic::Null } else { unsafe { (&*args).deep_clone() } };
343    let context = unsafe { (&*context).clone() };
344    std::thread::Builder::new()
345        .name(format!("zust:{fn_name}"))
346        .spawn(move || {
347            if let Err(err) = spawn_run(context, fn_name.as_str(), args) {
348                log::error!("spawn {fn_name} failed: {err:?}");
349            }
350        })
351        .is_ok()
352}
353
354fn spawn_args(args: Dynamic) -> Vec<Dynamic> {
355    match args {
356        Dynamic::Null => Vec::new(),
357        Dynamic::List(values) => values.read().iter().map(Dynamic::deep_clone).collect(),
358        value => vec![value],
359    }
360}
361
362fn spawn_run(context: Weak<RwLock<JITRunTime>>, fn_name: &str, args: Dynamic) -> Result<()> {
363    let args = spawn_args(args);
364    if args.len() > 16 {
365        anyhow::bail!("spawn supports at most 16 args, got {}", args.len());
366    }
367    let arg_tys = vec![Type::Any; args.len()];
368    let (ptr, ret_ty) = super::with_native_context(&context as *const Weak<RwLock<JITRunTime>>, |vm| vm.jit.write().get_fn_ptr(fn_name, &arg_tys))?;
369    let args: Vec<Box<Dynamic>> = args.into_iter().map(Box::new).collect();
370    let ptrs: Vec<*const Dynamic> = args.iter().map(|arg| arg.as_ref() as *const Dynamic).collect();
371    call_jit_isolated(|| unsafe { call_spawned(ptr, &ret_ty, &ptrs) })
372}
373
374pub(crate) extern "C" fn spawn_ptr(fn_ptr: i64, ret_ty: i64, args: *const Dynamic) -> bool {
375    if fn_ptr == 0 || ret_ty == 0 {
376        return false;
377    }
378    let fn_ptr = fn_ptr as usize;
379    let ret_ty = unsafe { (&*(ret_ty as *const Type)).clone() };
380    let args = if args.is_null() { Dynamic::Null } else { unsafe { (&*args).deep_clone() } };
381    std::thread::Builder::new()
382        .name("zust:closure".to_string())
383        .spawn(move || {
384            if let Err(err) = spawn_run_ptr(fn_ptr, ret_ty, args) {
385                log::error!("spawn closure failed: {err:?}");
386            }
387        })
388        .is_ok()
389}
390
391pub(crate) extern "C" fn callback_new(fn_ptr: i64, ret_ty: i64, explicit_arg_len: i64, captures: *const Dynamic) -> *const Dynamic {
392    if fn_ptr == 0 || ret_ty == 0 {
393        return alloc_dynamic(Dynamic::Null);
394    }
395    let ret_ty = unsafe { (&*(ret_ty as *const Type)).clone() };
396    let explicit_arg_len = usize::try_from(explicit_arg_len).unwrap_or(usize::MAX);
397    let captures = if captures.is_null() {
398        Vec::new()
399    } else {
400        // 闭包捕获按引用共享:浅 clone 只复制 Arc 句柄,多个闭包捕获同一个
401        // Map/List 时读写同一份数据(spawn 跨线程才需要 deep_clone 隔离)。
402        match unsafe { &*captures } {
403            Dynamic::List(values) => values.read().to_vec(),
404            value => vec![value.clone()],
405        }
406    };
407    alloc_dynamic(Dynamic::custom(ZustCallback::new_with_arg_len(fn_ptr as usize, ret_ty, explicit_arg_len, captures)))
408}
409
410pub(crate) extern "C" fn callback_call(callback: *const Dynamic, args: *const Dynamic) -> *const Dynamic {
411    if callback.is_null() {
412        return alloc_dynamic(Dynamic::Null);
413    }
414    let Some(callback) = (unsafe { &*callback }).as_custom::<ZustCallback>().cloned() else {
415        return alloc_dynamic(Dynamic::Null);
416    };
417    let args = if args.is_null() {
418        Vec::new()
419    } else {
420        match unsafe { &*args } {
421            Dynamic::List(values) => values.read().to_vec(),
422            Dynamic::Null => Vec::new(),
423            value => vec![value.clone()],
424        }
425    };
426    match callback.call(args) {
427        Ok(value) => alloc_dynamic(value),
428        Err(err) => {
429            log::error!("callback call failed: {err:?}");
430            alloc_dynamic(Dynamic::Null)
431        }
432    }
433}
434
435fn spawn_run_ptr(fn_ptr: usize, ret_ty: Type, args: Dynamic) -> Result<()> {
436    let args = spawn_args(args);
437    if args.len() > 16 {
438        anyhow::bail!("spawn supports at most 16 args, got {}", args.len());
439    }
440    let args: Vec<Box<Dynamic>> = args.into_iter().map(Box::new).collect();
441    let ptrs: Vec<*const Dynamic> = args.iter().map(|arg| arg.as_ref() as *const Dynamic).collect();
442    call_jit_isolated(|| unsafe { call_spawned(fn_ptr as *const u8, &ret_ty, &ptrs) })
443}
444
445/// 脚本执行的隔离边界。
446///
447/// JIT 代码无法返回 `Result`,运行期错误(整数除零等)通过 [`dynamic`] 的线程
448/// 局部 fault 标志上报(由 `__vm_arith_fault` 与 `Dynamic` 的除法守卫设置)。这里
449/// 在调用前清掉陈旧标志,调用后读取它,把"脚本出错"降级为一次失败的 `Result`,
450/// 而不是让进程崩溃。`catch_unwind` 额外兜住宿主侧 Rust 代码(参数编组、返回值
451/// 取出)的 panic。
452///
453/// 注意:若 panic 发生在 JIT 的 `extern "C"` 帧之内再向外穿越,Rust 默认会 abort,
454/// `catch_unwind` 无法拦截——这类路径靠的是各 native 助手不 panic(除零已改为置
455/// fault 标志)。
456pub(crate) fn call_jit_isolated<T>(f: impl FnOnce() -> Result<T>) -> Result<T> {
457    let _ = dynamic::take_fault();
458    let outcome = std::panic::catch_unwind(std::panic::AssertUnwindSafe(f));
459    match outcome {
460        Ok(inner) => match dynamic::take_fault() {
461            Some(reason) => Err(anyhow!("脚本运行期错误: {}", reason)),
462            None => inner,
463        },
464        Err(_) => Err(anyhow!("脚本执行 panic,已隔离")),
465    }
466}
467
468unsafe fn call_callback(ptr: *const u8, ret_ty: &Type, args: &[*const Dynamic]) -> Result<Dynamic> {
469    macro_rules! callback_arg_ty {
470        ($arg:ident) => {
471            *const Dynamic
472        };
473    }
474
475    macro_rules! callback_args {
476        ($body:ident $(, $extra:tt)*) => {
477            match args {
478                [] => $body!($($extra),*;),
479                [a] => $body!($($extra),*; a),
480                [a, b] => $body!($($extra),*; a, b),
481                [a, b, c] => $body!($($extra),*; a, b, c),
482                [a, b, c, d] => $body!($($extra),*; a, b, c, d),
483                [a, b, c, d, e] => $body!($($extra),*; a, b, c, d, e),
484                [a, b, c, d, e, f] => $body!($($extra),*; a, b, c, d, e, f),
485                [a, b, c, d, e, f, g] => $body!($($extra),*; a, b, c, d, e, f, g),
486                [a, b, c, d, e, f, g, h] => $body!($($extra),*; a, b, c, d, e, f, g, h),
487                [a, b, c, d, e, f, g, h, i] => $body!($($extra),*; a, b, c, d, e, f, g, h, i),
488                [a, b, c, d, e, f, g, h, i, j] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j),
489                [a, b, c, d, e, f, g, h, i, j, k] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k),
490                [a, b, c, d, e, f, g, h, i, j, k, l] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l),
491                [a, b, c, d, e, f, g, h, i, j, k, l, m] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m),
492                [a, b, c, d, e, f, g, h, i, j, k, l, m, n] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n),
493                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o),
494                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p),
495                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q),
496                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r),
497                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s),
498                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t),
499                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u),
500                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v),
501                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w),
502                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x),
503                _ => anyhow::bail!("callback supports at most 24 args including captures, got {}", args.len()),
504            }
505        };
506    }
507
508    macro_rules! call_void_body {
509        (; $($arg:ident),*) => {{
510            let fn_ptr: extern "C" fn($(callback_arg_ty!($arg)),*) = unsafe { std::mem::transmute(ptr) };
511            fn_ptr($(*$arg),*)
512        }};
513    }
514
515    macro_rules! call_void {
516        () => {
517            callback_args!(call_void_body)
518        };
519    }
520
521    macro_rules! call_ret_body {
522        ($ret:ty, $dynamic:expr; $($arg:ident),*) => {{
523            let fn_ptr: extern "C" fn($(callback_arg_ty!($arg)),*) -> $ret = unsafe { std::mem::transmute(ptr) };
524            $dynamic(fn_ptr($(*$arg),*))
525        }};
526    }
527
528    macro_rules! call_ret {
529        ($ret:ty, $dynamic:expr) => {{ callback_args!(call_ret_body, $ret, $dynamic) }};
530    }
531
532    if ret_ty.is_void() {
533        call_void!();
534        Ok(Dynamic::Null)
535    } else if ret_ty.is_bool() {
536        call_ret!(bool, |value| Ok(Dynamic::Bool(value)))
537    } else if ret_ty.is_float() {
538        if ret_ty.is_f64() { call_ret!(f64, |value| Ok(Dynamic::F64(value))) } else { call_ret!(f32, |value| Ok(Dynamic::F32(value))) }
539    } else if ret_ty.is_int() || ret_ty.is_uint() {
540        match ret_ty {
541            Type::I8 => call_ret!(i8, |value| Ok(Dynamic::I8(value))),
542            Type::U8 => call_ret!(u8, |value| Ok(Dynamic::U8(value))),
543            Type::I16 => call_ret!(i16, |value| Ok(Dynamic::I16(value))),
544            Type::U16 => call_ret!(u16, |value| Ok(Dynamic::U16(value))),
545            Type::I32 => call_ret!(i32, |value| Ok(Dynamic::I32(value))),
546            Type::U32 => call_ret!(u32, |value| Ok(Dynamic::U32(value))),
547            Type::I64 => call_ret!(i64, |value| Ok(Dynamic::I64(value))),
548            Type::U64 => call_ret!(u64, |value| Ok(Dynamic::U64(value))),
549            _ => unreachable!(),
550        }
551    } else if ret_ty.is_struct() || ret_ty.is_array() || ret_ty.is_vec() {
552        log::warn!("callback returns {ret_ty:?} — not supported, discarding");
553        call_ret!(*const u8, |_| Ok(Dynamic::Null))
554    } else {
555        call_ret!(*const Dynamic, |ptr| unsafe { Ok((*take_dynamic_return(ptr)).deep_clone()) })
556    }
557}
558
559unsafe fn call_spawned(ptr: *const u8, ret_ty: &Type, args: &[*const Dynamic]) -> Result<()> {
560    macro_rules! call_void {
561        () => {
562            match args {
563                [] => unsafe { std::mem::transmute::<_, extern "C" fn()>(ptr)() },
564                [a] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic)>(ptr)(*a) },
565                [a, b] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic)>(ptr)(*a, *b) },
566                [a, b, c] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c) },
567                [a, b, c, d] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c, *d) },
568                [a, b, c, d, e] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c, *d, *e) },
569                [a, b, c, d, e, f] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c, *d, *e, *f) },
570                [a, b, c, d, e, f, g] => unsafe {
571                    std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c, *d, *e, *f, *g)
572                },
573                [a, b, c, d, e, f, g, h] => unsafe {
574                    std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(
575                        *a, *b, *c, *d, *e, *f, *g, *h,
576                    )
577                },
578                [a, b, c, d, e, f, g, h, i] => unsafe {
579                    std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(
580                        *a, *b, *c, *d, *e, *f, *g, *h, *i,
581                    )
582                },
583                [a, b, c, d, e, f, g, h, i, j] => unsafe {
584                    std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(
585                        ptr,
586                    )(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j)
587                },
588                [a, b, c, d, e, f, g, h, i, j, k] => unsafe {
589                    std::mem::transmute::<
590                        _,
591                        extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic),
592                    >(ptr)(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k)
593                },
594                [a, b, c, d, e, f, g, h, i, j, k, l] => unsafe {
595                    std::mem::transmute::<
596                        _,
597                        extern "C" fn(
598                            *const Dynamic,
599                            *const Dynamic,
600                            *const Dynamic,
601                            *const Dynamic,
602                            *const Dynamic,
603                            *const Dynamic,
604                            *const Dynamic,
605                            *const Dynamic,
606                            *const Dynamic,
607                            *const Dynamic,
608                            *const Dynamic,
609                            *const Dynamic,
610                        ),
611                    >(ptr)(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l)
612                },
613                [a, b, c, d, e, f, g, h, i, j, k, l, m] => unsafe {
614                    std::mem::transmute::<
615                        _,
616                        extern "C" fn(
617                            *const Dynamic,
618                            *const Dynamic,
619                            *const Dynamic,
620                            *const Dynamic,
621                            *const Dynamic,
622                            *const Dynamic,
623                            *const Dynamic,
624                            *const Dynamic,
625                            *const Dynamic,
626                            *const Dynamic,
627                            *const Dynamic,
628                            *const Dynamic,
629                            *const Dynamic,
630                        ),
631                    >(ptr)(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m)
632                },
633                [a, b, c, d, e, f, g, h, i, j, k, l, m, n] => unsafe {
634                    std::mem::transmute::<
635                        _,
636                        extern "C" fn(
637                            *const Dynamic,
638                            *const Dynamic,
639                            *const Dynamic,
640                            *const Dynamic,
641                            *const Dynamic,
642                            *const Dynamic,
643                            *const Dynamic,
644                            *const Dynamic,
645                            *const Dynamic,
646                            *const Dynamic,
647                            *const Dynamic,
648                            *const Dynamic,
649                            *const Dynamic,
650                            *const Dynamic,
651                        ),
652                    >(ptr)(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n)
653                },
654                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o] => unsafe {
655                    std::mem::transmute::<
656                        _,
657                        extern "C" fn(
658                            *const Dynamic,
659                            *const Dynamic,
660                            *const Dynamic,
661                            *const Dynamic,
662                            *const Dynamic,
663                            *const Dynamic,
664                            *const Dynamic,
665                            *const Dynamic,
666                            *const Dynamic,
667                            *const Dynamic,
668                            *const Dynamic,
669                            *const Dynamic,
670                            *const Dynamic,
671                            *const Dynamic,
672                            *const Dynamic,
673                        ),
674                    >(ptr)(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n, *o)
675                },
676                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] => unsafe {
677                    std::mem::transmute::<
678                        _,
679                        extern "C" fn(
680                            *const Dynamic,
681                            *const Dynamic,
682                            *const Dynamic,
683                            *const Dynamic,
684                            *const Dynamic,
685                            *const Dynamic,
686                            *const Dynamic,
687                            *const Dynamic,
688                            *const Dynamic,
689                            *const Dynamic,
690                            *const Dynamic,
691                            *const Dynamic,
692                            *const Dynamic,
693                            *const Dynamic,
694                            *const Dynamic,
695                            *const Dynamic,
696                        ),
697                    >(ptr)(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n, *o, *p)
698                },
699                _ => unreachable!(),
700            }
701        };
702    }
703
704    if ret_ty.is_void() {
705        call_void!();
706        return Ok(());
707    }
708
709    macro_rules! call_ret {
710        ($ret:ty, $drop_result:expr) => {
711            match args {
712                [] => {
713                    let fn_ptr: extern "C" fn() -> $ret = unsafe { std::mem::transmute(ptr) };
714                    $drop_result(fn_ptr());
715                }
716                [a] => {
717                    let fn_ptr: extern "C" fn(*const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
718                    $drop_result(fn_ptr(*a));
719                }
720                [a, b] => {
721                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
722                    $drop_result(fn_ptr(*a, *b));
723                }
724                [a, b, c] => {
725                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
726                    $drop_result(fn_ptr(*a, *b, *c));
727                }
728                [a, b, c, d] => {
729                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
730                    $drop_result(fn_ptr(*a, *b, *c, *d));
731                }
732                [a, b, c, d, e] => {
733                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
734                    $drop_result(fn_ptr(*a, *b, *c, *d, *e));
735                }
736                [a, b, c, d, e, f] => {
737                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
738                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f));
739                }
740                [a, b, c, d, e, f, g] => {
741                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
742                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g));
743                }
744                [a, b, c, d, e, f, g, h] => {
745                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
746                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h));
747                }
748                [a, b, c, d, e, f, g, h, i] => {
749                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret =
750                        unsafe { std::mem::transmute(ptr) };
751                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i));
752                }
753                [a, b, c, d, e, f, g, h, i, j] => {
754                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret =
755                        unsafe { std::mem::transmute(ptr) };
756                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j));
757                }
758                [a, b, c, d, e, f, g, h, i, j, k] => {
759                    let fn_ptr: extern "C" fn(
760                        *const Dynamic,
761                        *const Dynamic,
762                        *const Dynamic,
763                        *const Dynamic,
764                        *const Dynamic,
765                        *const Dynamic,
766                        *const Dynamic,
767                        *const Dynamic,
768                        *const Dynamic,
769                        *const Dynamic,
770                        *const Dynamic,
771                    ) -> $ret = unsafe { std::mem::transmute(ptr) };
772                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k));
773                }
774                [a, b, c, d, e, f, g, h, i, j, k, l] => {
775                    let fn_ptr: extern "C" fn(
776                        *const Dynamic,
777                        *const Dynamic,
778                        *const Dynamic,
779                        *const Dynamic,
780                        *const Dynamic,
781                        *const Dynamic,
782                        *const Dynamic,
783                        *const Dynamic,
784                        *const Dynamic,
785                        *const Dynamic,
786                        *const Dynamic,
787                        *const Dynamic,
788                    ) -> $ret = unsafe { std::mem::transmute(ptr) };
789                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l));
790                }
791                [a, b, c, d, e, f, g, h, i, j, k, l, m] => {
792                    let fn_ptr: extern "C" fn(
793                        *const Dynamic,
794                        *const Dynamic,
795                        *const Dynamic,
796                        *const Dynamic,
797                        *const Dynamic,
798                        *const Dynamic,
799                        *const Dynamic,
800                        *const Dynamic,
801                        *const Dynamic,
802                        *const Dynamic,
803                        *const Dynamic,
804                        *const Dynamic,
805                        *const Dynamic,
806                    ) -> $ret = unsafe { std::mem::transmute(ptr) };
807                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m));
808                }
809                [a, b, c, d, e, f, g, h, i, j, k, l, m, n] => {
810                    let fn_ptr: extern "C" fn(
811                        *const Dynamic,
812                        *const Dynamic,
813                        *const Dynamic,
814                        *const Dynamic,
815                        *const Dynamic,
816                        *const Dynamic,
817                        *const Dynamic,
818                        *const Dynamic,
819                        *const Dynamic,
820                        *const Dynamic,
821                        *const Dynamic,
822                        *const Dynamic,
823                        *const Dynamic,
824                        *const Dynamic,
825                    ) -> $ret = unsafe { std::mem::transmute(ptr) };
826                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n));
827                }
828                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o] => {
829                    let fn_ptr: extern "C" fn(
830                        *const Dynamic,
831                        *const Dynamic,
832                        *const Dynamic,
833                        *const Dynamic,
834                        *const Dynamic,
835                        *const Dynamic,
836                        *const Dynamic,
837                        *const Dynamic,
838                        *const Dynamic,
839                        *const Dynamic,
840                        *const Dynamic,
841                        *const Dynamic,
842                        *const Dynamic,
843                        *const Dynamic,
844                        *const Dynamic,
845                    ) -> $ret = unsafe { std::mem::transmute(ptr) };
846                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n, *o));
847                }
848                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] => {
849                    let fn_ptr: extern "C" fn(
850                        *const Dynamic,
851                        *const Dynamic,
852                        *const Dynamic,
853                        *const Dynamic,
854                        *const Dynamic,
855                        *const Dynamic,
856                        *const Dynamic,
857                        *const Dynamic,
858                        *const Dynamic,
859                        *const Dynamic,
860                        *const Dynamic,
861                        *const Dynamic,
862                        *const Dynamic,
863                        *const Dynamic,
864                        *const Dynamic,
865                        *const Dynamic,
866                    ) -> $ret = unsafe { std::mem::transmute(ptr) };
867                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n, *o, *p));
868                }
869                _ => unreachable!(),
870            }
871        };
872    }
873
874    if ret_ty.is_bool() {
875        call_ret!(bool, |_| {});
876    } else if ret_ty.is_float() {
877        if ret_ty.is_f64() {
878            call_ret!(f64, |_| {});
879        } else {
880            call_ret!(f32, |_| {});
881        }
882    } else if ret_ty.is_int() || ret_ty.is_uint() {
883        match ret_ty {
884            Type::I8 => call_ret!(i8, |_| {}),
885            Type::U8 => call_ret!(u8, |_| {}),
886            Type::I16 => call_ret!(i16, |_| {}),
887            Type::U16 => call_ret!(u16, |_| {}),
888            Type::I32 => call_ret!(i32, |_| {}),
889            Type::U32 => call_ret!(u32, |_| {}),
890            Type::I64 => call_ret!(i64, |_| {}),
891            Type::U64 => call_ret!(u64, |_| {}),
892            _ => unreachable!(),
893        }
894    } else if ret_ty.is_struct() || ret_ty.is_array() || ret_ty.is_vec() {
895        log::warn!("spawned fn returns {ret_ty:?} — not supported, discarding");
896        call_ret!(*const u8, |_| {});
897    } else {
898        call_ret!(*const Dynamic, |ptr| drop(unsafe { take_dynamic_return(ptr) }));
899    }
900    Ok(())
901}
902
903extern "C" fn any_len(addr: *const Dynamic) -> i64 {
904    if addr.is_null() { 0 } else { unsafe { (&*addr).len() as i64 } }
905}
906
907extern "C" fn any_keys(addr: *const Dynamic) -> *const Dynamic {
908    if addr.is_null() {
909        return alloc_dynamic(Dynamic::list(Vec::new()));
910    }
911    let keys = match unsafe { &*addr } {
912        Dynamic::Map(map) => map.read().keys().map(|key| Dynamic::from(key.as_str())).collect(),
913        _ => Vec::new(),
914    };
915    alloc_dynamic(Dynamic::list(keys))
916}
917
918extern "C" fn any_iter(addr: *const Dynamic) -> *const Dynamic {
919    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).clone().into_iter() }) }
920}
921
922extern "C" fn any_next(addr: *const Dynamic) -> *const Dynamic {
923    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (&mut *(addr as *mut Dynamic)).next().unwrap_or(Dynamic::Null) }) }
924}
925
926extern "C" fn any_next_pair(addr: *const Dynamic) -> *const Dynamic {
927    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (&mut *(addr as *mut Dynamic)).next_pair().unwrap_or(Dynamic::Null) }) }
928}
929
930extern "C" fn any_push(addr: *mut Dynamic, value: *mut Dynamic) {
931    if !addr.is_null() && !value.is_null() {
932        unsafe {
933            (&mut *addr).push_dynamic((&*value).clone());
934        }
935    }
936}
937
938extern "C" fn any_pop(addr: *mut Dynamic) -> *const Dynamic {
939    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).pop().unwrap_or(Dynamic::Null) }) }
940}
941
942extern "C" fn get_key(addr: *const Dynamic, key: *const Dynamic) -> *const Dynamic {
943    if addr.is_null() || key.is_null() {
944        any_null()
945    } else {
946        let key: &str = unsafe { &*key }.as_str();
947        alloc_dynamic(unsafe { (*addr).get_dynamic(key).unwrap_or(Dynamic::Null) })
948    }
949}
950
951extern "C" fn del_key(addr: *const Dynamic, key: *const Dynamic) -> *const Dynamic {
952    if addr.is_null() || key.is_null() {
953        any_null()
954    } else {
955        let key: &str = unsafe { &*key }.as_str();
956        alloc_dynamic(unsafe { (*addr).remove_dynamic(key).unwrap_or(Dynamic::Null) })
957    }
958}
959
960extern "C" fn contains(addr: *const Dynamic, key: *const Dynamic) -> bool {
961    if addr.is_null() || key.is_null() {
962        false
963    } else {
964        let key: &str = unsafe { &*key }.as_str();
965        unsafe { (*addr).contains(key) }
966    }
967}
968
969extern "C" fn starts_with(addr: *const Dynamic, prefix: *const Dynamic) -> bool {
970    if addr.is_null() || prefix.is_null() {
971        false
972    } else {
973        let prefix: &str = unsafe { &*prefix }.as_str();
974        unsafe { (*addr).starts_with(prefix) }
975    }
976}
977
978extern "C" fn ends_with(addr: *const Dynamic, suffix: *const Dynamic) -> bool {
979    if addr.is_null() || suffix.is_null() {
980        false
981    } else {
982        let suffix: &str = unsafe { &*suffix }.as_str();
983        unsafe { (*addr).ends_with(suffix) }
984    }
985}
986
987extern "C" fn get_idx(addr: *const Dynamic, idx: i64) -> *const Dynamic {
988    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).get_idx(idx as usize).unwrap_or(Dynamic::Null) }) }
989}
990
991fn list_get_idx_value(addr: *const Dynamic, idx: i64) -> Option<Dynamic> {
992    if addr.is_null() {
993        return None;
994    }
995    let Ok(idx) = usize::try_from(idx) else {
996        return None;
997    };
998    unsafe { (&*addr).get_idx(idx) }
999}
1000
1001fn dynamic_as_int(value: Dynamic) -> Option<i64> {
1002    value.as_int().or_else(|| value.as_uint().and_then(|value| i64::try_from(value).ok()))
1003}
1004
1005fn dynamic_as_uint(value: Dynamic) -> Option<u64> {
1006    value.as_uint().or_else(|| value.as_int().and_then(|value| u64::try_from(value).ok()))
1007}
1008
1009macro_rules! myvec_list_native {
1010    ($push:ident, $get_idx:ident, $set_idx:ident, $vec:ident, $dynamic:ident, $ty:ty, $fallback:expr) => {
1011        extern "C" fn $push(addr: *mut Dynamic, value: $ty) {
1012            if addr.is_null() {
1013                return;
1014            }
1015            unsafe {
1016                match &mut *addr {
1017                    Dynamic::$vec(values) => values.push(value),
1018                    list => {
1019                        list.push_dynamic(Dynamic::$dynamic(value));
1020                    }
1021                }
1022            }
1023        }
1024
1025        extern "C" fn $get_idx(addr: *const Dynamic, idx: i64) -> $ty {
1026            if addr.is_null() {
1027                return <$ty>::default();
1028            }
1029            let Ok(idx) = usize::try_from(idx) else {
1030                return <$ty>::default();
1031            };
1032            unsafe {
1033                match &*addr {
1034                    Dynamic::$vec(values) => values.get(idx).unwrap_or_default(),
1035                    values => values.get_idx(idx).and_then($fallback).unwrap_or_default(),
1036                }
1037            }
1038        }
1039
1040        extern "C" fn $set_idx(addr: *mut Dynamic, idx: i64, value: $ty) {
1041            if addr.is_null() {
1042                return;
1043            }
1044            let Ok(idx) = usize::try_from(idx) else {
1045                return;
1046            };
1047            unsafe {
1048                match &mut *addr {
1049                    Dynamic::$vec(values) => values.set(idx, value),
1050                    list => list.set_idx(idx, Dynamic::$dynamic(value)),
1051                }
1052            }
1053        }
1054    };
1055}
1056
1057macro_rules! stdvec_list_native {
1058    ($push:ident, $get_idx:ident, $set_idx:ident, $vec:ident, $dynamic:ident, $ty:ty, $fallback:expr) => {
1059        extern "C" fn $push(addr: *mut Dynamic, value: $ty) {
1060            if addr.is_null() {
1061                return;
1062            }
1063            unsafe {
1064                match &mut *addr {
1065                    Dynamic::$vec(values) => values.push(value),
1066                    list => {
1067                        list.push_dynamic(Dynamic::$dynamic(value));
1068                    }
1069                }
1070            }
1071        }
1072
1073        extern "C" fn $get_idx(addr: *const Dynamic, idx: i64) -> $ty {
1074            if addr.is_null() {
1075                return <$ty>::default();
1076            }
1077            let Ok(idx) = usize::try_from(idx) else {
1078                return <$ty>::default();
1079            };
1080            unsafe {
1081                match &*addr {
1082                    Dynamic::$vec(values) => values.get(idx).copied().unwrap_or_default(),
1083                    values => values.get_idx(idx).and_then($fallback).unwrap_or_default(),
1084                }
1085            }
1086        }
1087
1088        extern "C" fn $set_idx(addr: *mut Dynamic, idx: i64, value: $ty) {
1089            if addr.is_null() {
1090                return;
1091            }
1092            let Ok(idx) = usize::try_from(idx) else {
1093                return;
1094            };
1095            unsafe {
1096                match &mut *addr {
1097                    Dynamic::$vec(values) => {
1098                        if let Some(slot) = values.get_mut(idx) {
1099                            *slot = value;
1100                        }
1101                    }
1102                    list => list.set_idx(idx, Dynamic::$dynamic(value)),
1103                }
1104            }
1105        }
1106    };
1107}
1108
1109myvec_list_native!(list_i8_push, list_i8_get_idx, list_i8_set_idx, VecI8, I8, i8, |value: Dynamic| dynamic_as_int(value).map(|value| value as i8));
1110myvec_list_native!(list_u16_push, list_u16_get_idx, list_u16_set_idx, VecU16, U16, u16, |value: Dynamic| dynamic_as_uint(value).map(|value| value as u16));
1111myvec_list_native!(list_i16_push, list_i16_get_idx, list_i16_set_idx, VecI16, I16, i16, |value: Dynamic| dynamic_as_int(value).map(|value| value as i16));
1112myvec_list_native!(list_u32_push, list_u32_get_idx, list_u32_set_idx, VecU32, U32, u32, |value: Dynamic| dynamic_as_uint(value).map(|value| value as u32));
1113myvec_list_native!(list_i32_push, list_i32_get_idx, list_i32_set_idx, VecI32, I32, i32, |value: Dynamic| dynamic_as_int(value).map(|value| value as i32));
1114myvec_list_native!(list_f32_push, list_f32_get_idx, list_f32_set_idx, VecF32, F32, f32, |value: Dynamic| value.as_float().map(|value| value as f32));
1115stdvec_list_native!(list_u64_push, list_u64_get_idx, list_u64_set_idx, VecU64, U64, u64, dynamic_as_uint);
1116stdvec_list_native!(list_i64_push, list_i64_get_idx, list_i64_set_idx, VecI64, I64, i64, dynamic_as_int);
1117stdvec_list_native!(list_f64_push, list_f64_get_idx, list_f64_set_idx, VecF64, F64, f64, |value: Dynamic| value.as_float());
1118
1119extern "C" fn list_u64_data_ptr(addr: *const Dynamic) -> *const u64 {
1120    if addr.is_null() {
1121        return std::ptr::null();
1122    }
1123    unsafe {
1124        match &*addr {
1125            Dynamic::VecU64(values) => values.as_ptr(),
1126            _ => std::ptr::null(),
1127        }
1128    }
1129}
1130
1131extern "C" fn list_i64_data_ptr(addr: *const Dynamic) -> *const i64 {
1132    if addr.is_null() {
1133        return std::ptr::null();
1134    }
1135    unsafe {
1136        match &*addr {
1137            Dynamic::VecI64(values) => values.as_ptr(),
1138            _ => std::ptr::null(),
1139        }
1140    }
1141}
1142
1143extern "C" fn list_f64_data_ptr(addr: *const Dynamic) -> *const f64 {
1144    if addr.is_null() {
1145        return std::ptr::null();
1146    }
1147    unsafe {
1148        match &*addr {
1149            Dynamic::VecF64(values) => values.as_ptr(),
1150            _ => std::ptr::null(),
1151        }
1152    }
1153}
1154
1155extern "C" fn list_i8_get_idx_i64(addr: *const Dynamic, idx: i64) -> i64 {
1156    list_get_idx_value(addr, idx).and_then(dynamic_as_int).map(|value| value as i8 as i64).unwrap_or_default()
1157}
1158
1159extern "C" fn list_u16_get_idx_i64(addr: *const Dynamic, idx: i64) -> i64 {
1160    list_get_idx_value(addr, idx).and_then(dynamic_as_uint).map(|value| value as u16 as i64).unwrap_or_default()
1161}
1162
1163extern "C" fn list_i16_get_idx_i64(addr: *const Dynamic, idx: i64) -> i64 {
1164    list_get_idx_value(addr, idx).and_then(dynamic_as_int).map(|value| value as i16 as i64).unwrap_or_default()
1165}
1166
1167extern "C" fn list_bool_push(addr: *mut Dynamic, value: bool) {
1168    if !addr.is_null() {
1169        unsafe {
1170            (&mut *addr).push_dynamic(Dynamic::Bool(value));
1171        }
1172    }
1173}
1174
1175extern "C" fn list_bool_get_idx(addr: *const Dynamic, idx: i64) -> bool {
1176    if addr.is_null() {
1177        return false;
1178    }
1179    let Ok(idx) = usize::try_from(idx) else {
1180        return false;
1181    };
1182    unsafe { (&*addr).get_idx(idx).is_some_and(|value| value.is_true() || value.as_int().is_some_and(|value| value != 0) || value.as_uint().is_some_and(|value| value != 0)) }
1183}
1184
1185extern "C" fn list_bool_get_idx_i64(addr: *const Dynamic, idx: i64) -> i64 {
1186    list_get_idx_value(addr, idx).map(|value| i64::from(value.is_true() || value.as_int().is_some_and(|value| value != 0) || value.as_uint().is_some_and(|value| value != 0))).unwrap_or_default()
1187}
1188
1189extern "C" fn list_bool_set_idx(addr: *mut Dynamic, idx: i64, value: bool) {
1190    if addr.is_null() {
1191        return;
1192    }
1193    let Ok(idx) = usize::try_from(idx) else {
1194        return;
1195    };
1196    unsafe {
1197        (&mut *addr).set_idx(idx, Dynamic::Bool(value));
1198    }
1199}
1200
1201extern "C" fn list_u8_push(addr: *mut Dynamic, value: u8) {
1202    if !addr.is_null() {
1203        unsafe {
1204            (&mut *addr).push_dynamic(Dynamic::U8(value));
1205        }
1206    }
1207}
1208
1209extern "C" fn list_u8_get_idx(addr: *const Dynamic, idx: i64) -> u8 {
1210    if addr.is_null() {
1211        return 0;
1212    }
1213    let Ok(idx) = usize::try_from(idx) else {
1214        return 0;
1215    };
1216    unsafe { (&*addr).get_idx(idx).and_then(dynamic_as_uint).map(|value| value as u8).unwrap_or(0) }
1217}
1218
1219extern "C" fn list_u8_get_idx_i64(addr: *const Dynamic, idx: i64) -> i64 {
1220    list_get_idx_value(addr, idx).and_then(dynamic_as_uint).map(|value| value as u8 as i64).unwrap_or_default()
1221}
1222
1223extern "C" fn list_u8_set_idx(addr: *mut Dynamic, idx: i64, value: u8) {
1224    if addr.is_null() {
1225        return;
1226    }
1227    let Ok(idx) = usize::try_from(idx) else {
1228        return;
1229    };
1230    unsafe {
1231        (&mut *addr).set_idx(idx, Dynamic::U8(value));
1232    }
1233}
1234
1235extern "C" fn list_str_push(addr: *mut Dynamic, value: *const Dynamic) {
1236    if addr.is_null() || value.is_null() {
1237        return;
1238    }
1239    unsafe {
1240        (&mut *addr).push_dynamic((&*value).clone());
1241    }
1242}
1243
1244extern "C" fn list_str_get_idx(addr: *const Dynamic, idx: i64) -> *const Dynamic {
1245    if addr.is_null() {
1246        return any_null();
1247    };
1248    let Ok(idx) = usize::try_from(idx) else {
1249        return any_null();
1250    };
1251    if let Some(value) = unsafe { (&*addr).get_idx(idx) } { alloc_dynamic(value) } else { any_null() }
1252}
1253
1254extern "C" fn list_str_set_idx(addr: *mut Dynamic, idx: i64, value: *const Dynamic) {
1255    if addr.is_null() || value.is_null() {
1256        return;
1257    }
1258    let Ok(idx) = usize::try_from(idx) else {
1259        return;
1260    };
1261    unsafe {
1262        (&mut *addr).set_idx(idx, (&*value).clone());
1263    }
1264}
1265
1266extern "C" fn slice(addr: *const Dynamic, start: i64, stop: *const Dynamic, inclusive: bool) -> *const Dynamic {
1267    if addr.is_null() {
1268        return any_null();
1269    }
1270
1271    let value = unsafe { &*addr };
1272    let len = value.len() as i64;
1273    let start = start.clamp(0, len) as usize;
1274    let mut stop = if stop.is_null() {
1275        len
1276    } else {
1277        let raw = unsafe { &*stop };
1278        if raw.is_null() { len } else { raw.as_int().unwrap_or(len) }
1279    };
1280    if inclusive && stop < len {
1281        stop += 1;
1282    }
1283    let stop = stop.clamp(start as i64, len) as usize;
1284
1285    let sliced = if value.is_str() {
1286        Dynamic::from(value.as_str().chars().skip(start).take(stop.saturating_sub(start)).collect::<String>())
1287    } else {
1288        match value {
1289            Dynamic::List(list) => Dynamic::list(list.read()[start..stop].to_vec()),
1290            _ => Dynamic::Null,
1291        }
1292    };
1293    alloc_dynamic(sliced)
1294}
1295
1296extern "C" fn set_key(addr: *mut Dynamic, key: *const Dynamic, value: *const Dynamic) {
1297    if addr.is_null() || key.is_null() {
1298        return;
1299    }
1300    let key: &str = unsafe { &*key }.as_str();
1301    unsafe { (&mut *addr).set_dynamic(key.into(), (&*value).clone()) }
1302}
1303
1304extern "C" fn set_idx(addr: *mut Dynamic, idx: i64, value: *const Dynamic) {
1305    if addr.is_null() {
1306        return;
1307    }
1308    unsafe { (&mut *addr).set_idx(idx as usize, (&*value).clone()) }
1309}
1310
1311extern "C" fn any_from_i64(v: i64) -> *const Dynamic {
1312    alloc_dynamic(Dynamic::I64(v))
1313}
1314
1315extern "C" fn any_from_u64(v: u64) -> *const Dynamic {
1316    alloc_dynamic(Dynamic::U64(v))
1317}
1318
1319extern "C" fn any_from_bool(v: bool) -> *const Dynamic {
1320    alloc_dynamic(Dynamic::Bool(v))
1321}
1322
1323extern "C" fn any_to_i64(addr: *const Dynamic) -> i64 {
1324    if addr.is_null() {
1325        return 0;
1326    }
1327    unsafe {
1328        let value = &*addr;
1329        value
1330            .as_int()
1331            .or_else(|| value.as_float().map(|value| value as i64))
1332            .or_else(|| {
1333                let text = value.as_str();
1334                let text = text.trim();
1335                if text.is_empty() { None } else { text.parse::<i64>().ok().or_else(|| text.parse::<f64>().ok().map(|value| value as i64)) }
1336            })
1337            .unwrap_or(0)
1338    }
1339}
1340
1341extern "C" fn any_to_bool(addr: *const Dynamic) -> bool {
1342    if addr.is_null() {
1343        return false;
1344    }
1345    unsafe {
1346        let value = &*addr;
1347        if let Some(v) = value.as_bool() {
1348            v
1349        } else if let Some(v) = value.as_int() {
1350            v != 0
1351        } else if let Some(v) = value.as_float() {
1352            v != 0.0
1353        } else {
1354            !value.is_null()
1355        }
1356    }
1357}
1358
1359extern "C" fn any_from_f64(v: f64) -> *const Dynamic {
1360    alloc_dynamic(Dynamic::F64(v))
1361}
1362
1363extern "C" fn any_split(addr: *mut Dynamic, s: *const Dynamic) -> *const Dynamic {
1364    if addr.is_null() || s.is_null() {
1365        return any_null();
1366    }
1367    let s: &str = unsafe { &*s }.as_str();
1368    alloc_dynamic(unsafe { (&*addr).clone() }.split(s))
1369}
1370
1371extern "C" fn any_to_f64(addr: *const Dynamic) -> f64 {
1372    if addr.is_null() {
1373        return 0.0;
1374    }
1375    unsafe {
1376        let value = &*addr;
1377        value.as_float().or_else(|| value.as_str().trim().parse::<f64>().ok()).unwrap_or(0.0)
1378    }
1379}
1380
1381extern "C" fn any_to_string(addr: *const Dynamic) -> *const Dynamic {
1382    if addr.is_null() {
1383        return alloc_dynamic(Dynamic::from(""));
1384    }
1385    alloc_dynamic(Dynamic::from(unsafe { &*addr }.to_string()))
1386}
1387
1388extern "C" fn any_binary(left: *const Dynamic, op: i32, right: *const Dynamic) -> *const Dynamic {
1389    if left.is_null() {
1390        if right.is_null() {
1391            return any_null();
1392        }
1393        return alloc_dynamic(unsafe { (&*right).clone() });
1394    }
1395    if right.is_null() {
1396        return alloc_dynamic(unsafe { (&*left).clone() });
1397    }
1398    let op = BinaryOp::try_from(op).unwrap_or(BinaryOp::Unknow);
1399    if op == BinaryOp::Add {
1400        let (left_value, right_value) = unsafe { (&*left, &*right) };
1401        if left_value.is_str() || right_value.is_str() {
1402            return alloc_dynamic(left_value.clone() + right_value.clone());
1403        }
1404    }
1405    unsafe {
1406        let expr = Expr::new(
1407            ExprKind::Binary { left: Box::new(Expr::new(ExprKind::Value((&*left).clone()), Span::default())), op, right: Box::new(Expr::new(ExprKind::Value((&*right).clone()), Span::default())) },
1408            Span::default(),
1409        );
1410        alloc_dynamic(expr.compact().unwrap_or(Dynamic::Null))
1411    }
1412}
1413
1414extern "C" fn any_logic(left: *const Dynamic, op: i32, right: *const Dynamic) -> bool {
1415    let op = BinaryOp::try_from(op).unwrap_or(BinaryOp::Unknow);
1416    unsafe {
1417        let expr = Expr::new(
1418            ExprKind::Binary { left: Box::new(Expr::new(ExprKind::Value((&*left).clone()), Span::default())), op, right: Box::new(Expr::new(ExprKind::Value((&*right).clone()), Span::default())) },
1419            Span::default(),
1420        );
1421        expr.compact().and_then(|r| r.as_bool()).unwrap_or(false)
1422    }
1423}
1424
1425pub const STD: [(&str, &[Type], Type, *const u8); 6] = [
1426    ("print", &[Type::Any], Type::Void, print as *const u8),
1427    ("sqrt", &[Type::F64], Type::F64, sqrt as *const u8),
1428    ("sleep", &[Type::I64], Type::Void, sleep as *const u8),
1429    ("log", &[Type::Any], Type::Void, log_any as *const u8),
1430    ("uuid", &[], Type::Any, uuid as *const u8),
1431    ("rand", &[Type::Any, Type::Any], Type::Any, random as *const u8),
1432];
1433
1434pub const ANY: [(&str, &[Type], Type, *const u8); 79] = [
1435    ("Any::null", &[], Type::Any, any_null as *const u8),
1436    ("Any::is_map", &[Type::Any], Type::Bool, any_is_map as *const u8),
1437    ("Any::is_list", &[Type::Any], Type::Bool, any_is_list as *const u8),
1438    ("Any::is_string", &[Type::Any], Type::Bool, any_is_string as *const u8),
1439    ("Any::is_null", &[Type::Any], Type::Bool, any_is_null as *const u8),
1440    ("Any::clone", &[Type::Any], Type::Any, any_clone as *const u8),
1441    ("Any::len", &[Type::Any], Type::I32, any_len as *const u8),
1442    ("Any::keys", &[Type::Any], Type::Any, any_keys as *const u8),
1443    ("Any::split", &[Type::Any, Type::Any], Type::Any, any_split as *const u8),
1444    ("Any::push", &[Type::Any, Type::Any], Type::Void, any_push as *const u8),
1445    ("Any::pop", &[Type::Any], Type::Any, any_pop as *const u8),
1446    ("Any::get_idx", &[Type::Any, Type::I64], Type::Any, get_idx as *const u8),
1447    ("Any::push_bool", &[Type::Any, Type::Bool], Type::Void, list_bool_push as *const u8),
1448    ("Any::get_idx_bool", &[Type::Any, Type::I64], Type::Bool, list_bool_get_idx as *const u8),
1449    ("Any::get_idx_bool_i64", &[Type::Any, Type::I64], Type::I64, list_bool_get_idx_i64 as *const u8),
1450    ("Any::set_idx_bool", &[Type::Any, Type::I64, Type::Bool], Type::Void, list_bool_set_idx as *const u8),
1451    ("Any::push_u8", &[Type::Any, Type::U8], Type::Void, list_u8_push as *const u8),
1452    ("Any::get_idx_u8", &[Type::Any, Type::I64], Type::U8, list_u8_get_idx as *const u8),
1453    ("Any::get_idx_u8_i64", &[Type::Any, Type::I64], Type::I64, list_u8_get_idx_i64 as *const u8),
1454    ("Any::set_idx_u8", &[Type::Any, Type::I64, Type::U8], Type::Void, list_u8_set_idx as *const u8),
1455    ("Any::push_i8", &[Type::Any, Type::I8], Type::Void, list_i8_push as *const u8),
1456    ("Any::get_idx_i8", &[Type::Any, Type::I64], Type::I8, list_i8_get_idx as *const u8),
1457    ("Any::get_idx_i8_i64", &[Type::Any, Type::I64], Type::I64, list_i8_get_idx_i64 as *const u8),
1458    ("Any::set_idx_i8", &[Type::Any, Type::I64, Type::I8], Type::Void, list_i8_set_idx as *const u8),
1459    ("Any::push_u16", &[Type::Any, Type::U16], Type::Void, list_u16_push as *const u8),
1460    ("Any::get_idx_u16", &[Type::Any, Type::I64], Type::U16, list_u16_get_idx as *const u8),
1461    ("Any::get_idx_u16_i64", &[Type::Any, Type::I64], Type::I64, list_u16_get_idx_i64 as *const u8),
1462    ("Any::set_idx_u16", &[Type::Any, Type::I64, Type::U16], Type::Void, list_u16_set_idx as *const u8),
1463    ("Any::push_i16", &[Type::Any, Type::I16], Type::Void, list_i16_push as *const u8),
1464    ("Any::get_idx_i16", &[Type::Any, Type::I64], Type::I16, list_i16_get_idx as *const u8),
1465    ("Any::get_idx_i16_i64", &[Type::Any, Type::I64], Type::I64, list_i16_get_idx_i64 as *const u8),
1466    ("Any::set_idx_i16", &[Type::Any, Type::I64, Type::I16], Type::Void, list_i16_set_idx as *const u8),
1467    ("Any::push_u32", &[Type::Any, Type::U32], Type::Void, list_u32_push as *const u8),
1468    ("Any::get_idx_u32", &[Type::Any, Type::I64], Type::U32, list_u32_get_idx as *const u8),
1469    ("Any::set_idx_u32", &[Type::Any, Type::I64, Type::U32], Type::Void, list_u32_set_idx as *const u8),
1470    ("Any::push_i32", &[Type::Any, Type::I32], Type::Void, list_i32_push as *const u8),
1471    ("Any::get_idx_i32", &[Type::Any, Type::I64], Type::I32, list_i32_get_idx as *const u8),
1472    ("Any::set_idx_i32", &[Type::Any, Type::I64, Type::I32], Type::Void, list_i32_set_idx as *const u8),
1473    ("Any::push_f32", &[Type::Any, Type::F32], Type::Void, list_f32_push as *const u8),
1474    ("Any::get_idx_f32", &[Type::Any, Type::I64], Type::F32, list_f32_get_idx as *const u8),
1475    ("Any::set_idx_f32", &[Type::Any, Type::I64, Type::F32], Type::Void, list_f32_set_idx as *const u8),
1476    ("Any::push_u64", &[Type::Any, Type::U64], Type::Void, list_u64_push as *const u8),
1477    ("Any::data_ptr_u64", &[Type::Any], Type::Any, list_u64_data_ptr as *const u8),
1478    ("Any::get_idx_u64", &[Type::Any, Type::I64], Type::U64, list_u64_get_idx as *const u8),
1479    ("Any::set_idx_u64", &[Type::Any, Type::I64, Type::U64], Type::Void, list_u64_set_idx as *const u8),
1480    ("Any::push_i64", &[Type::Any, Type::I64], Type::Void, list_i64_push as *const u8),
1481    ("Any::data_ptr_i64", &[Type::Any], Type::Any, list_i64_data_ptr as *const u8),
1482    ("Any::get_idx_i64", &[Type::Any, Type::I64], Type::I64, list_i64_get_idx as *const u8),
1483    ("Any::set_idx_i64", &[Type::Any, Type::I64, Type::I64], Type::Void, list_i64_set_idx as *const u8),
1484    ("Any::push_f64", &[Type::Any, Type::F64], Type::Void, list_f64_push as *const u8),
1485    ("Any::data_ptr_f64", &[Type::Any], Type::Any, list_f64_data_ptr as *const u8),
1486    ("Any::get_idx_f64", &[Type::Any, Type::I64], Type::F64, list_f64_get_idx as *const u8),
1487    ("Any::set_idx_f64", &[Type::Any, Type::I64, Type::F64], Type::Void, list_f64_set_idx as *const u8),
1488    ("Any::push_str", &[Type::Any, Type::Str], Type::Void, list_str_push as *const u8),
1489    ("Any::get_idx_str", &[Type::Any, Type::I64], Type::Str, list_str_get_idx as *const u8),
1490    ("Any::set_idx_str", &[Type::Any, Type::I64, Type::Str], Type::Void, list_str_set_idx as *const u8),
1491    ("Any::slice", &[Type::Any, Type::I64, Type::Any, Type::Bool], Type::Any, slice as *const u8),
1492    ("Any::contains", &[Type::Any, Type::Any], Type::Bool, contains as *const u8),
1493    ("Any::starts_with", &[Type::Any, Type::Any], Type::Bool, starts_with as *const u8),
1494    ("Any::ends_with", &[Type::Any, Type::Any], Type::Bool, ends_with as *const u8),
1495    ("Any::get", &[Type::Any, Type::Any], Type::Any, get_key as *const u8),
1496    ("Any::get_key", &[Type::Any, Type::Any], Type::Any, get_key as *const u8),
1497    ("Any::del_key", &[Type::Any, Type::Any], Type::Any, del_key as *const u8),
1498    ("Any::set_idx", &[Type::Any, Type::I64, Type::Any], Type::Void, set_idx as *const u8),
1499    ("Any::set_key", &[Type::Any, Type::Any, Type::Any], Type::Void, set_key as *const u8),
1500    ("Any::set", &[Type::Any, Type::Any, Type::Any], Type::Void, set_key as *const u8),
1501    ("Any::from_i64", &[Type::I64], Type::Any, any_from_i64 as *const u8),
1502    ("Any::from_u64", &[Type::U64], Type::Any, any_from_u64 as *const u8),
1503    ("Any::from_bool", &[Type::Bool], Type::Any, any_from_bool as *const u8),
1504    ("Any::to_i64", &[Type::Any], Type::I64, any_to_i64 as *const u8),
1505    ("Any::to_bool", &[Type::Any], Type::Bool, any_to_bool as *const u8),
1506    ("Any::from_f64", &[Type::F64], Type::Any, any_from_f64 as *const u8),
1507    ("Any::to_f64", &[Type::Any], Type::F64, any_to_f64 as *const u8),
1508    ("Any::to_string", &[Type::Any], Type::Str, any_to_string as *const u8),
1509    ("Any::binary", &[Type::Any, Type::I32, Type::Any], Type::Any, any_binary as *const u8),
1510    ("Any::logic", &[Type::Any, Type::I32, Type::Any], Type::Bool, any_logic as *const u8),
1511    ("Any::iter", &[Type::Any], Type::Any, any_iter as *const u8),
1512    ("Any::next", &[Type::Any], Type::Any, any_next as *const u8),
1513    ("Any::next_pair", &[Type::Any], Type::Any, any_next_pair as *const u8),
1514];
1515
1516use std::rc::Rc;
1517impl JITRunTime {
1518    pub fn add_native_ptr(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type, fn_ptr: *const u8) -> Result<u32> {
1519        self.native_symbols.write().insert(full_name.to_string(), fn_ptr as usize);
1520        self.add_native(full_name, name, arg_tys, ret_ty)
1521    }
1522
1523    pub(crate) fn add_context_native_ptr(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type, fn_ptr: *const u8) -> Result<u32> {
1524        self.native_symbols.write().insert(full_name.to_string(), fn_ptr as usize);
1525        self.add_context_native(full_name, name, arg_tys, ret_ty)
1526    }
1527
1528    pub fn add_native(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type) -> Result<u32> {
1529        let fn_ty = Type::Fn { tys: arg_tys.to_vec(), ret: Rc::new(ret_ty.clone()) };
1530        let id = self.compiler.add_symbol(name, compiler::Symbol::Native(fn_ty.clone()));
1531        let sig = self.get_sig(arg_tys, ret_ty)?;
1532        let fn_id = self.module.declare_function(full_name, Linkage::Import, &sig)?;
1533        self.fns.insert(id, FnVariant::Native { ty: fn_ty, fn_id, context: None });
1534        Ok(id)
1535    }
1536
1537    pub(crate) fn add_context_native(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type) -> Result<u32> {
1538        let fn_ty = Type::Fn { tys: arg_tys.to_vec(), ret: Rc::new(ret_ty.clone()) };
1539        let id = self.compiler.add_symbol(name, compiler::Symbol::Native(fn_ty.clone()));
1540        let mut sig = self.module.make_signature();
1541        sig.params.push(AbiParam::new(crate::ptr_type()));
1542        for arg in arg_tys.iter() {
1543            sig.params.push(AbiParam::new(crate::get_type(arg)?));
1544        }
1545        if !ret_ty.is_void() {
1546            sig.returns.push(AbiParam::new(crate::get_type(&ret_ty)?));
1547        }
1548        let fn_id = self.module.declare_function(full_name, Linkage::Import, &sig)?;
1549        self.fns.insert(id, FnVariant::Native { ty: fn_ty, fn_id, context: Some(self.owner_context_ptr()) });
1550        Ok(id)
1551    }
1552}