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