Skip to main content

vm/
native.rs

1use super::FnVariant;
2use crate::JITRunTime;
3use crate::memory::{alloc_dynamic, alloc_struct_bytes, take_dynamic_return};
4use anyhow::Result;
5use cranelift::prelude::AbiParam;
6use cranelift_module::{Linkage, Module};
7use dynamic::{Dynamic, Type};
8use parser::{BinaryOp, Expr, ExprKind, Span};
9use rand::RngExt;
10use std::borrow::Cow;
11use std::collections::BTreeMap;
12use std::fmt::Write as _;
13use std::sync::{RwLock, Weak};
14
15#[derive(Clone, Debug)]
16pub struct ZustCallback {
17    pub fn_ptr: usize,
18    pub ret_ty: Type,
19    pub explicit_arg_len: usize,
20    pub captures: Vec<Dynamic>,
21}
22
23impl ZustCallback {
24    pub fn new(fn_ptr: usize, ret_ty: Type, captures: Vec<Dynamic>) -> Self {
25        Self { fn_ptr, ret_ty, explicit_arg_len: usize::MAX, captures }
26    }
27
28    pub fn new_with_arg_len(fn_ptr: usize, ret_ty: Type, explicit_arg_len: usize, captures: Vec<Dynamic>) -> Self {
29        Self { fn_ptr, ret_ty, explicit_arg_len, captures }
30    }
31
32    pub fn call0(&self) -> Result<Dynamic> {
33        self.call(Vec::new())
34    }
35
36    pub fn call1(&self, arg: Dynamic) -> Result<Dynamic> {
37        self.call(vec![arg])
38    }
39
40    pub fn call(&self, mut args: Vec<Dynamic>) -> Result<Dynamic> {
41        if self.explicit_arg_len != usize::MAX {
42            args.truncate(self.explicit_arg_len);
43            while args.len() < self.explicit_arg_len {
44                args.push(Dynamic::Null);
45            }
46        }
47        let args: Vec<Box<Dynamic>> = args.into_iter().map(Box::new).collect();
48        let mut ptrs: Vec<*const Dynamic> = args.iter().map(|arg| arg.as_ref() as *const Dynamic).collect();
49        ptrs.extend(self.captures.iter().map(|value| value as *const Dynamic));
50        unsafe { call_callback(self.fn_ptr as *const u8, &self.ret_ty, &ptrs) }
51    }
52}
53
54extern "C" fn any_clone(addr: *const Dynamic) -> *const Dynamic {
55    //在堆上分配内存 复制 addr 到内存中
56    unsafe {
57        let cloned_value = (*addr).deep_clone();
58        alloc_dynamic(cloned_value)
59    }
60}
61
62extern "C" fn any_null() -> *const Dynamic {
63    //在堆上分配内存 复制 addr 到内存中
64    alloc_dynamic(Dynamic::Null)
65}
66
67extern "C" fn print(addr: *const Dynamic) {
68    if !addr.is_null() {
69        unsafe {
70            println!("{}", (*addr).to_string());
71        }
72    }
73}
74
75extern "C" fn sqrt(value: f64) -> f64 {
76    value.sqrt()
77}
78
79extern "C" fn log_any(addr: *const Dynamic) {
80    if addr.is_null() {
81        log::debug!("{:?}", Dynamic::Null);
82    } else {
83        log::debug!("{:?}", unsafe { &*addr });
84    }
85}
86
87extern "C" fn any_is_map(addr: *const Dynamic) -> bool {
88    !addr.is_null() && unsafe { (*addr).is_map() }
89}
90
91extern "C" fn any_is_list(addr: *const Dynamic) -> bool {
92    !addr.is_null() && unsafe { (*addr).is_list() }
93}
94
95extern "C" fn any_is_string(addr: *const Dynamic) -> bool {
96    !addr.is_null() && unsafe { (*addr).is_str() }
97}
98
99extern "C" fn any_is_null(addr: *const Dynamic) -> bool {
100    addr.is_null() || unsafe { (*addr).is_null() }
101}
102
103extern "C" fn random(start: *const Dynamic, stop: *const Dynamic) -> *const Dynamic {
104    if !start.is_null() && !stop.is_null() {
105        let mut rng = rand::rng();
106        unsafe {
107            if (&*start).is_int() {
108                let start = (*start).as_int().unwrap_or(0);
109                let stop = (*stop).as_int().unwrap_or(100);
110                return alloc_dynamic(Dynamic::I64(rng.random_range(start..stop)));
111            } else if (&*start).is_f32() || (&*start).is_f64() {
112                let start = (*start).as_float().unwrap_or(0.0);
113                let stop = (*stop).as_float().unwrap_or(1.0);
114                return alloc_dynamic(Dynamic::F64(rng.random_range(start..stop)));
115            }
116        }
117    }
118    alloc_dynamic(Dynamic::Null)
119}
120
121extern "C" fn uuid() -> *const Dynamic {
122    alloc_dynamic(uuid::Uuid::new_v4().to_string().into())
123}
124
125pub(crate) extern "C" fn struct_alloc(size: i64) -> *mut u8 {
126    let size = size.max(0) as usize;
127    let ptr = alloc_struct_bytes(size);
128    unsafe {
129        std::ptr::write_bytes(ptr, 0, size);
130    }
131    ptr
132}
133
134pub(crate) extern "C" fn repeat_fill(dst: *mut u8, pattern: u64, width: i64, len: i64) {
135    if dst.is_null() || width <= 0 || len <= 0 {
136        return;
137    }
138    let width = width as usize;
139    let len = len as usize;
140    let bytes = pattern.to_le_bytes();
141    unsafe {
142        if width == 1 {
143            std::ptr::write_bytes(dst, bytes[0], len);
144            return;
145        }
146        if !matches!(width, 2 | 4 | 8) {
147            return;
148        }
149        for idx in 0..len {
150            std::ptr::copy_nonoverlapping(bytes.as_ptr(), dst.add(idx * width), width);
151        }
152    }
153}
154
155pub(crate) extern "C" fn strcat(left: *const Dynamic, right: *const Dynamic) -> *const Dynamic {
156    let left = if left.is_null() { "" } else { unsafe { (&*left).as_str() } };
157    let right = if right.is_null() { "" } else { unsafe { (&*right).as_str() } };
158    let mut out = String::with_capacity(left.len() + right.len());
159    out.push_str(left);
160    out.push_str(right);
161    alloc_dynamic(Dynamic::StringBuf(out))
162}
163
164pub(crate) extern "C" fn strcat_i64(left: *const Dynamic, right: i64) -> *const Dynamic {
165    let left = if left.is_null() { "" } else { unsafe { (&*left).as_str() } };
166    let mut out = String::with_capacity(left.len() + 20);
167    out.push_str(left);
168    let _ = write!(&mut out, "{right}");
169    alloc_dynamic(Dynamic::StringBuf(out))
170}
171
172pub(crate) extern "C" fn strcat_assign(left: *mut Dynamic, right: *const Dynamic) -> *const Dynamic {
173    if left.is_null() {
174        return strcat(left, right);
175    }
176    let suffix = if right.is_null() {
177        Cow::Borrowed("")
178    } else if std::ptr::eq(left as *const Dynamic, right) {
179        Cow::Owned(unsafe { (&*right).to_string() })
180    } else {
181        let right = unsafe { &*right };
182        if right.is_str() { Cow::Borrowed(right.as_str()) } else { Cow::Owned(right.to_string()) }
183    };
184    unsafe {
185        match &mut *left {
186            Dynamic::StringBuf(text) => text.push_str(suffix.as_ref()),
187            Dynamic::String(text) => {
188                let mut out = String::with_capacity(text.len() + suffix.len());
189                out.push_str(text.as_str());
190                out.push_str(suffix.as_ref());
191                *left = Dynamic::StringBuf(out);
192            }
193            value => {
194                let prefix = value.to_string();
195                let mut out = String::with_capacity(prefix.len() + suffix.len());
196                out.push_str(&prefix);
197                out.push_str(suffix.as_ref());
198                *value = Dynamic::StringBuf(out);
199            }
200        }
201    }
202    left
203}
204
205pub(crate) extern "C" fn struct_from_ptr(addr: i64, ty: i64) -> *const Dynamic {
206    let ty = unsafe { (&*(ty as *const Type)).clone() };
207    alloc_dynamic(Dynamic::Struct { addr: addr as usize, ty })
208}
209
210pub(crate) extern "C" fn array_from_ptr(addr: i64, ty: i64) -> *const Dynamic {
211    if addr == 0 || ty == 0 {
212        return alloc_dynamic(Dynamic::Null);
213    }
214    let ty = unsafe { &*(ty as *const Type) };
215    alloc_dynamic(dynamic_from_ptr(addr as *const u8, ty))
216}
217
218pub(crate) extern "C" fn array_to_ptr(dst: *mut u8, value: *const Dynamic, ty: i64) {
219    if dst.is_null() || value.is_null() || ty == 0 {
220        return;
221    }
222    let ty = unsafe { &*(ty as *const Type) };
223    write_dynamic_to_ptr(dst, unsafe { &*value }, ty);
224}
225
226fn dynamic_from_ptr(addr: *const u8, ty: &Type) -> Dynamic {
227    if addr.is_null() {
228        return Dynamic::Null;
229    }
230    match ty {
231        Type::Bool => Dynamic::Bool(unsafe { std::ptr::read_unaligned(addr) } != 0),
232        Type::I8 => Dynamic::I8(unsafe { std::ptr::read_unaligned(addr as *const i8) }),
233        Type::U8 => Dynamic::U8(unsafe { std::ptr::read_unaligned(addr) }),
234        Type::I16 => Dynamic::I16(unsafe { std::ptr::read_unaligned(addr as *const i16) }),
235        Type::U16 => Dynamic::U16(unsafe { std::ptr::read_unaligned(addr as *const u16) }),
236        Type::I32 => Dynamic::I32(unsafe { std::ptr::read_unaligned(addr as *const i32) }),
237        Type::U32 => Dynamic::U32(unsafe { std::ptr::read_unaligned(addr as *const u32) }),
238        Type::I64 => Dynamic::I64(unsafe { std::ptr::read_unaligned(addr as *const i64) }),
239        Type::U64 => Dynamic::U64(unsafe { std::ptr::read_unaligned(addr as *const u64) }),
240        Type::F32 => Dynamic::F32(unsafe { std::ptr::read_unaligned(addr as *const f32) }),
241        Type::F64 => Dynamic::F64(unsafe { std::ptr::read_unaligned(addr as *const f64) }),
242        Type::Array(elem_ty, len) => {
243            let width = elem_ty.storage_width() as usize;
244            let values = (0..*len as usize).map(|idx| unsafe { dynamic_from_ptr(addr.add(idx * width), elem_ty) }).collect();
245            Dynamic::list(values)
246        }
247        Type::Struct { fields, .. } => {
248            let mut map = BTreeMap::new();
249            let (_, offsets) = Type::struct_layout(fields);
250            for ((name, field_ty), offset) in fields.iter().zip(offsets) {
251                let value = unsafe { dynamic_from_ptr(addr.add(offset as usize), field_ty) };
252                map.insert(name.clone(), value);
253            }
254            Dynamic::map(map)
255        }
256        _ => {
257            let ptr = unsafe { std::ptr::read_unaligned(addr as *const *const Dynamic) };
258            if ptr.is_null() { Dynamic::Null } else { unsafe { (&*ptr).deep_clone() } }
259        }
260    }
261}
262
263fn write_dynamic_to_ptr(dst: *mut u8, value: &Dynamic, ty: &Type) {
264    if dst.is_null() {
265        return;
266    }
267    match ty {
268        Type::Bool => unsafe { std::ptr::write_unaligned(dst, if value.is_true() { 1 } else { 0 }) },
269        Type::I8 => unsafe { std::ptr::write_unaligned(dst as *mut i8, value.clone().try_into().unwrap_or_default()) },
270        Type::U8 => unsafe { std::ptr::write_unaligned(dst, value.clone().try_into().unwrap_or_default()) },
271        Type::I16 => unsafe { std::ptr::write_unaligned(dst as *mut i16, value.clone().try_into().unwrap_or_default()) },
272        Type::U16 => unsafe { std::ptr::write_unaligned(dst as *mut u16, value.clone().try_into().unwrap_or_default()) },
273        Type::I32 => unsafe { std::ptr::write_unaligned(dst as *mut i32, value.clone().try_into().unwrap_or_default()) },
274        Type::U32 => unsafe { std::ptr::write_unaligned(dst as *mut u32, value.clone().try_into().unwrap_or_default()) },
275        Type::I64 => unsafe { std::ptr::write_unaligned(dst as *mut i64, value.clone().try_into().unwrap_or_default()) },
276        Type::U64 => unsafe { std::ptr::write_unaligned(dst as *mut u64, value.clone().try_into().unwrap_or_default()) },
277        Type::F32 => unsafe { std::ptr::write_unaligned(dst as *mut f32, f32::try_from(value.clone()).unwrap_or_default()) },
278        Type::F64 => unsafe { std::ptr::write_unaligned(dst as *mut f64, value.clone().try_into().unwrap_or_default()) },
279        Type::Array(elem_ty, len) => {
280            let width = elem_ty.storage_width() as usize;
281            for idx in 0..*len as usize {
282                let item = value.get_idx(idx).unwrap_or(Dynamic::Null);
283                unsafe { write_dynamic_to_ptr(dst.add(idx * width), &item, elem_ty) };
284            }
285        }
286        Type::Struct { fields, .. } => {
287            let (_, offsets) = Type::struct_layout(fields);
288            for ((name, field_ty), offset) in fields.iter().zip(offsets) {
289                let item = value.get_dynamic(name.as_str()).unwrap_or(Dynamic::Null);
290                unsafe { write_dynamic_to_ptr(dst.add(offset as usize), &item, field_ty) };
291            }
292        }
293        _ => {
294            let ptr = alloc_dynamic(value.deep_clone());
295            unsafe { std::ptr::write_unaligned(dst as *mut usize, ptr as usize) };
296        }
297    }
298}
299
300pub(crate) extern "C" fn import_with_vm(context: *const Weak<RwLock<JITRunTime>>, addr: *const Dynamic, path: *const Dynamic) -> bool {
301    if addr.is_null() || path.is_null() {
302        return false;
303    }
304    super::with_vm_context(context, |jit| {
305        let name = unsafe { &*addr }.as_str();
306        let path = unsafe { &*path }.as_str();
307        jit.import(name, path)
308    }).map_err(|e| log::error!("import failed: {e:#}")).is_ok()
309}
310
311pub(crate) extern "C" fn spawn_with_vm(context: *const Weak<RwLock<JITRunTime>>, fn_name: *const Dynamic, args: *const Dynamic) -> bool {
312    if context.is_null() || fn_name.is_null() {
313        return false;
314    }
315    let fn_name = unsafe { (&*fn_name).as_str().to_string() };
316    if fn_name.is_empty() {
317        return false;
318    }
319    let args = if args.is_null() { Dynamic::Null } else { unsafe { (&*args).deep_clone() } };
320    let context = unsafe { (&*context).clone() };
321    std::thread::Builder::new()
322        .name(format!("zust:{fn_name}"))
323        .spawn(move || {
324            if let Err(err) = spawn_run(context, fn_name.as_str(), args) {
325                log::error!("spawn {fn_name} failed: {err:?}");
326            }
327        })
328        .is_ok()
329}
330
331fn spawn_args(args: Dynamic) -> Vec<Dynamic> {
332    match args {
333        Dynamic::Null => Vec::new(),
334        Dynamic::List(values) => values.read().unwrap().iter().map(Dynamic::deep_clone).collect(),
335        value => vec![value],
336    }
337}
338
339fn spawn_run(context: Weak<RwLock<JITRunTime>>, fn_name: &str, args: Dynamic) -> Result<()> {
340    let args = spawn_args(args);
341    if args.len() > 16 {
342        anyhow::bail!("spawn supports at most 16 args, got {}", args.len());
343    }
344    let arg_tys = vec![Type::Any; args.len()];
345    let (ptr, ret_ty) = super::with_vm_context(&context as *const Weak<RwLock<JITRunTime>>, |vm| vm.jit.write().unwrap().get_fn_ptr(fn_name, &arg_tys))?;
346    let args: Vec<Box<Dynamic>> = args.into_iter().map(Box::new).collect();
347    let ptrs: Vec<*const Dynamic> = args.iter().map(|arg| arg.as_ref() as *const Dynamic).collect();
348    unsafe {
349        call_spawned(ptr, &ret_ty, &ptrs)?;
350    }
351    Ok(())
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        match unsafe { &*captures } {
381            Dynamic::List(values) => values.read().unwrap().iter().map(Dynamic::deep_clone).collect(),
382            value => vec![value.deep_clone()],
383        }
384    };
385    alloc_dynamic(Dynamic::custom(ZustCallback::new_with_arg_len(fn_ptr as usize, ret_ty, explicit_arg_len, captures)))
386}
387
388fn spawn_run_ptr(fn_ptr: usize, ret_ty: Type, args: Dynamic) -> Result<()> {
389    let args = spawn_args(args);
390    if args.len() > 16 {
391        anyhow::bail!("spawn supports at most 16 args, got {}", args.len());
392    }
393    let args: Vec<Box<Dynamic>> = args.into_iter().map(Box::new).collect();
394    let ptrs: Vec<*const Dynamic> = args.iter().map(|arg| arg.as_ref() as *const Dynamic).collect();
395    unsafe {
396        call_spawned(fn_ptr as *const u8, &ret_ty, &ptrs)?;
397    }
398    Ok(())
399}
400
401unsafe fn call_callback(ptr: *const u8, ret_ty: &Type, args: &[*const Dynamic]) -> Result<Dynamic> {
402    macro_rules! callback_arg_ty {
403        ($arg:ident) => {
404            *const Dynamic
405        };
406    }
407
408    macro_rules! callback_args {
409        ($body:ident $(, $extra:tt)*) => {
410            match args {
411                [] => $body!($($extra),*;),
412                [a] => $body!($($extra),*; a),
413                [a, b] => $body!($($extra),*; a, b),
414                [a, b, c] => $body!($($extra),*; a, b, c),
415                [a, b, c, d] => $body!($($extra),*; a, b, c, d),
416                [a, b, c, d, e] => $body!($($extra),*; a, b, c, d, e),
417                [a, b, c, d, e, f] => $body!($($extra),*; a, b, c, d, e, f),
418                [a, b, c, d, e, f, g] => $body!($($extra),*; a, b, c, d, e, f, g),
419                [a, b, c, d, e, f, g, h] => $body!($($extra),*; a, b, c, d, e, f, g, h),
420                [a, b, c, d, e, f, g, h, i] => $body!($($extra),*; a, b, c, d, e, f, g, h, i),
421                [a, b, c, d, e, f, g, h, i, j] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j),
422                [a, b, c, d, e, f, g, h, i, j, k] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k),
423                [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),
424                [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),
425                [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),
426                [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),
427                [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),
428                [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),
429                [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),
430                [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),
431                [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),
432                [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),
433                [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),
434                [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),
435                [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),
436                _ => anyhow::bail!("callback supports at most 24 args including captures, got {}", args.len()),
437            }
438        };
439    }
440
441    macro_rules! call_void_body {
442        (; $($arg:ident),*) => {{
443            let fn_ptr: extern "C" fn($(callback_arg_ty!($arg)),*) = unsafe { std::mem::transmute(ptr) };
444            fn_ptr($(*$arg),*)
445        }};
446    }
447
448    macro_rules! call_void {
449        () => {
450            callback_args!(call_void_body)
451        };
452    }
453
454    macro_rules! call_ret_body {
455        ($ret:ty, $dynamic:expr; $($arg:ident),*) => {{
456            let fn_ptr: extern "C" fn($(callback_arg_ty!($arg)),*) -> $ret = unsafe { std::mem::transmute(ptr) };
457            $dynamic(fn_ptr($(*$arg),*))
458        }};
459    }
460
461    macro_rules! call_ret {
462        ($ret:ty, $dynamic:expr) => {{ callback_args!(call_ret_body, $ret, $dynamic) }};
463    }
464
465    if ret_ty.is_void() {
466        call_void!();
467        Ok(Dynamic::Null)
468    } else if ret_ty.is_bool() {
469        call_ret!(bool, |value| Ok(Dynamic::Bool(value)))
470    } else if ret_ty.is_float() {
471        if ret_ty.is_f64() { call_ret!(f64, |value| Ok(Dynamic::F64(value))) } else { call_ret!(f32, |value| Ok(Dynamic::F32(value))) }
472    } else if ret_ty.is_int() || ret_ty.is_uint() {
473        match ret_ty {
474            Type::I8 => call_ret!(i8, |value| Ok(Dynamic::I8(value))),
475            Type::U8 => call_ret!(u8, |value| Ok(Dynamic::U8(value))),
476            Type::I16 => call_ret!(i16, |value| Ok(Dynamic::I16(value))),
477            Type::U16 => call_ret!(u16, |value| Ok(Dynamic::U16(value))),
478            Type::I32 => call_ret!(i32, |value| Ok(Dynamic::I32(value))),
479            Type::U32 => call_ret!(u32, |value| Ok(Dynamic::U32(value))),
480            Type::I64 => call_ret!(i64, |value| Ok(Dynamic::I64(value))),
481            Type::U64 => call_ret!(u64, |value| Ok(Dynamic::U64(value))),
482            _ => unreachable!(),
483        }
484    } else if ret_ty.is_struct() || ret_ty.is_array() || ret_ty.is_vec() {
485        log::warn!("callback returns {ret_ty:?} — not supported, discarding");
486        call_ret!(*const u8, |_| Ok(Dynamic::Null))
487    } else {
488        call_ret!(*const Dynamic, |ptr| unsafe { Ok((*take_dynamic_return(ptr)).deep_clone()) })
489    }
490}
491
492unsafe fn call_spawned(ptr: *const u8, ret_ty: &Type, args: &[*const Dynamic]) -> Result<()> {
493    macro_rules! call_void {
494        () => {
495            match args {
496                [] => unsafe { std::mem::transmute::<_, extern "C" fn()>(ptr)() },
497                [a] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic)>(ptr)(*a) },
498                [a, b] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic)>(ptr)(*a, *b) },
499                [a, b, c] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c) },
500                [a, b, c, d] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c, *d) },
501                [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) },
502                [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) },
503                [a, b, c, d, e, f, g] => unsafe {
504                    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)
505                },
506                [a, b, c, d, e, f, g, h] => unsafe {
507                    std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(
508                        *a, *b, *c, *d, *e, *f, *g, *h,
509                    )
510                },
511                [a, b, c, d, e, f, g, h, i] => unsafe {
512                    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)(
513                        *a, *b, *c, *d, *e, *f, *g, *h, *i,
514                    )
515                },
516                [a, b, c, d, e, f, g, h, i, j] => unsafe {
517                    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)>(ptr)(
518                        *a, *b, *c, *d, *e, *f, *g, *h, *i, *j,
519                    )
520                },
521                [a, b, c, d, e, f, g, h, i, j, k] => unsafe {
522                    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, *const Dynamic)>(ptr)(
523                        *a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k,
524                    )
525                },
526                [a, b, c, d, e, f, g, h, i, j, k, l] => unsafe {
527                    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, *const Dynamic, *const Dynamic)>(ptr)(
528                        *a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l,
529                    )
530                },
531                [a, b, c, d, e, f, g, h, i, j, k, l, m] => unsafe {
532                    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, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(
533                        *a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m,
534                    )
535                },
536                [a, b, c, d, e, f, g, h, i, j, k, l, m, n] => unsafe {
537                    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, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(
538                        *a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n,
539                    )
540                },
541                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o] => unsafe {
542                    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, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(
543                        *a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n, *o,
544                    )
545                },
546                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] => unsafe {
547                    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, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(
548                        *a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n, *o, *p,
549                    )
550                },
551                _ => unreachable!(),
552            }
553        };
554    }
555
556    if ret_ty.is_void() {
557        call_void!();
558        return Ok(());
559    }
560
561    macro_rules! call_ret {
562        ($ret:ty, $drop_result:expr) => {
563            match args {
564                [] => {
565                    let fn_ptr: extern "C" fn() -> $ret = unsafe { std::mem::transmute(ptr) };
566                    $drop_result(fn_ptr());
567                }
568                [a] => {
569                    let fn_ptr: extern "C" fn(*const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
570                    $drop_result(fn_ptr(*a));
571                }
572                [a, b] => {
573                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
574                    $drop_result(fn_ptr(*a, *b));
575                }
576                [a, b, c] => {
577                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
578                    $drop_result(fn_ptr(*a, *b, *c));
579                }
580                [a, b, c, d] => {
581                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
582                    $drop_result(fn_ptr(*a, *b, *c, *d));
583                }
584                [a, b, c, d, e] => {
585                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
586                    $drop_result(fn_ptr(*a, *b, *c, *d, *e));
587                }
588                [a, b, c, d, e, f] => {
589                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
590                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f));
591                }
592                [a, b, c, d, e, f, g] => {
593                    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) };
594                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g));
595                }
596                [a, b, c, d, e, f, g, h] => {
597                    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) };
598                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h));
599                }
600                [a, b, c, d, e, f, g, h, i] => {
601                    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 = unsafe { std::mem::transmute(ptr) };
602                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i));
603                }
604                [a, b, c, d, e, f, g, h, i, j] => {
605                    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 = unsafe { std::mem::transmute(ptr) };
606                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j));
607                }
608                [a, b, c, d, e, f, g, h, i, j, k] => {
609                    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, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
610                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k));
611                }
612                [a, b, c, d, e, f, g, h, i, j, k, l] => {
613                    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, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
614                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l));
615                }
616                [a, b, c, d, e, f, g, h, i, j, k, l, m] => {
617                    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, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
618                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m));
619                }
620                [a, b, c, d, e, f, g, h, i, j, k, l, m, n] => {
621                    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, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
622                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n));
623                }
624                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o] => {
625                    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, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
626                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n, *o));
627                }
628                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] => {
629                    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, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
630                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n, *o, *p));
631                }
632                _ => unreachable!(),
633            }
634        };
635    }
636
637    if ret_ty.is_bool() {
638        call_ret!(bool, |_| {});
639    } else if ret_ty.is_float() {
640        if ret_ty.is_f64() {
641            call_ret!(f64, |_| {});
642        } else {
643            call_ret!(f32, |_| {});
644        }
645    } else if ret_ty.is_int() || ret_ty.is_uint() {
646        match ret_ty {
647            Type::I8 => call_ret!(i8, |_| {}),
648            Type::U8 => call_ret!(u8, |_| {}),
649            Type::I16 => call_ret!(i16, |_| {}),
650            Type::U16 => call_ret!(u16, |_| {}),
651            Type::I32 => call_ret!(i32, |_| {}),
652            Type::U32 => call_ret!(u32, |_| {}),
653            Type::I64 => call_ret!(i64, |_| {}),
654            Type::U64 => call_ret!(u64, |_| {}),
655            _ => unreachable!(),
656        }
657    } else if ret_ty.is_struct() || ret_ty.is_array() || ret_ty.is_vec() {
658        log::warn!("spawned fn returns {ret_ty:?} — not supported, discarding");
659        call_ret!(*const u8, |_| {});
660    } else {
661        call_ret!(*const Dynamic, |ptr| drop(unsafe { take_dynamic_return(ptr) }));
662    }
663    Ok(())
664}
665
666extern "C" fn any_len(addr: *const Dynamic) -> i64 {
667    if addr.is_null() { 0 } else { unsafe { (&*addr).len() as i64 } }
668}
669
670extern "C" fn any_keys(addr: *const Dynamic) -> *const Dynamic {
671    if addr.is_null() {
672        return alloc_dynamic(Dynamic::list(Vec::new()));
673    }
674    let keys = match unsafe { &*addr } {
675        Dynamic::Map(map) => map.read().unwrap().keys().map(|key| Dynamic::from(key.as_str())).collect(),
676        _ => Vec::new(),
677    };
678    alloc_dynamic(Dynamic::list(keys))
679}
680
681extern "C" fn any_iter(addr: *const Dynamic) -> *const Dynamic {
682    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).clone().into_iter() }) }
683}
684
685extern "C" fn any_next(addr: *mut Dynamic) -> *const Dynamic {
686    alloc_dynamic(unsafe { (*addr).next().unwrap_or(Dynamic::Null) })
687}
688
689extern "C" fn any_next_pair(addr: *mut Dynamic) -> *const Dynamic {
690    alloc_dynamic(unsafe { (*addr).next_pair().unwrap_or(Dynamic::Null) })
691}
692
693extern "C" fn any_push(addr: *mut Dynamic, value: *mut Dynamic) {
694    if !addr.is_null() && !value.is_null() {
695        unsafe {
696            (&mut *addr).push_dynamic((&*value).clone());
697        }
698    }
699}
700
701extern "C" fn any_pop(addr: *mut Dynamic) -> *const Dynamic {
702    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).pop().unwrap_or(Dynamic::Null) }) }
703}
704
705extern "C" fn get_key(addr: *const Dynamic, key: *const Dynamic) -> *const Dynamic {
706    if addr.is_null() || key.is_null() {
707        any_null()
708    } else {
709        let key: &str = unsafe { &*key }.as_str();
710        alloc_dynamic(unsafe { (*addr).get_dynamic(key).unwrap_or(Dynamic::Null) })
711    }
712}
713
714extern "C" fn del_key(addr: *const Dynamic, key: *const Dynamic) -> *const Dynamic {
715    if addr.is_null() || key.is_null() {
716        any_null()
717    } else {
718        let key: &str = unsafe { &*key }.as_str();
719        alloc_dynamic(unsafe { (*addr).remove_dynamic(key).unwrap_or(Dynamic::Null) })
720    }
721}
722
723extern "C" fn contains(addr: *const Dynamic, key: *const Dynamic) -> bool {
724    if addr.is_null() || key.is_null() {
725        false
726    } else {
727        let key: &str = unsafe { &*key }.as_str();
728        unsafe { (*addr).contains(key) }
729    }
730}
731
732extern "C" fn starts_with(addr: *const Dynamic, prefix: *const Dynamic) -> bool {
733    if addr.is_null() || prefix.is_null() {
734        false
735    } else {
736        let prefix: &str = unsafe { &*prefix }.as_str();
737        unsafe { (*addr).starts_with(prefix) }
738    }
739}
740
741extern "C" fn get_idx(addr: *const Dynamic, idx: i64) -> *const Dynamic {
742    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).get_idx(idx as usize).unwrap_or(Dynamic::Null) }) }
743}
744
745macro_rules! myvec_list_native {
746    ($push:ident, $get_idx:ident, $set_idx:ident, $vec:ident, $dynamic:ident, $ty:ty, $fallback:expr) => {
747        extern "C" fn $push(addr: *mut Dynamic, value: $ty) {
748            if addr.is_null() {
749                return;
750            }
751            unsafe {
752                match &mut *addr {
753                    Dynamic::$vec(values) => values.push(value),
754                    list => {
755                        list.push_dynamic(Dynamic::$dynamic(value));
756                    }
757                }
758            }
759        }
760
761        extern "C" fn $get_idx(addr: *const Dynamic, idx: i64) -> $ty {
762            if addr.is_null() {
763                return <$ty>::default();
764            }
765            let Ok(idx) = usize::try_from(idx) else {
766                return <$ty>::default();
767            };
768            unsafe {
769                match &*addr {
770                    Dynamic::$vec(values) => values.get(idx).unwrap_or_default(),
771                    values => values.get_idx(idx).and_then($fallback).unwrap_or_default(),
772                }
773            }
774        }
775
776        extern "C" fn $set_idx(addr: *mut Dynamic, idx: i64, value: $ty) {
777            if addr.is_null() {
778                return;
779            }
780            let Ok(idx) = usize::try_from(idx) else {
781                return;
782            };
783            unsafe {
784                match &mut *addr {
785                    Dynamic::$vec(values) => values.set(idx, value),
786                    list => list.set_idx(idx, Dynamic::$dynamic(value)),
787                }
788            }
789        }
790    };
791}
792
793macro_rules! stdvec_list_native {
794    ($push:ident, $get_idx:ident, $set_idx:ident, $vec:ident, $dynamic:ident, $ty:ty, $fallback:expr) => {
795        extern "C" fn $push(addr: *mut Dynamic, value: $ty) {
796            if addr.is_null() {
797                return;
798            }
799            unsafe {
800                match &mut *addr {
801                    Dynamic::$vec(values) => values.push(value),
802                    list => {
803                        list.push_dynamic(Dynamic::$dynamic(value));
804                    }
805                }
806            }
807        }
808
809        extern "C" fn $get_idx(addr: *const Dynamic, idx: i64) -> $ty {
810            if addr.is_null() {
811                return <$ty>::default();
812            }
813            let Ok(idx) = usize::try_from(idx) else {
814                return <$ty>::default();
815            };
816            unsafe {
817                match &*addr {
818                    Dynamic::$vec(values) => values.get(idx).copied().unwrap_or_default(),
819                    values => values.get_idx(idx).and_then($fallback).unwrap_or_default(),
820                }
821            }
822        }
823
824        extern "C" fn $set_idx(addr: *mut Dynamic, idx: i64, value: $ty) {
825            if addr.is_null() {
826                return;
827            }
828            let Ok(idx) = usize::try_from(idx) else {
829                return;
830            };
831            unsafe {
832                match &mut *addr {
833                    Dynamic::$vec(values) => {
834                        if let Some(slot) = values.get_mut(idx) {
835                            *slot = value;
836                        }
837                    }
838                    list => list.set_idx(idx, Dynamic::$dynamic(value)),
839                }
840            }
841        }
842    };
843}
844
845myvec_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));
846myvec_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));
847myvec_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));
848myvec_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));
849myvec_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));
850myvec_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));
851stdvec_list_native!(list_u64_push, list_u64_get_idx, list_u64_set_idx, VecU64, U64, u64, |value: Dynamic| value.as_uint());
852stdvec_list_native!(list_i64_push, list_i64_get_idx, list_i64_set_idx, VecI64, I64, i64, |value: Dynamic| value.as_int());
853stdvec_list_native!(list_f64_push, list_f64_get_idx, list_f64_set_idx, VecF64, F64, f64, |value: Dynamic| value.as_float());
854
855extern "C" fn list_bool_push(addr: *mut Dynamic, value: bool) {
856    if !addr.is_null() {
857        unsafe {
858            (&mut *addr).push_dynamic(Dynamic::Bool(value));
859        }
860    }
861}
862
863extern "C" fn list_bool_get_idx(addr: *const Dynamic, idx: i64) -> bool {
864    if addr.is_null() {
865        return false;
866    }
867    let Ok(idx) = usize::try_from(idx) else {
868        return false;
869    };
870    unsafe { (&*addr).get_idx(idx).and_then(|value| value.as_bool()).unwrap_or(false) }
871}
872
873extern "C" fn list_bool_set_idx(addr: *mut Dynamic, idx: i64, value: bool) {
874    if addr.is_null() {
875        return;
876    }
877    let Ok(idx) = usize::try_from(idx) else {
878        return;
879    };
880    unsafe {
881        (&mut *addr).set_idx(idx, Dynamic::Bool(value));
882    }
883}
884
885extern "C" fn list_u8_push(addr: *mut Dynamic, value: u8) {
886    if !addr.is_null() {
887        unsafe {
888            (&mut *addr).push_dynamic(Dynamic::U8(value));
889        }
890    }
891}
892
893extern "C" fn list_u8_get_idx(addr: *const Dynamic, idx: i64) -> u8 {
894    if addr.is_null() {
895        return 0;
896    }
897    let Ok(idx) = usize::try_from(idx) else {
898        return 0;
899    };
900    unsafe { (&*addr).get_idx(idx).and_then(|value| value.as_uint()).map(|value| value as u8).unwrap_or(0) }
901}
902
903extern "C" fn list_u8_set_idx(addr: *mut Dynamic, idx: i64, value: u8) {
904    if addr.is_null() {
905        return;
906    }
907    let Ok(idx) = usize::try_from(idx) else {
908        return;
909    };
910    unsafe {
911        (&mut *addr).set_idx(idx, Dynamic::U8(value));
912    }
913}
914
915extern "C" fn list_str_push(addr: *mut Dynamic, value: *const Dynamic) {
916    if addr.is_null() || value.is_null() {
917        return;
918    }
919    unsafe {
920        (&mut *addr).push_dynamic((&*value).clone());
921    }
922}
923
924extern "C" fn list_str_get_idx(addr: *const Dynamic, idx: i64) -> *const Dynamic {
925    if addr.is_null() {
926        return any_null();
927    };
928    let Ok(idx) = usize::try_from(idx) else {
929        return any_null();
930    };
931    if let Some(value) = unsafe { (&*addr).get_idx(idx) } { alloc_dynamic(value) } else { any_null() }
932}
933
934extern "C" fn list_str_set_idx(addr: *mut Dynamic, idx: i64, value: *const Dynamic) {
935    if addr.is_null() || value.is_null() {
936        return;
937    }
938    let Ok(idx) = usize::try_from(idx) else {
939        return;
940    };
941    unsafe {
942        (&mut *addr).set_idx(idx, (&*value).clone());
943    }
944}
945
946extern "C" fn slice(addr: *const Dynamic, start: i64, stop: *const Dynamic, inclusive: bool) -> *const Dynamic {
947    if addr.is_null() {
948        return any_null();
949    }
950
951    let value = unsafe { &*addr };
952    let len = value.len() as i64;
953    let start = start.clamp(0, len) as usize;
954    let mut stop = if stop.is_null() {
955        len
956    } else {
957        let raw = unsafe { &*stop };
958        if raw.is_null() { len } else { raw.as_int().unwrap_or(len) }
959    };
960    if inclusive && stop < len {
961        stop += 1;
962    }
963    let stop = stop.clamp(start as i64, len) as usize;
964
965    let sliced = if value.is_str() {
966        Dynamic::from(value.as_str().chars().skip(start).take(stop.saturating_sub(start)).collect::<String>())
967    } else {
968        match value {
969            Dynamic::List(list) => Dynamic::list(list.read().unwrap()[start..stop].to_vec()),
970            _ => Dynamic::Null,
971        }
972    };
973    alloc_dynamic(sliced)
974}
975
976extern "C" fn set_key(addr: *mut Dynamic, key: *const Dynamic, value: *const Dynamic) {
977    if addr.is_null() || key.is_null() {
978        return;
979    }
980    let key: &str = unsafe { &*key }.as_str();
981    unsafe { (&mut *addr).set_dynamic(key.into(), (&*value).clone()) }
982}
983
984extern "C" fn set_idx(addr: *mut Dynamic, idx: i64, value: *const Dynamic) {
985    if addr.is_null() {
986        return;
987    }
988    unsafe { (&mut *addr).set_idx(idx as usize, (&*value).clone()) }
989}
990
991extern "C" fn any_from_i64(v: i64) -> *const Dynamic {
992    alloc_dynamic(Dynamic::I64(v))
993}
994
995extern "C" fn any_from_u64(v: u64) -> *const Dynamic {
996    alloc_dynamic(Dynamic::U64(v))
997}
998
999extern "C" fn any_from_bool(v: bool) -> *const Dynamic {
1000    alloc_dynamic(Dynamic::Bool(v))
1001}
1002
1003extern "C" fn any_to_i64(addr: *const Dynamic) -> i64 {
1004    if addr.is_null() {
1005        return 0;
1006    }
1007    unsafe {
1008        let value = &*addr;
1009        value
1010            .as_int()
1011            .or_else(|| value.as_float().map(|value| value as i64))
1012            .or_else(|| {
1013                let text = value.as_str();
1014                let text = text.trim();
1015                if text.is_empty() { None } else { text.parse::<i64>().ok().or_else(|| text.parse::<f64>().ok().map(|value| value as i64)) }
1016            })
1017            .unwrap_or(0)
1018    }
1019}
1020
1021extern "C" fn any_to_bool(addr: *const Dynamic) -> bool {
1022    if addr.is_null() {
1023        return false;
1024    }
1025    unsafe {
1026        let value = &*addr;
1027        if let Some(v) = value.as_bool() {
1028            v
1029        } else if let Some(v) = value.as_int() {
1030            v != 0
1031        } else if let Some(v) = value.as_float() {
1032            v != 0.0
1033        } else {
1034            !value.is_null()
1035        }
1036    }
1037}
1038
1039extern "C" fn any_from_f64(v: f64) -> *const Dynamic {
1040    alloc_dynamic(Dynamic::F64(v))
1041}
1042
1043extern "C" fn any_split(addr: *mut Dynamic, s: *const Dynamic) -> *const Dynamic {
1044    if addr.is_null() || s.is_null() {
1045        return any_null();
1046    }
1047    let s: &str = unsafe { &*s }.as_str();
1048    alloc_dynamic(unsafe { (&*addr).clone() }.split(s))
1049}
1050
1051extern "C" fn any_to_f64(addr: *const Dynamic) -> f64 {
1052    if addr.is_null() {
1053        return 0.0;
1054    }
1055    unsafe {
1056        let value = &*addr;
1057        value.as_float().or_else(|| value.as_str().trim().parse::<f64>().ok()).unwrap_or(0.0)
1058    }
1059}
1060
1061extern "C" fn any_to_string(addr: *const Dynamic) -> *const Dynamic {
1062    if addr.is_null() {
1063        return alloc_dynamic(Dynamic::from(""));
1064    }
1065    alloc_dynamic(Dynamic::from(unsafe { &*addr }.to_string()))
1066}
1067
1068extern "C" fn any_binary(left: *const Dynamic, op: i32, right: *const Dynamic) -> *const Dynamic {
1069    if left.is_null() {
1070        if right.is_null() {
1071            return any_null();
1072        }
1073        return alloc_dynamic(unsafe { (&*right).clone() });
1074    }
1075    if right.is_null() {
1076        return alloc_dynamic(unsafe { (&*left).clone() });
1077    }
1078    let op = BinaryOp::try_from(op).unwrap();
1079    if op == BinaryOp::Add {
1080        let (left_value, right_value) = unsafe { (&*left, &*right) };
1081        if left_value.is_str() || right_value.is_str() {
1082            return alloc_dynamic(left_value.clone() + right_value.clone());
1083        }
1084    }
1085    unsafe {
1086        let expr = Expr::new(
1087            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())) },
1088            Span::default(),
1089        );
1090        alloc_dynamic(expr.compact().unwrap_or(Dynamic::Null))
1091    }
1092}
1093
1094extern "C" fn any_logic(left: *const Dynamic, op: i32, right: *const Dynamic) -> i32 {
1095    let op = BinaryOp::try_from(op).unwrap();
1096    unsafe {
1097        let expr = Expr::new(
1098            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())) },
1099            Span::default(),
1100        );
1101        if expr.compact().and_then(|r| r.as_bool()).unwrap_or(false) { 1 } else { 0 }
1102    }
1103}
1104
1105pub const STD: [(&str, &[Type], Type, *const u8); 5] = [
1106    ("print", &[Type::Any], Type::Void, print as *const u8),
1107    ("sqrt", &[Type::F64], Type::F64, sqrt as *const u8),
1108    ("log", &[Type::Any], Type::Void, log_any as *const u8),
1109    ("uuid", &[], Type::Any, uuid as *const u8),
1110    ("rand", &[Type::Any, Type::Any], Type::Any, random as *const u8),
1111];
1112
1113pub const ANY: [(&str, &[Type], Type, *const u8); 68] = [
1114    ("Any::null", &[], Type::Any, any_null as *const u8),
1115    ("Any::is_map", &[Type::Any], Type::Bool, any_is_map as *const u8),
1116    ("Any::is_list", &[Type::Any], Type::Bool, any_is_list as *const u8),
1117    ("Any::is_string", &[Type::Any], Type::Bool, any_is_string as *const u8),
1118    ("Any::is_null", &[Type::Any], Type::Bool, any_is_null as *const u8),
1119    ("Any::clone", &[Type::Any], Type::Any, any_clone as *const u8),
1120    ("Any::len", &[Type::Any], Type::I32, any_len as *const u8),
1121    ("Any::keys", &[Type::Any], Type::Any, any_keys as *const u8),
1122    ("Any::split", &[Type::Any, Type::Any], Type::Any, any_split as *const u8),
1123    ("Any::push", &[Type::Any, Type::Any], Type::Void, any_push as *const u8),
1124    ("Any::pop", &[Type::Any], Type::Any, any_pop as *const u8),
1125    ("Any::get_idx", &[Type::Any, Type::I64], Type::Any, get_idx as *const u8),
1126    ("Any::push_bool", &[Type::Any, Type::Bool], Type::Void, list_bool_push as *const u8),
1127    ("Any::get_idx_bool", &[Type::Any, Type::I64], Type::Bool, list_bool_get_idx as *const u8),
1128    ("Any::set_idx_bool", &[Type::Any, Type::I64, Type::Bool], Type::Void, list_bool_set_idx as *const u8),
1129    ("Any::push_u8", &[Type::Any, Type::U8], Type::Void, list_u8_push as *const u8),
1130    ("Any::get_idx_u8", &[Type::Any, Type::I64], Type::U8, list_u8_get_idx as *const u8),
1131    ("Any::set_idx_u8", &[Type::Any, Type::I64, Type::U8], Type::Void, list_u8_set_idx as *const u8),
1132    ("Any::push_i8", &[Type::Any, Type::I8], Type::Void, list_i8_push as *const u8),
1133    ("Any::get_idx_i8", &[Type::Any, Type::I64], Type::I8, list_i8_get_idx as *const u8),
1134    ("Any::set_idx_i8", &[Type::Any, Type::I64, Type::I8], Type::Void, list_i8_set_idx as *const u8),
1135    ("Any::push_u16", &[Type::Any, Type::U16], Type::Void, list_u16_push as *const u8),
1136    ("Any::get_idx_u16", &[Type::Any, Type::I64], Type::U16, list_u16_get_idx as *const u8),
1137    ("Any::set_idx_u16", &[Type::Any, Type::I64, Type::U16], Type::Void, list_u16_set_idx as *const u8),
1138    ("Any::push_i16", &[Type::Any, Type::I16], Type::Void, list_i16_push as *const u8),
1139    ("Any::get_idx_i16", &[Type::Any, Type::I64], Type::I16, list_i16_get_idx as *const u8),
1140    ("Any::set_idx_i16", &[Type::Any, Type::I64, Type::I16], Type::Void, list_i16_set_idx as *const u8),
1141    ("Any::push_u32", &[Type::Any, Type::U32], Type::Void, list_u32_push as *const u8),
1142    ("Any::get_idx_u32", &[Type::Any, Type::I64], Type::U32, list_u32_get_idx as *const u8),
1143    ("Any::set_idx_u32", &[Type::Any, Type::I64, Type::U32], Type::Void, list_u32_set_idx as *const u8),
1144    ("Any::push_i32", &[Type::Any, Type::I32], Type::Void, list_i32_push as *const u8),
1145    ("Any::get_idx_i32", &[Type::Any, Type::I64], Type::I32, list_i32_get_idx as *const u8),
1146    ("Any::set_idx_i32", &[Type::Any, Type::I64, Type::I32], Type::Void, list_i32_set_idx as *const u8),
1147    ("Any::push_f32", &[Type::Any, Type::F32], Type::Void, list_f32_push as *const u8),
1148    ("Any::get_idx_f32", &[Type::Any, Type::I64], Type::F32, list_f32_get_idx as *const u8),
1149    ("Any::set_idx_f32", &[Type::Any, Type::I64, Type::F32], Type::Void, list_f32_set_idx as *const u8),
1150    ("Any::push_u64", &[Type::Any, Type::U64], Type::Void, list_u64_push as *const u8),
1151    ("Any::get_idx_u64", &[Type::Any, Type::I64], Type::U64, list_u64_get_idx as *const u8),
1152    ("Any::set_idx_u64", &[Type::Any, Type::I64, Type::U64], Type::Void, list_u64_set_idx as *const u8),
1153    ("Any::push_i64", &[Type::Any, Type::I64], Type::Void, list_i64_push as *const u8),
1154    ("Any::get_idx_i64", &[Type::Any, Type::I64], Type::I64, list_i64_get_idx as *const u8),
1155    ("Any::set_idx_i64", &[Type::Any, Type::I64, Type::I64], Type::Void, list_i64_set_idx as *const u8),
1156    ("Any::push_f64", &[Type::Any, Type::F64], Type::Void, list_f64_push as *const u8),
1157    ("Any::get_idx_f64", &[Type::Any, Type::I64], Type::F64, list_f64_get_idx as *const u8),
1158    ("Any::set_idx_f64", &[Type::Any, Type::I64, Type::F64], Type::Void, list_f64_set_idx as *const u8),
1159    ("Any::push_str", &[Type::Any, Type::Str], Type::Void, list_str_push as *const u8),
1160    ("Any::get_idx_str", &[Type::Any, Type::I64], Type::Str, list_str_get_idx as *const u8),
1161    ("Any::set_idx_str", &[Type::Any, Type::I64, Type::Str], Type::Void, list_str_set_idx as *const u8),
1162    ("Any::slice", &[Type::Any, Type::I64, Type::Any, Type::Bool], Type::Any, slice as *const u8),
1163    ("Any::contains", &[Type::Any, Type::Any], Type::Bool, contains as *const u8),
1164    ("Any::starts_with", &[Type::Any, Type::Any], Type::Bool, starts_with as *const u8),
1165    ("Any::get_key", &[Type::Any, Type::Any], Type::Any, get_key as *const u8),
1166    ("Any::del_key", &[Type::Any, Type::Any], Type::Any, del_key as *const u8),
1167    ("Any::set_idx", &[Type::Any, Type::I64, Type::Any], Type::Void, set_idx as *const u8),
1168    ("Any::set_key", &[Type::Any, Type::Any, Type::Any], Type::Void, set_key as *const u8),
1169    ("Any::from_i64", &[Type::I64], Type::Any, any_from_i64 as *const u8),
1170    ("Any::from_u64", &[Type::U64], Type::Any, any_from_u64 as *const u8),
1171    ("Any::from_bool", &[Type::Bool], Type::Any, any_from_bool as *const u8),
1172    ("Any::to_i64", &[Type::Any], Type::I64, any_to_i64 as *const u8),
1173    ("Any::to_bool", &[Type::Any], Type::Bool, any_to_bool as *const u8),
1174    ("Any::from_f64", &[Type::F64], Type::Any, any_from_f64 as *const u8),
1175    ("Any::to_f64", &[Type::Any], Type::F64, any_to_f64 as *const u8),
1176    ("Any::to_string", &[Type::Any], Type::Str, any_to_string as *const u8),
1177    ("Any::binary", &[Type::Any, Type::I32, Type::Any], Type::Any, any_binary as *const u8),
1178    ("Any::logic", &[Type::Any, Type::I32, Type::Any], Type::Bool, any_logic as *const u8),
1179    ("Any::iter", &[Type::Any], Type::Any, any_iter as *const u8),
1180    ("Any::next", &[Type::Any], Type::Any, any_next as *const u8),
1181    ("Any::next_pair", &[Type::Any], Type::Any, any_next_pair as *const u8),
1182];
1183
1184use std::rc::Rc;
1185impl JITRunTime {
1186    pub fn add_native_ptr(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type, fn_ptr: *const u8) -> Result<u32> {
1187        self.native_symbols.write().unwrap().insert(full_name.to_string(), fn_ptr as usize);
1188        self.add_native(full_name, name, arg_tys, ret_ty)
1189    }
1190
1191    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> {
1192        self.native_symbols.write().unwrap().insert(full_name.to_string(), fn_ptr as usize);
1193        self.add_context_native(full_name, name, arg_tys, ret_ty)
1194    }
1195
1196    pub fn add_native(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type) -> Result<u32> {
1197        let fn_ty = Type::Fn { tys: arg_tys.to_vec(), ret: Rc::new(ret_ty.clone()) };
1198        let id = self.compiler.add_symbol(name, compiler::Symbol::Native(fn_ty.clone()));
1199        let sig = self.get_sig(arg_tys, ret_ty)?;
1200        let fn_id = self.module.declare_function(full_name, Linkage::Import, &sig)?;
1201        self.fns.insert(id, FnVariant::Native { ty: fn_ty, fn_id, context: None });
1202        Ok(id)
1203    }
1204
1205    pub(crate) fn add_context_native(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type) -> Result<u32> {
1206        let fn_ty = Type::Fn { tys: arg_tys.to_vec(), ret: Rc::new(ret_ty.clone()) };
1207        let id = self.compiler.add_symbol(name, compiler::Symbol::Native(fn_ty.clone()));
1208        let mut sig = self.module.make_signature();
1209        sig.params.push(AbiParam::new(crate::ptr_type()));
1210        for arg in arg_tys.iter() {
1211            sig.params.push(AbiParam::new(crate::get_type(arg)?));
1212        }
1213        if !ret_ty.is_void() {
1214            sig.returns.push(AbiParam::new(crate::get_type(&ret_ty)?));
1215        }
1216        let fn_id = self.module.declare_function(full_name, Linkage::Import, &sig)?;
1217        self.fns.insert(id, FnVariant::Native { ty: fn_ty, fn_id, context: Some(self.owner_context_ptr()) });
1218        Ok(id)
1219    }
1220}