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