1use super::FnVariant;
2use crate::JITRunTime;
3use crate::memory::{alloc_dynamic, alloc_struct_bytes, take_dynamic_return};
4use anyhow::{Result, anyhow};
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 call_jit_isolated(|| 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 unsafe {
57 let cloned_value = (*addr).deep_clone();
58 alloc_dynamic(cloned_value)
59 }
60}
61
62extern "C" fn any_null() -> *const Dynamic {
63 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 call_jit_isolated(|| unsafe { call_spawned(ptr, &ret_ty, &ptrs) })
349}
350
351pub(crate) extern "C" fn spawn_ptr(fn_ptr: i64, ret_ty: i64, args: *const Dynamic) -> bool {
352 if fn_ptr == 0 || ret_ty == 0 {
353 return false;
354 }
355 let fn_ptr = fn_ptr as usize;
356 let ret_ty = unsafe { (&*(ret_ty as *const Type)).clone() };
357 let args = if args.is_null() { Dynamic::Null } else { unsafe { (&*args).deep_clone() } };
358 std::thread::Builder::new()
359 .name("zust:closure".to_string())
360 .spawn(move || {
361 if let Err(err) = spawn_run_ptr(fn_ptr, ret_ty, args) {
362 log::error!("spawn closure failed: {err:?}");
363 }
364 })
365 .is_ok()
366}
367
368pub(crate) extern "C" fn callback_new(fn_ptr: i64, ret_ty: i64, explicit_arg_len: i64, captures: *const Dynamic) -> *const Dynamic {
369 if fn_ptr == 0 || ret_ty == 0 {
370 return alloc_dynamic(Dynamic::Null);
371 }
372 let ret_ty = unsafe { (&*(ret_ty as *const Type)).clone() };
373 let explicit_arg_len = usize::try_from(explicit_arg_len).unwrap_or(usize::MAX);
374 let captures = if captures.is_null() {
375 Vec::new()
376 } else {
377 match unsafe { &*captures } {
378 Dynamic::List(values) => values.read().unwrap().iter().map(Dynamic::deep_clone).collect(),
379 value => vec![value.deep_clone()],
380 }
381 };
382 alloc_dynamic(Dynamic::custom(ZustCallback::new_with_arg_len(fn_ptr as usize, ret_ty, explicit_arg_len, captures)))
383}
384
385fn spawn_run_ptr(fn_ptr: usize, ret_ty: Type, args: Dynamic) -> Result<()> {
386 let args = spawn_args(args);
387 if args.len() > 16 {
388 anyhow::bail!("spawn supports at most 16 args, got {}", args.len());
389 }
390 let args: Vec<Box<Dynamic>> = args.into_iter().map(Box::new).collect();
391 let ptrs: Vec<*const Dynamic> = args.iter().map(|arg| arg.as_ref() as *const Dynamic).collect();
392 call_jit_isolated(|| unsafe { call_spawned(fn_ptr as *const u8, &ret_ty, &ptrs) })
393}
394
395pub(crate) fn call_jit_isolated<T>(f: impl FnOnce() -> Result<T>) -> Result<T> {
407 let _ = dynamic::take_fault();
408 let outcome = std::panic::catch_unwind(std::panic::AssertUnwindSafe(f));
409 match outcome {
410 Ok(inner) => match dynamic::take_fault() {
411 Some(reason) => Err(anyhow!("脚本运行期错误: {}", reason)),
412 None => inner,
413 },
414 Err(_) => Err(anyhow!("脚本执行 panic,已隔离")),
415 }
416}
417
418unsafe fn call_callback(ptr: *const u8, ret_ty: &Type, args: &[*const Dynamic]) -> Result<Dynamic> {
419 macro_rules! callback_arg_ty {
420 ($arg:ident) => {
421 *const Dynamic
422 };
423 }
424
425 macro_rules! callback_args {
426 ($body:ident $(, $extra:tt)*) => {
427 match args {
428 [] => $body!($($extra),*;),
429 [a] => $body!($($extra),*; a),
430 [a, b] => $body!($($extra),*; a, b),
431 [a, b, c] => $body!($($extra),*; a, b, c),
432 [a, b, c, d] => $body!($($extra),*; a, b, c, d),
433 [a, b, c, d, e] => $body!($($extra),*; a, b, c, d, e),
434 [a, b, c, d, e, f] => $body!($($extra),*; a, b, c, d, e, f),
435 [a, b, c, d, e, f, g] => $body!($($extra),*; a, b, c, d, e, f, g),
436 [a, b, c, d, e, f, g, h] => $body!($($extra),*; a, b, c, d, e, f, g, h),
437 [a, b, c, d, e, f, g, h, i] => $body!($($extra),*; a, b, c, d, e, f, g, h, i),
438 [a, b, c, d, e, f, g, h, i, j] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j),
439 [a, b, c, d, e, f, g, h, i, j, k] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k),
440 [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),
441 [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),
442 [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),
443 [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),
444 [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),
445 [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),
446 [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),
447 [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),
448 [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),
449 [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),
450 [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),
451 [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),
452 [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),
453 _ => anyhow::bail!("callback supports at most 24 args including captures, got {}", args.len()),
454 }
455 };
456 }
457
458 macro_rules! call_void_body {
459 (; $($arg:ident),*) => {{
460 let fn_ptr: extern "C" fn($(callback_arg_ty!($arg)),*) = unsafe { std::mem::transmute(ptr) };
461 fn_ptr($(*$arg),*)
462 }};
463 }
464
465 macro_rules! call_void {
466 () => {
467 callback_args!(call_void_body)
468 };
469 }
470
471 macro_rules! call_ret_body {
472 ($ret:ty, $dynamic:expr; $($arg:ident),*) => {{
473 let fn_ptr: extern "C" fn($(callback_arg_ty!($arg)),*) -> $ret = unsafe { std::mem::transmute(ptr) };
474 $dynamic(fn_ptr($(*$arg),*))
475 }};
476 }
477
478 macro_rules! call_ret {
479 ($ret:ty, $dynamic:expr) => {{ callback_args!(call_ret_body, $ret, $dynamic) }};
480 }
481
482 if ret_ty.is_void() {
483 call_void!();
484 Ok(Dynamic::Null)
485 } else if ret_ty.is_bool() {
486 call_ret!(bool, |value| Ok(Dynamic::Bool(value)))
487 } else if ret_ty.is_float() {
488 if ret_ty.is_f64() { call_ret!(f64, |value| Ok(Dynamic::F64(value))) } else { call_ret!(f32, |value| Ok(Dynamic::F32(value))) }
489 } else if ret_ty.is_int() || ret_ty.is_uint() {
490 match ret_ty {
491 Type::I8 => call_ret!(i8, |value| Ok(Dynamic::I8(value))),
492 Type::U8 => call_ret!(u8, |value| Ok(Dynamic::U8(value))),
493 Type::I16 => call_ret!(i16, |value| Ok(Dynamic::I16(value))),
494 Type::U16 => call_ret!(u16, |value| Ok(Dynamic::U16(value))),
495 Type::I32 => call_ret!(i32, |value| Ok(Dynamic::I32(value))),
496 Type::U32 => call_ret!(u32, |value| Ok(Dynamic::U32(value))),
497 Type::I64 => call_ret!(i64, |value| Ok(Dynamic::I64(value))),
498 Type::U64 => call_ret!(u64, |value| Ok(Dynamic::U64(value))),
499 _ => unreachable!(),
500 }
501 } else if ret_ty.is_struct() || ret_ty.is_array() || ret_ty.is_vec() {
502 log::warn!("callback returns {ret_ty:?} — not supported, discarding");
503 call_ret!(*const u8, |_| Ok(Dynamic::Null))
504 } else {
505 call_ret!(*const Dynamic, |ptr| unsafe { Ok((*take_dynamic_return(ptr)).deep_clone()) })
506 }
507}
508
509unsafe fn call_spawned(ptr: *const u8, ret_ty: &Type, args: &[*const Dynamic]) -> Result<()> {
510 macro_rules! call_void {
511 () => {
512 match args {
513 [] => unsafe { std::mem::transmute::<_, extern "C" fn()>(ptr)() },
514 [a] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic)>(ptr)(*a) },
515 [a, b] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic)>(ptr)(*a, *b) },
516 [a, b, c] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c) },
517 [a, b, c, d] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c, *d) },
518 [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) },
519 [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) },
520 [a, b, c, d, e, f, g] => unsafe {
521 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)
522 },
523 [a, b, c, d, e, f, g, h] => unsafe {
524 std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(
525 *a, *b, *c, *d, *e, *f, *g, *h,
526 )
527 },
528 [a, b, c, d, e, f, g, h, i] => unsafe {
529 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)(
530 *a, *b, *c, *d, *e, *f, *g, *h, *i,
531 )
532 },
533 [a, b, c, d, e, f, g, h, i, j] => 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, *const Dynamic)>(ptr)(
535 *a, *b, *c, *d, *e, *f, *g, *h, *i, *j,
536 )
537 },
538 [a, b, c, d, e, f, g, h, i, j, k] => 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, *const Dynamic)>(ptr)(
540 *a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k,
541 )
542 },
543 [a, b, c, d, e, f, g, h, i, j, k, l] => unsafe {
544 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)(
545 *a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l,
546 )
547 },
548 [a, b, c, d, e, f, g, h, i, j, k, l, m] => unsafe {
549 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)(
550 *a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m,
551 )
552 },
553 [a, b, c, d, e, f, g, h, i, j, k, l, m, n] => unsafe {
554 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)(
555 *a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n,
556 )
557 },
558 [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o] => unsafe {
559 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)(
560 *a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n, *o,
561 )
562 },
563 [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] => unsafe {
564 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)(
565 *a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n, *o, *p,
566 )
567 },
568 _ => unreachable!(),
569 }
570 };
571 }
572
573 if ret_ty.is_void() {
574 call_void!();
575 return Ok(());
576 }
577
578 macro_rules! call_ret {
579 ($ret:ty, $drop_result:expr) => {
580 match args {
581 [] => {
582 let fn_ptr: extern "C" fn() -> $ret = unsafe { std::mem::transmute(ptr) };
583 $drop_result(fn_ptr());
584 }
585 [a] => {
586 let fn_ptr: extern "C" fn(*const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
587 $drop_result(fn_ptr(*a));
588 }
589 [a, b] => {
590 let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
591 $drop_result(fn_ptr(*a, *b));
592 }
593 [a, b, c] => {
594 let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
595 $drop_result(fn_ptr(*a, *b, *c));
596 }
597 [a, b, c, d] => {
598 let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
599 $drop_result(fn_ptr(*a, *b, *c, *d));
600 }
601 [a, b, c, d, e] => {
602 let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
603 $drop_result(fn_ptr(*a, *b, *c, *d, *e));
604 }
605 [a, b, c, d, e, f] => {
606 let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
607 $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f));
608 }
609 [a, b, c, d, e, f, g] => {
610 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) };
611 $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g));
612 }
613 [a, b, c, d, e, f, g, h] => {
614 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) };
615 $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h));
616 }
617 [a, b, c, d, e, f, g, h, i] => {
618 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) };
619 $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i));
620 }
621 [a, b, c, d, e, f, g, h, i, j] => {
622 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) };
623 $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j));
624 }
625 [a, b, c, d, e, f, g, h, i, j, k] => {
626 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) };
627 $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k));
628 }
629 [a, b, c, d, e, f, g, h, i, j, k, l] => {
630 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) };
631 $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l));
632 }
633 [a, b, c, d, e, f, g, h, i, j, k, l, m] => {
634 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) };
635 $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m));
636 }
637 [a, b, c, d, e, f, g, h, i, j, k, l, m, n] => {
638 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) };
639 $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n));
640 }
641 [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o] => {
642 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) };
643 $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n, *o));
644 }
645 [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] => {
646 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) };
647 $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n, *o, *p));
648 }
649 _ => unreachable!(),
650 }
651 };
652 }
653
654 if ret_ty.is_bool() {
655 call_ret!(bool, |_| {});
656 } else if ret_ty.is_float() {
657 if ret_ty.is_f64() {
658 call_ret!(f64, |_| {});
659 } else {
660 call_ret!(f32, |_| {});
661 }
662 } else if ret_ty.is_int() || ret_ty.is_uint() {
663 match ret_ty {
664 Type::I8 => call_ret!(i8, |_| {}),
665 Type::U8 => call_ret!(u8, |_| {}),
666 Type::I16 => call_ret!(i16, |_| {}),
667 Type::U16 => call_ret!(u16, |_| {}),
668 Type::I32 => call_ret!(i32, |_| {}),
669 Type::U32 => call_ret!(u32, |_| {}),
670 Type::I64 => call_ret!(i64, |_| {}),
671 Type::U64 => call_ret!(u64, |_| {}),
672 _ => unreachable!(),
673 }
674 } else if ret_ty.is_struct() || ret_ty.is_array() || ret_ty.is_vec() {
675 log::warn!("spawned fn returns {ret_ty:?} — not supported, discarding");
676 call_ret!(*const u8, |_| {});
677 } else {
678 call_ret!(*const Dynamic, |ptr| drop(unsafe { take_dynamic_return(ptr) }));
679 }
680 Ok(())
681}
682
683extern "C" fn any_len(addr: *const Dynamic) -> i64 {
684 if addr.is_null() { 0 } else { unsafe { (&*addr).len() as i64 } }
685}
686
687extern "C" fn any_keys(addr: *const Dynamic) -> *const Dynamic {
688 if addr.is_null() {
689 return alloc_dynamic(Dynamic::list(Vec::new()));
690 }
691 let keys = match unsafe { &*addr } {
692 Dynamic::Map(map) => map.read().unwrap().keys().map(|key| Dynamic::from(key.as_str())).collect(),
693 _ => Vec::new(),
694 };
695 alloc_dynamic(Dynamic::list(keys))
696}
697
698extern "C" fn any_iter(addr: *const Dynamic) -> *const Dynamic {
699 if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).clone().into_iter() }) }
700}
701
702extern "C" fn any_next(addr: *const Dynamic) -> *const Dynamic {
703 if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (&mut *(addr as *mut Dynamic)).next().unwrap_or(Dynamic::Null) }) }
704}
705
706extern "C" fn any_next_pair(addr: *const Dynamic) -> *const Dynamic {
707 if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (&mut *(addr as *mut Dynamic)).next_pair().unwrap_or(Dynamic::Null) }) }
708}
709
710extern "C" fn any_push(addr: *mut Dynamic, value: *mut Dynamic) {
711 if !addr.is_null() && !value.is_null() {
712 unsafe {
713 (&mut *addr).push_dynamic((&*value).clone());
714 }
715 }
716}
717
718extern "C" fn any_pop(addr: *mut Dynamic) -> *const Dynamic {
719 if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).pop().unwrap_or(Dynamic::Null) }) }
720}
721
722extern "C" fn get_key(addr: *const Dynamic, key: *const Dynamic) -> *const Dynamic {
723 if addr.is_null() || key.is_null() {
724 any_null()
725 } else {
726 let key: &str = unsafe { &*key }.as_str();
727 alloc_dynamic(unsafe { (*addr).get_dynamic(key).unwrap_or(Dynamic::Null) })
728 }
729}
730
731extern "C" fn del_key(addr: *const Dynamic, key: *const Dynamic) -> *const Dynamic {
732 if addr.is_null() || key.is_null() {
733 any_null()
734 } else {
735 let key: &str = unsafe { &*key }.as_str();
736 alloc_dynamic(unsafe { (*addr).remove_dynamic(key).unwrap_or(Dynamic::Null) })
737 }
738}
739
740extern "C" fn contains(addr: *const Dynamic, key: *const Dynamic) -> bool {
741 if addr.is_null() || key.is_null() {
742 false
743 } else {
744 let key: &str = unsafe { &*key }.as_str();
745 unsafe { (*addr).contains(key) }
746 }
747}
748
749extern "C" fn starts_with(addr: *const Dynamic, prefix: *const Dynamic) -> bool {
750 if addr.is_null() || prefix.is_null() {
751 false
752 } else {
753 let prefix: &str = unsafe { &*prefix }.as_str();
754 unsafe { (*addr).starts_with(prefix) }
755 }
756}
757
758extern "C" fn get_idx(addr: *const Dynamic, idx: i64) -> *const Dynamic {
759 if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).get_idx(idx as usize).unwrap_or(Dynamic::Null) }) }
760}
761
762macro_rules! myvec_list_native {
763 ($push:ident, $get_idx:ident, $set_idx:ident, $vec:ident, $dynamic:ident, $ty:ty, $fallback:expr) => {
764 extern "C" fn $push(addr: *mut Dynamic, value: $ty) {
765 if addr.is_null() {
766 return;
767 }
768 unsafe {
769 match &mut *addr {
770 Dynamic::$vec(values) => values.push(value),
771 list => {
772 list.push_dynamic(Dynamic::$dynamic(value));
773 }
774 }
775 }
776 }
777
778 extern "C" fn $get_idx(addr: *const Dynamic, idx: i64) -> $ty {
779 if addr.is_null() {
780 return <$ty>::default();
781 }
782 let Ok(idx) = usize::try_from(idx) else {
783 return <$ty>::default();
784 };
785 unsafe {
786 match &*addr {
787 Dynamic::$vec(values) => values.get(idx).unwrap_or_default(),
788 values => values.get_idx(idx).and_then($fallback).unwrap_or_default(),
789 }
790 }
791 }
792
793 extern "C" fn $set_idx(addr: *mut Dynamic, idx: i64, value: $ty) {
794 if addr.is_null() {
795 return;
796 }
797 let Ok(idx) = usize::try_from(idx) else {
798 return;
799 };
800 unsafe {
801 match &mut *addr {
802 Dynamic::$vec(values) => values.set(idx, value),
803 list => list.set_idx(idx, Dynamic::$dynamic(value)),
804 }
805 }
806 }
807 };
808}
809
810macro_rules! stdvec_list_native {
811 ($push:ident, $get_idx:ident, $set_idx:ident, $vec:ident, $dynamic:ident, $ty:ty, $fallback:expr) => {
812 extern "C" fn $push(addr: *mut Dynamic, value: $ty) {
813 if addr.is_null() {
814 return;
815 }
816 unsafe {
817 match &mut *addr {
818 Dynamic::$vec(values) => values.push(value),
819 list => {
820 list.push_dynamic(Dynamic::$dynamic(value));
821 }
822 }
823 }
824 }
825
826 extern "C" fn $get_idx(addr: *const Dynamic, idx: i64) -> $ty {
827 if addr.is_null() {
828 return <$ty>::default();
829 }
830 let Ok(idx) = usize::try_from(idx) else {
831 return <$ty>::default();
832 };
833 unsafe {
834 match &*addr {
835 Dynamic::$vec(values) => values.get(idx).copied().unwrap_or_default(),
836 values => values.get_idx(idx).and_then($fallback).unwrap_or_default(),
837 }
838 }
839 }
840
841 extern "C" fn $set_idx(addr: *mut Dynamic, idx: i64, value: $ty) {
842 if addr.is_null() {
843 return;
844 }
845 let Ok(idx) = usize::try_from(idx) else {
846 return;
847 };
848 unsafe {
849 match &mut *addr {
850 Dynamic::$vec(values) => {
851 if let Some(slot) = values.get_mut(idx) {
852 *slot = value;
853 }
854 }
855 list => list.set_idx(idx, Dynamic::$dynamic(value)),
856 }
857 }
858 }
859 };
860}
861
862myvec_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));
863myvec_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));
864myvec_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));
865myvec_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));
866myvec_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));
867myvec_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));
868stdvec_list_native!(list_u64_push, list_u64_get_idx, list_u64_set_idx, VecU64, U64, u64, |value: Dynamic| value.as_uint());
869stdvec_list_native!(list_i64_push, list_i64_get_idx, list_i64_set_idx, VecI64, I64, i64, |value: Dynamic| value.as_int());
870stdvec_list_native!(list_f64_push, list_f64_get_idx, list_f64_set_idx, VecF64, F64, f64, |value: Dynamic| value.as_float());
871
872extern "C" fn list_bool_push(addr: *mut Dynamic, value: bool) {
873 if !addr.is_null() {
874 unsafe {
875 (&mut *addr).push_dynamic(Dynamic::Bool(value));
876 }
877 }
878}
879
880extern "C" fn list_bool_get_idx(addr: *const Dynamic, idx: i64) -> bool {
881 if addr.is_null() {
882 return false;
883 }
884 let Ok(idx) = usize::try_from(idx) else {
885 return false;
886 };
887 unsafe { (&*addr).get_idx(idx).and_then(|value| value.as_bool()).unwrap_or(false) }
888}
889
890extern "C" fn list_bool_set_idx(addr: *mut Dynamic, idx: i64, value: bool) {
891 if addr.is_null() {
892 return;
893 }
894 let Ok(idx) = usize::try_from(idx) else {
895 return;
896 };
897 unsafe {
898 (&mut *addr).set_idx(idx, Dynamic::Bool(value));
899 }
900}
901
902extern "C" fn list_u8_push(addr: *mut Dynamic, value: u8) {
903 if !addr.is_null() {
904 unsafe {
905 (&mut *addr).push_dynamic(Dynamic::U8(value));
906 }
907 }
908}
909
910extern "C" fn list_u8_get_idx(addr: *const Dynamic, idx: i64) -> u8 {
911 if addr.is_null() {
912 return 0;
913 }
914 let Ok(idx) = usize::try_from(idx) else {
915 return 0;
916 };
917 unsafe { (&*addr).get_idx(idx).and_then(|value| value.as_uint()).map(|value| value as u8).unwrap_or(0) }
918}
919
920extern "C" fn list_u8_set_idx(addr: *mut Dynamic, idx: i64, value: u8) {
921 if addr.is_null() {
922 return;
923 }
924 let Ok(idx) = usize::try_from(idx) else {
925 return;
926 };
927 unsafe {
928 (&mut *addr).set_idx(idx, Dynamic::U8(value));
929 }
930}
931
932extern "C" fn list_str_push(addr: *mut Dynamic, value: *const Dynamic) {
933 if addr.is_null() || value.is_null() {
934 return;
935 }
936 unsafe {
937 (&mut *addr).push_dynamic((&*value).clone());
938 }
939}
940
941extern "C" fn list_str_get_idx(addr: *const Dynamic, idx: i64) -> *const Dynamic {
942 if addr.is_null() {
943 return any_null();
944 };
945 let Ok(idx) = usize::try_from(idx) else {
946 return any_null();
947 };
948 if let Some(value) = unsafe { (&*addr).get_idx(idx) } { alloc_dynamic(value) } else { any_null() }
949}
950
951extern "C" fn list_str_set_idx(addr: *mut Dynamic, idx: i64, value: *const Dynamic) {
952 if addr.is_null() || value.is_null() {
953 return;
954 }
955 let Ok(idx) = usize::try_from(idx) else {
956 return;
957 };
958 unsafe {
959 (&mut *addr).set_idx(idx, (&*value).clone());
960 }
961}
962
963extern "C" fn slice(addr: *const Dynamic, start: i64, stop: *const Dynamic, inclusive: bool) -> *const Dynamic {
964 if addr.is_null() {
965 return any_null();
966 }
967
968 let value = unsafe { &*addr };
969 let len = value.len() as i64;
970 let start = start.clamp(0, len) as usize;
971 let mut stop = if stop.is_null() {
972 len
973 } else {
974 let raw = unsafe { &*stop };
975 if raw.is_null() { len } else { raw.as_int().unwrap_or(len) }
976 };
977 if inclusive && stop < len {
978 stop += 1;
979 }
980 let stop = stop.clamp(start as i64, len) as usize;
981
982 let sliced = if value.is_str() {
983 Dynamic::from(value.as_str().chars().skip(start).take(stop.saturating_sub(start)).collect::<String>())
984 } else {
985 match value {
986 Dynamic::List(list) => Dynamic::list(list.read().unwrap()[start..stop].to_vec()),
987 _ => Dynamic::Null,
988 }
989 };
990 alloc_dynamic(sliced)
991}
992
993extern "C" fn set_key(addr: *mut Dynamic, key: *const Dynamic, value: *const Dynamic) {
994 if addr.is_null() || key.is_null() {
995 return;
996 }
997 let key: &str = unsafe { &*key }.as_str();
998 unsafe { (&mut *addr).set_dynamic(key.into(), (&*value).clone()) }
999}
1000
1001extern "C" fn set_idx(addr: *mut Dynamic, idx: i64, value: *const Dynamic) {
1002 if addr.is_null() {
1003 return;
1004 }
1005 unsafe { (&mut *addr).set_idx(idx as usize, (&*value).clone()) }
1006}
1007
1008extern "C" fn any_from_i64(v: i64) -> *const Dynamic {
1009 alloc_dynamic(Dynamic::I64(v))
1010}
1011
1012extern "C" fn any_from_u64(v: u64) -> *const Dynamic {
1013 alloc_dynamic(Dynamic::U64(v))
1014}
1015
1016extern "C" fn any_from_bool(v: bool) -> *const Dynamic {
1017 alloc_dynamic(Dynamic::Bool(v))
1018}
1019
1020extern "C" fn any_to_i64(addr: *const Dynamic) -> i64 {
1021 if addr.is_null() {
1022 return 0;
1023 }
1024 unsafe {
1025 let value = &*addr;
1026 value
1027 .as_int()
1028 .or_else(|| value.as_float().map(|value| value as i64))
1029 .or_else(|| {
1030 let text = value.as_str();
1031 let text = text.trim();
1032 if text.is_empty() { None } else { text.parse::<i64>().ok().or_else(|| text.parse::<f64>().ok().map(|value| value as i64)) }
1033 })
1034 .unwrap_or(0)
1035 }
1036}
1037
1038extern "C" fn any_to_bool(addr: *const Dynamic) -> bool {
1039 if addr.is_null() {
1040 return false;
1041 }
1042 unsafe {
1043 let value = &*addr;
1044 if let Some(v) = value.as_bool() {
1045 v
1046 } else if let Some(v) = value.as_int() {
1047 v != 0
1048 } else if let Some(v) = value.as_float() {
1049 v != 0.0
1050 } else {
1051 !value.is_null()
1052 }
1053 }
1054}
1055
1056extern "C" fn any_from_f64(v: f64) -> *const Dynamic {
1057 alloc_dynamic(Dynamic::F64(v))
1058}
1059
1060extern "C" fn any_split(addr: *mut Dynamic, s: *const Dynamic) -> *const Dynamic {
1061 if addr.is_null() || s.is_null() {
1062 return any_null();
1063 }
1064 let s: &str = unsafe { &*s }.as_str();
1065 alloc_dynamic(unsafe { (&*addr).clone() }.split(s))
1066}
1067
1068extern "C" fn any_to_f64(addr: *const Dynamic) -> f64 {
1069 if addr.is_null() {
1070 return 0.0;
1071 }
1072 unsafe {
1073 let value = &*addr;
1074 value.as_float().or_else(|| value.as_str().trim().parse::<f64>().ok()).unwrap_or(0.0)
1075 }
1076}
1077
1078extern "C" fn any_to_string(addr: *const Dynamic) -> *const Dynamic {
1079 if addr.is_null() {
1080 return alloc_dynamic(Dynamic::from(""));
1081 }
1082 alloc_dynamic(Dynamic::from(unsafe { &*addr }.to_string()))
1083}
1084
1085extern "C" fn any_binary(left: *const Dynamic, op: i32, right: *const Dynamic) -> *const Dynamic {
1086 if left.is_null() {
1087 if right.is_null() {
1088 return any_null();
1089 }
1090 return alloc_dynamic(unsafe { (&*right).clone() });
1091 }
1092 if right.is_null() {
1093 return alloc_dynamic(unsafe { (&*left).clone() });
1094 }
1095 let op = BinaryOp::try_from(op).unwrap_or(BinaryOp::Unknow);
1096 if op == BinaryOp::Add {
1097 let (left_value, right_value) = unsafe { (&*left, &*right) };
1098 if left_value.is_str() || right_value.is_str() {
1099 return alloc_dynamic(left_value.clone() + right_value.clone());
1100 }
1101 }
1102 unsafe {
1103 let expr = Expr::new(
1104 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())) },
1105 Span::default(),
1106 );
1107 alloc_dynamic(expr.compact().unwrap_or(Dynamic::Null))
1108 }
1109}
1110
1111extern "C" fn any_logic(left: *const Dynamic, op: i32, right: *const Dynamic) -> i32 {
1112 let op = BinaryOp::try_from(op).unwrap_or(BinaryOp::Unknow);
1113 unsafe {
1114 let expr = Expr::new(
1115 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())) },
1116 Span::default(),
1117 );
1118 if expr.compact().and_then(|r| r.as_bool()).unwrap_or(false) { 1 } else { 0 }
1119 }
1120}
1121
1122pub const STD: [(&str, &[Type], Type, *const u8); 5] = [
1123 ("print", &[Type::Any], Type::Void, print as *const u8),
1124 ("sqrt", &[Type::F64], Type::F64, sqrt as *const u8),
1125 ("log", &[Type::Any], Type::Void, log_any as *const u8),
1126 ("uuid", &[], Type::Any, uuid as *const u8),
1127 ("rand", &[Type::Any, Type::Any], Type::Any, random as *const u8),
1128];
1129
1130pub const ANY: [(&str, &[Type], Type, *const u8); 68] = [
1131 ("Any::null", &[], Type::Any, any_null as *const u8),
1132 ("Any::is_map", &[Type::Any], Type::Bool, any_is_map as *const u8),
1133 ("Any::is_list", &[Type::Any], Type::Bool, any_is_list as *const u8),
1134 ("Any::is_string", &[Type::Any], Type::Bool, any_is_string as *const u8),
1135 ("Any::is_null", &[Type::Any], Type::Bool, any_is_null as *const u8),
1136 ("Any::clone", &[Type::Any], Type::Any, any_clone as *const u8),
1137 ("Any::len", &[Type::Any], Type::I32, any_len as *const u8),
1138 ("Any::keys", &[Type::Any], Type::Any, any_keys as *const u8),
1139 ("Any::split", &[Type::Any, Type::Any], Type::Any, any_split as *const u8),
1140 ("Any::push", &[Type::Any, Type::Any], Type::Void, any_push as *const u8),
1141 ("Any::pop", &[Type::Any], Type::Any, any_pop as *const u8),
1142 ("Any::get_idx", &[Type::Any, Type::I64], Type::Any, get_idx as *const u8),
1143 ("Any::push_bool", &[Type::Any, Type::Bool], Type::Void, list_bool_push as *const u8),
1144 ("Any::get_idx_bool", &[Type::Any, Type::I64], Type::Bool, list_bool_get_idx as *const u8),
1145 ("Any::set_idx_bool", &[Type::Any, Type::I64, Type::Bool], Type::Void, list_bool_set_idx as *const u8),
1146 ("Any::push_u8", &[Type::Any, Type::U8], Type::Void, list_u8_push as *const u8),
1147 ("Any::get_idx_u8", &[Type::Any, Type::I64], Type::U8, list_u8_get_idx as *const u8),
1148 ("Any::set_idx_u8", &[Type::Any, Type::I64, Type::U8], Type::Void, list_u8_set_idx as *const u8),
1149 ("Any::push_i8", &[Type::Any, Type::I8], Type::Void, list_i8_push as *const u8),
1150 ("Any::get_idx_i8", &[Type::Any, Type::I64], Type::I8, list_i8_get_idx as *const u8),
1151 ("Any::set_idx_i8", &[Type::Any, Type::I64, Type::I8], Type::Void, list_i8_set_idx as *const u8),
1152 ("Any::push_u16", &[Type::Any, Type::U16], Type::Void, list_u16_push as *const u8),
1153 ("Any::get_idx_u16", &[Type::Any, Type::I64], Type::U16, list_u16_get_idx as *const u8),
1154 ("Any::set_idx_u16", &[Type::Any, Type::I64, Type::U16], Type::Void, list_u16_set_idx as *const u8),
1155 ("Any::push_i16", &[Type::Any, Type::I16], Type::Void, list_i16_push as *const u8),
1156 ("Any::get_idx_i16", &[Type::Any, Type::I64], Type::I16, list_i16_get_idx as *const u8),
1157 ("Any::set_idx_i16", &[Type::Any, Type::I64, Type::I16], Type::Void, list_i16_set_idx as *const u8),
1158 ("Any::push_u32", &[Type::Any, Type::U32], Type::Void, list_u32_push as *const u8),
1159 ("Any::get_idx_u32", &[Type::Any, Type::I64], Type::U32, list_u32_get_idx as *const u8),
1160 ("Any::set_idx_u32", &[Type::Any, Type::I64, Type::U32], Type::Void, list_u32_set_idx as *const u8),
1161 ("Any::push_i32", &[Type::Any, Type::I32], Type::Void, list_i32_push as *const u8),
1162 ("Any::get_idx_i32", &[Type::Any, Type::I64], Type::I32, list_i32_get_idx as *const u8),
1163 ("Any::set_idx_i32", &[Type::Any, Type::I64, Type::I32], Type::Void, list_i32_set_idx as *const u8),
1164 ("Any::push_f32", &[Type::Any, Type::F32], Type::Void, list_f32_push as *const u8),
1165 ("Any::get_idx_f32", &[Type::Any, Type::I64], Type::F32, list_f32_get_idx as *const u8),
1166 ("Any::set_idx_f32", &[Type::Any, Type::I64, Type::F32], Type::Void, list_f32_set_idx as *const u8),
1167 ("Any::push_u64", &[Type::Any, Type::U64], Type::Void, list_u64_push as *const u8),
1168 ("Any::get_idx_u64", &[Type::Any, Type::I64], Type::U64, list_u64_get_idx as *const u8),
1169 ("Any::set_idx_u64", &[Type::Any, Type::I64, Type::U64], Type::Void, list_u64_set_idx as *const u8),
1170 ("Any::push_i64", &[Type::Any, Type::I64], Type::Void, list_i64_push as *const u8),
1171 ("Any::get_idx_i64", &[Type::Any, Type::I64], Type::I64, list_i64_get_idx as *const u8),
1172 ("Any::set_idx_i64", &[Type::Any, Type::I64, Type::I64], Type::Void, list_i64_set_idx as *const u8),
1173 ("Any::push_f64", &[Type::Any, Type::F64], Type::Void, list_f64_push as *const u8),
1174 ("Any::get_idx_f64", &[Type::Any, Type::I64], Type::F64, list_f64_get_idx as *const u8),
1175 ("Any::set_idx_f64", &[Type::Any, Type::I64, Type::F64], Type::Void, list_f64_set_idx as *const u8),
1176 ("Any::push_str", &[Type::Any, Type::Str], Type::Void, list_str_push as *const u8),
1177 ("Any::get_idx_str", &[Type::Any, Type::I64], Type::Str, list_str_get_idx as *const u8),
1178 ("Any::set_idx_str", &[Type::Any, Type::I64, Type::Str], Type::Void, list_str_set_idx as *const u8),
1179 ("Any::slice", &[Type::Any, Type::I64, Type::Any, Type::Bool], Type::Any, slice as *const u8),
1180 ("Any::contains", &[Type::Any, Type::Any], Type::Bool, contains as *const u8),
1181 ("Any::starts_with", &[Type::Any, Type::Any], Type::Bool, starts_with as *const u8),
1182 ("Any::get_key", &[Type::Any, Type::Any], Type::Any, get_key as *const u8),
1183 ("Any::del_key", &[Type::Any, Type::Any], Type::Any, del_key as *const u8),
1184 ("Any::set_idx", &[Type::Any, Type::I64, Type::Any], Type::Void, set_idx as *const u8),
1185 ("Any::set_key", &[Type::Any, Type::Any, Type::Any], Type::Void, set_key as *const u8),
1186 ("Any::from_i64", &[Type::I64], Type::Any, any_from_i64 as *const u8),
1187 ("Any::from_u64", &[Type::U64], Type::Any, any_from_u64 as *const u8),
1188 ("Any::from_bool", &[Type::Bool], Type::Any, any_from_bool as *const u8),
1189 ("Any::to_i64", &[Type::Any], Type::I64, any_to_i64 as *const u8),
1190 ("Any::to_bool", &[Type::Any], Type::Bool, any_to_bool as *const u8),
1191 ("Any::from_f64", &[Type::F64], Type::Any, any_from_f64 as *const u8),
1192 ("Any::to_f64", &[Type::Any], Type::F64, any_to_f64 as *const u8),
1193 ("Any::to_string", &[Type::Any], Type::Str, any_to_string as *const u8),
1194 ("Any::binary", &[Type::Any, Type::I32, Type::Any], Type::Any, any_binary as *const u8),
1195 ("Any::logic", &[Type::Any, Type::I32, Type::Any], Type::Bool, any_logic as *const u8),
1196 ("Any::iter", &[Type::Any], Type::Any, any_iter as *const u8),
1197 ("Any::next", &[Type::Any], Type::Any, any_next as *const u8),
1198 ("Any::next_pair", &[Type::Any], Type::Any, any_next_pair as *const u8),
1199];
1200
1201use std::rc::Rc;
1202impl JITRunTime {
1203 pub fn add_native_ptr(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type, fn_ptr: *const u8) -> Result<u32> {
1204 self.native_symbols.write().unwrap().insert(full_name.to_string(), fn_ptr as usize);
1205 self.add_native(full_name, name, arg_tys, ret_ty)
1206 }
1207
1208 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> {
1209 self.native_symbols.write().unwrap().insert(full_name.to_string(), fn_ptr as usize);
1210 self.add_context_native(full_name, name, arg_tys, ret_ty)
1211 }
1212
1213 pub fn add_native(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type) -> Result<u32> {
1214 let fn_ty = Type::Fn { tys: arg_tys.to_vec(), ret: Rc::new(ret_ty.clone()) };
1215 let id = self.compiler.add_symbol(name, compiler::Symbol::Native(fn_ty.clone()));
1216 let sig = self.get_sig(arg_tys, ret_ty)?;
1217 let fn_id = self.module.declare_function(full_name, Linkage::Import, &sig)?;
1218 self.fns.insert(id, FnVariant::Native { ty: fn_ty, fn_id, context: None });
1219 Ok(id)
1220 }
1221
1222 pub(crate) fn add_context_native(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type) -> Result<u32> {
1223 let fn_ty = Type::Fn { tys: arg_tys.to_vec(), ret: Rc::new(ret_ty.clone()) };
1224 let id = self.compiler.add_symbol(name, compiler::Symbol::Native(fn_ty.clone()));
1225 let mut sig = self.module.make_signature();
1226 sig.params.push(AbiParam::new(crate::ptr_type()));
1227 for arg in arg_tys.iter() {
1228 sig.params.push(AbiParam::new(crate::get_type(arg)?));
1229 }
1230 if !ret_ty.is_void() {
1231 sig.returns.push(AbiParam::new(crate::get_type(&ret_ty)?));
1232 }
1233 let fn_id = self.module.declare_function(full_name, Linkage::Import, &sig)?;
1234 self.fns.insert(id, FnVariant::Native { ty: fn_ty, fn_id, context: Some(self.owner_context_ptr()) });
1235 Ok(id)
1236 }
1237}