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