lust/
embed.rs

1use crate::ast::{EnumDef, FieldOwnership, Item, ItemKind, Span, StructDef, Type, TypeKind};
2use crate::bytecode::{Compiler, NativeCallResult, TaskHandle, Value};
3use crate::modules::{ModuleImports, ModuleLoader};
4use crate::number::{LustFloat, LustInt};
5use crate::typechecker::{FunctionSignature, TypeChecker};
6use crate::vm::VM;
7use crate::{LustConfig, LustError, Result};
8use hashbrown::HashMap;
9use std::cell::RefCell;
10use std::future::Future;
11use std::path::{Path, PathBuf};
12use std::pin::Pin;
13use std::rc::Rc;
14use std::sync::atomic::{AtomicBool, Ordering};
15use std::sync::Arc;
16use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
17
18type AsyncValueFuture = Pin<Box<dyn Future<Output = std::result::Result<Value, String>>>>;
19
20struct AsyncRegistry {
21    pending: HashMap<u64, AsyncTaskEntry>,
22}
23
24impl AsyncRegistry {
25    fn new() -> Self {
26        Self {
27            pending: HashMap::new(),
28        }
29    }
30
31    fn register(
32        &mut self,
33        handle: TaskHandle,
34        future: AsyncValueFuture,
35    ) -> std::result::Result<(), String> {
36        let key = handle.id();
37        if self.pending.contains_key(&key) {
38            return Err(format!(
39                "Task {} already has a pending async native call",
40                key
41            ));
42        }
43
44        self.pending
45            .insert(key, AsyncTaskEntry::new(handle, future));
46        Ok(())
47    }
48
49    fn is_empty(&self) -> bool {
50        self.pending.is_empty()
51    }
52}
53
54struct AsyncTaskEntry {
55    handle: TaskHandle,
56    future: AsyncValueFuture,
57    wake_flag: Arc<WakeFlag>,
58    immediate_poll: bool,
59}
60
61impl AsyncTaskEntry {
62    fn new(handle: TaskHandle, future: AsyncValueFuture) -> Self {
63        Self {
64            handle,
65            future,
66            wake_flag: Arc::new(WakeFlag::new()),
67            immediate_poll: true,
68        }
69    }
70
71    fn take_should_poll(&mut self) -> bool {
72        if self.immediate_poll {
73            self.immediate_poll = false;
74            true
75        } else {
76            self.wake_flag.take()
77        }
78    }
79
80    fn make_waker(&self) -> Waker {
81        make_async_waker(&self.wake_flag)
82    }
83}
84
85struct WakeFlag {
86    pending: AtomicBool,
87}
88
89impl WakeFlag {
90    fn new() -> Self {
91        Self {
92            pending: AtomicBool::new(true),
93        }
94    }
95
96    fn take(&self) -> bool {
97        self.pending.swap(false, Ordering::SeqCst)
98    }
99
100    fn wake(&self) {
101        self.pending.store(true, Ordering::SeqCst);
102    }
103}
104
105fn make_async_waker(flag: &Arc<WakeFlag>) -> Waker {
106    unsafe {
107        Waker::from_raw(RawWaker::new(
108            Arc::into_raw(flag.clone()) as *const (),
109            &ASYNC_WAKER_VTABLE,
110        ))
111    }
112}
113
114unsafe fn async_waker_clone(ptr: *const ()) -> RawWaker {
115    let arc = Arc::<WakeFlag>::from_raw(ptr as *const WakeFlag);
116    let cloned = arc.clone();
117    std::mem::forget(arc);
118    RawWaker::new(Arc::into_raw(cloned) as *const (), &ASYNC_WAKER_VTABLE)
119}
120
121unsafe fn async_waker_wake(ptr: *const ()) {
122    let arc = Arc::<WakeFlag>::from_raw(ptr as *const WakeFlag);
123    arc.wake();
124}
125
126unsafe fn async_waker_wake_by_ref(ptr: *const ()) {
127    let arc = Arc::<WakeFlag>::from_raw(ptr as *const WakeFlag);
128    arc.wake();
129    std::mem::forget(arc);
130}
131
132unsafe fn async_waker_drop(ptr: *const ()) {
133    let _ = Arc::<WakeFlag>::from_raw(ptr as *const WakeFlag);
134}
135
136static ASYNC_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
137    async_waker_clone,
138    async_waker_wake,
139    async_waker_wake_by_ref,
140    async_waker_drop,
141);
142pub struct EmbeddedBuilder {
143    base_dir: PathBuf,
144    modules: HashMap<String, String>,
145    entry_module: Option<String>,
146    config: LustConfig,
147}
148
149impl Default for EmbeddedBuilder {
150    fn default() -> Self {
151        Self {
152            base_dir: PathBuf::from("__embedded__"),
153            modules: HashMap::new(),
154            entry_module: None,
155            config: LustConfig::default(),
156        }
157    }
158}
159
160impl EmbeddedBuilder {
161    pub fn new() -> Self {
162        Self::default()
163    }
164
165    pub fn with_base_dir(self, base_dir: impl Into<PathBuf>) -> Self {
166        self.set_base_dir(base_dir)
167    }
168
169    pub fn set_base_dir(mut self, base_dir: impl Into<PathBuf>) -> Self {
170        self.base_dir = base_dir.into();
171        self
172    }
173
174    pub fn module(mut self, module_path: impl Into<String>, source: impl Into<String>) -> Self {
175        self.modules.insert(module_path.into(), source.into());
176        self
177    }
178
179    pub fn enable_stdlib_module<S: AsRef<str>>(mut self, module: S) -> Self {
180        self.config.enable_module(module);
181        self
182    }
183
184    pub fn add_stdlib_module<S: AsRef<str>>(mut self, module: S) -> Self {
185        self.config.enable_module(module);
186        self
187    }
188
189    pub fn with_config(mut self, config: LustConfig) -> Self {
190        self.config = config;
191        self
192    }
193
194    pub fn set_config(mut self, config: LustConfig) -> Self {
195        self.config = config;
196        self
197    }
198
199    pub fn add_module(
200        &mut self,
201        module_path: impl Into<String>,
202        source: impl Into<String>,
203    ) -> &mut Self {
204        self.modules.insert(module_path.into(), source.into());
205        self
206    }
207
208    pub fn entry_module(mut self, module_path: impl Into<String>) -> Self {
209        self.set_entry_module(module_path);
210        self
211    }
212
213    pub fn set_entry_module(&mut self, module_path: impl Into<String>) -> &mut Self {
214        self.entry_module = Some(module_path.into());
215        self
216    }
217
218    pub fn compile(self) -> Result<EmbeddedProgram> {
219        let entry_module = self
220            .entry_module
221            .ok_or_else(|| LustError::Unknown("No entry module configured for embedding".into()))?;
222        let has_entry = self.modules.contains_key(&entry_module);
223        if !has_entry {
224            return Err(LustError::Unknown(format!(
225                "Entry module '{}' was not provided via EmbeddedBuilder::module",
226                entry_module
227            )));
228        }
229
230        let overrides: HashMap<PathBuf, String> = self
231            .modules
232            .into_iter()
233            .map(|(module, source)| (module_path_to_file(&self.base_dir, &module), source))
234            .collect();
235        compile_in_memory(self.base_dir, entry_module, overrides, self.config)
236    }
237}
238
239pub struct EmbeddedProgram {
240    vm: VM,
241    signatures: HashMap<String, FunctionSignature>,
242    struct_defs: HashMap<String, StructDef>,
243    enum_defs: HashMap<String, EnumDef>,
244    entry_script: Option<String>,
245    entry_module: String,
246    async_registry: Rc<RefCell<AsyncRegistry>>,
247}
248
249impl EmbeddedProgram {
250    pub fn builder() -> EmbeddedBuilder {
251        EmbeddedBuilder::default()
252    }
253
254    pub fn vm_mut(&mut self) -> &mut VM {
255        &mut self.vm
256    }
257
258    pub fn global_names(&self) -> Vec<String> {
259        self.vm.global_names()
260    }
261
262    pub fn globals(&self) -> Vec<(String, Value)> {
263        self.vm.globals_snapshot()
264    }
265
266    pub fn signature(&self, function_name: &str) -> Option<&FunctionSignature> {
267        self.find_signature(function_name).map(|(_, sig)| sig)
268    }
269
270    pub fn typed_functions(&self) -> impl Iterator<Item = (&String, &FunctionSignature)> {
271        self.signatures.iter()
272    }
273
274    pub fn struct_definition(&self, type_name: &str) -> Option<&StructDef> {
275        self.struct_defs.get(type_name)
276    }
277
278    pub fn enum_definition(&self, type_name: &str) -> Option<&EnumDef> {
279        self.enum_defs.get(type_name)
280    }
281
282    fn find_signature(&self, name: &str) -> Option<(String, &FunctionSignature)> {
283        if let Some(sig) = self.signatures.get(name) {
284            return Some((name.to_string(), sig));
285        }
286
287        for candidate in self.signature_lookup_candidates(name) {
288            if let Some(sig) = self.signatures.get(&candidate) {
289                return Some((candidate, sig));
290            }
291        }
292
293        let matches = self
294            .signatures
295            .iter()
296            .filter_map(|(key, sig)| {
297                if Self::simple_name(key) == name {
298                    Some((key, sig))
299                } else {
300                    None
301                }
302            })
303            .collect::<Vec<_>>();
304        if matches.len() == 1 {
305            let (key, sig) = matches[0];
306            return Some((key.clone(), sig));
307        }
308
309        None
310    }
311
312    fn resolve_signature(&self, name: &str) -> Result<(String, &FunctionSignature)> {
313        if let Some(found) = self.find_signature(name) {
314            return Ok(found);
315        }
316
317        let matches = self
318            .signatures
319            .keys()
320            .filter(|key| Self::simple_name(key) == name)
321            .count();
322        if matches > 1 {
323            return Err(LustError::TypeError {
324                message: format!(
325                    "Cannot register native '{}': multiple matching functions found; specify a fully qualified name",
326                    name
327                ),
328            });
329        }
330
331        Err(LustError::TypeError {
332            message: format!(
333                "Cannot register native '{}': function not declared in Lust source",
334                name
335            ),
336        })
337    }
338
339    fn signature_lookup_candidates(&self, name: &str) -> Vec<String> {
340        let mut candidates: Vec<String> = Vec::new();
341        if name.contains("::") {
342            candidates.push(name.replace("::", "."));
343        }
344
345        if name.contains('.') {
346            candidates.push(name.replace('.', "::"));
347        }
348
349        if !name.contains('.') && !name.contains("::") {
350            let module = &self.entry_module;
351            candidates.push(format!("{}.{}", module, name));
352            candidates.push(format!("{}::{}", module, name));
353        }
354
355        candidates
356    }
357
358    fn simple_name(name: &str) -> &str {
359        name.rsplit(|c| c == '.' || c == ':').next().unwrap_or(name)
360    }
361
362    fn register_native_with_aliases<F>(&mut self, requested_name: &str, canonical: String, func: F)
363    where
364        F: Fn(&[Value]) -> std::result::Result<NativeCallResult, String> + 'static,
365    {
366        let native_fn: Rc<dyn Fn(&[Value]) -> std::result::Result<NativeCallResult, String>> =
367            Rc::new(func);
368        let value = Value::NativeFunction(native_fn);
369        let mut aliases: Vec<String> = Vec::new();
370        aliases.push(canonical.clone());
371        let canonical_normalized = normalize_global_name(&canonical);
372        if canonical_normalized != canonical {
373            aliases.push(canonical_normalized);
374        }
375
376        if requested_name != canonical {
377            aliases.push(requested_name.to_string());
378            let normalized = normalize_global_name(requested_name);
379            if normalized != requested_name {
380                aliases.push(normalized);
381            }
382        }
383
384        aliases.sort();
385        aliases.dedup();
386        for key in aliases {
387            self.vm.register_native(key, value.clone());
388        }
389    }
390
391    pub fn get_global_value(&self, name: &str) -> Option<Value> {
392        let normalized = normalize_global_name(name);
393        self.vm.get_global(&normalized)
394    }
395
396    pub fn get_typed_global<T: FromLustValue>(&self, name: &str) -> Result<Option<T>> {
397        let normalized = normalize_global_name(name);
398        match self.vm.get_global(&normalized) {
399            Some(value) => T::from_value(value).map(Some),
400            None => Ok(None),
401        }
402    }
403
404    pub fn set_global_value<V: IntoTypedValue>(&mut self, name: impl Into<String>, value: V) {
405        let name_string = name.into();
406        let normalized = normalize_global_name(&name_string);
407        let value = value.into_typed_value().into_value();
408        self.vm.set_global(normalized, value);
409    }
410
411    pub fn struct_instance<I>(
412        &self,
413        type_name: impl Into<String>,
414        fields: I,
415    ) -> Result<StructInstance>
416    where
417        I: IntoIterator,
418        I::Item: Into<StructField>,
419    {
420        let type_name = type_name.into();
421        let def = self
422            .struct_defs
423            .get(&type_name)
424            .ok_or_else(|| LustError::TypeError {
425                message: format!("Unknown struct '{}'", type_name),
426            })?;
427        let mut provided: HashMap<String, TypedValue> = fields
428            .into_iter()
429            .map(|field| {
430                let field: StructField = field.into();
431                field.into_parts()
432            })
433            .collect();
434        let mut ordered_fields: Vec<(Rc<String>, Value)> = Vec::with_capacity(def.fields.len());
435        for field in &def.fields {
436            let typed_value = provided
437                .remove(&field.name)
438                .ok_or_else(|| LustError::TypeError {
439                    message: format!(
440                        "Struct '{}' is missing required field '{}'",
441                        type_name, field.name
442                    ),
443                })?;
444            let matches_declared = typed_value.matches(&field.ty);
445            let matches_ref_inner = matches!(field.ownership, FieldOwnership::Weak)
446                && field
447                    .weak_target
448                    .as_ref()
449                    .map(|inner| typed_value.matches(inner))
450                    .unwrap_or(false);
451            if !(matches_declared || matches_ref_inner) {
452                return Err(LustError::TypeError {
453                    message: format!(
454                        "Struct '{}' field '{}' expects Lust type '{}' but Rust provided '{}'",
455                        type_name,
456                        field.name,
457                        field.ty,
458                        typed_value.description()
459                    ),
460                });
461            }
462
463            ordered_fields.push((Rc::new(field.name.clone()), typed_value.into_value()));
464        }
465
466        if !provided.is_empty() {
467            let extra = provided.keys().cloned().collect::<Vec<_>>().join(", ");
468            return Err(LustError::TypeError {
469                message: format!(
470                    "Struct '{}' received unknown field(s): {}",
471                    type_name, extra
472                ),
473            });
474        }
475
476        let value = self.vm.instantiate_struct(&type_name, ordered_fields)?;
477        Ok(StructInstance::new(type_name.clone(), value))
478    }
479
480    pub fn enum_variant(
481        &self,
482        type_name: impl Into<String>,
483        variant: impl Into<String>,
484    ) -> Result<EnumInstance> {
485        self.enum_variant_with(type_name, variant, std::iter::empty::<Value>())
486    }
487
488    pub fn enum_variant_with<I, V>(
489        &self,
490        type_name: impl Into<String>,
491        variant: impl Into<String>,
492        payload: I,
493    ) -> Result<EnumInstance>
494    where
495        I: IntoIterator<Item = V>,
496        V: IntoTypedValue,
497    {
498        let type_name = type_name.into();
499        let variant_name = variant.into();
500        let def = self
501            .enum_defs
502            .get(&type_name)
503            .ok_or_else(|| LustError::TypeError {
504                message: format!("Unknown enum '{}'", type_name),
505            })?;
506        let enum_variant = def
507            .variants
508            .iter()
509            .find(|v| v.name == variant_name)
510            .ok_or_else(|| LustError::TypeError {
511                message: format!(
512                    "Enum '{}' has no variant named '{}'",
513                    type_name, variant_name
514                ),
515            })?;
516        let mut values: Vec<TypedValue> =
517            payload.into_iter().map(|v| v.into_typed_value()).collect();
518        let coerced_values: Option<Rc<Vec<Value>>> = match &enum_variant.fields {
519            None => {
520                if !values.is_empty() {
521                    return Err(LustError::TypeError {
522                        message: format!(
523                            "Enum variant '{}.{}' does not accept payload values",
524                            type_name, variant_name
525                        ),
526                    });
527                }
528
529                None
530            }
531
532            Some(field_types) => {
533                if values.len() != field_types.len() {
534                    return Err(LustError::TypeError {
535                        message: format!(
536                            "Enum variant '{}.{}' expects {} value(s) but {} were supplied",
537                            type_name,
538                            variant_name,
539                            field_types.len(),
540                            values.len()
541                        ),
542                    });
543                }
544
545                let mut collected = Vec::with_capacity(field_types.len());
546                for (idx, (typed_value, field_ty)) in
547                    values.drain(..).zip(field_types.iter()).enumerate()
548                {
549                    if !typed_value.matches(field_ty) {
550                        return Err(LustError::TypeError {
551                            message: format!(
552                                "Enum variant '{}.{}' field {} expects Lust type '{}' but Rust provided '{}'",
553                                type_name,
554                                variant_name,
555                                idx + 1,
556                                field_ty,
557                                typed_value.description()
558                            ),
559                        });
560                    }
561
562                    collected.push(typed_value.into_value());
563                }
564
565                Some(Rc::new(collected))
566            }
567        };
568        Ok(EnumInstance::new(
569            type_name.clone(),
570            variant_name.clone(),
571            Value::Enum {
572                enum_name: type_name,
573                variant: variant_name,
574                values: coerced_values,
575            },
576        ))
577    }
578
579    pub fn register_native_fn<F>(&mut self, name: impl Into<String>, func: F)
580    where
581        F: Fn(&[Value]) -> std::result::Result<NativeCallResult, String> + 'static,
582    {
583        let native = Value::NativeFunction(Rc::new(func));
584        self.vm.register_native(name, native);
585    }
586
587    pub fn register_async_native<F, Fut>(&mut self, name: impl Into<String>, func: F) -> Result<()>
588    where
589        F: Fn(Vec<Value>) -> Fut + 'static,
590        Fut: Future<Output = std::result::Result<Value, String>> + 'static,
591    {
592        let registry = self.async_registry.clone();
593        let name_string = name.into();
594        let handler = move |values: &[Value]| -> std::result::Result<NativeCallResult, String> {
595            let args: Vec<Value> = values.iter().cloned().collect();
596            let future: AsyncValueFuture = Box::pin(func(args));
597            VM::with_current(|vm| {
598                let handle = vm
599                    .current_task_handle()
600                    .ok_or_else(|| "Async native functions require a running task".to_string())?;
601                registry.borrow_mut().register(handle, future)?;
602                Ok(NativeCallResult::Yield(Value::Nil))
603            })
604        };
605        self.register_native_fn(name_string, handler);
606        Ok(())
607    }
608
609    pub fn register_typed_native<Args, R, F>(&mut self, name: &str, func: F) -> Result<()>
610    where
611        Args: FromLustArgs,
612        R: IntoLustValue + FromLustValue,
613        F: Fn(Args) -> std::result::Result<R, String> + 'static,
614    {
615        let (canonical, signature) = self.resolve_signature(name)?;
616        if !Args::matches_signature(&signature.params) {
617            return Err(LustError::TypeError {
618                message: format!(
619                    "Native '{}' argument types do not match Lust signature",
620                    name
621                ),
622            });
623        }
624
625        ensure_return_type::<R>(name, &signature.return_type)?;
626        let handler = move |values: &[Value]| -> std::result::Result<NativeCallResult, String> {
627            let args = Args::from_values(values)?;
628            let result = func(args)?;
629            Ok(NativeCallResult::Return(result.into_value()))
630        };
631        self.register_native_with_aliases(name, canonical, handler);
632        Ok(())
633    }
634
635    pub fn register_async_typed_native<Args, R, F, Fut>(
636        &mut self,
637        name: &str,
638        func: F,
639    ) -> Result<()>
640    where
641        Args: FromLustArgs,
642        R: IntoLustValue + FromLustValue,
643        F: Fn(Args) -> Fut + 'static,
644        Fut: Future<Output = std::result::Result<R, String>> + 'static,
645    {
646        let (canonical, signature) = self.resolve_signature(name)?;
647        let signature = signature.clone();
648        if !Args::matches_signature(&signature.params) {
649            return Err(LustError::TypeError {
650                message: format!(
651                    "Native '{}' argument types do not match Lust signature",
652                    name
653                ),
654            });
655        }
656
657        ensure_return_type::<R>(name, &signature.return_type)?;
658        let registry = self.async_registry.clone();
659        let handler = move |values: &[Value]| -> std::result::Result<NativeCallResult, String> {
660            let args = Args::from_values(values)?;
661            let future = func(args);
662            let mapped = async move {
663                match future.await {
664                    Ok(result) => Ok(result.into_value()),
665                    Err(err) => Err(err),
666                }
667            };
668            let future: AsyncValueFuture = Box::pin(mapped);
669            VM::with_current(|vm| {
670                let handle = vm
671                    .current_task_handle()
672                    .ok_or_else(|| "Async native functions require a running task".to_string())?;
673                registry.borrow_mut().register(handle, future)?;
674                Ok(NativeCallResult::Yield(Value::Nil))
675            })
676        };
677        self.register_native_with_aliases(name, canonical, handler);
678        Ok(())
679    }
680
681    pub fn call_typed<Args, R>(&mut self, function_name: &str, args: Args) -> Result<R>
682    where
683        Args: FunctionArgs,
684        R: FromLustValue,
685    {
686        let signature = self
687            .signatures
688            .get(function_name)
689            .ok_or_else(|| LustError::TypeError {
690                message: format!(
691                    "No type information available for function '{}'; \
692                     use call_raw if the function is dynamically typed",
693                    function_name
694                ),
695            })?;
696        Args::validate_signature(function_name, &signature.params)?;
697        ensure_return_type::<R>(function_name, &signature.return_type)?;
698        let values = args.into_values();
699        let value = self.vm.call(function_name, values)?;
700        R::from_value(value)
701    }
702
703    pub fn call_raw(&mut self, function_name: &str, args: Vec<Value>) -> Result<Value> {
704        self.vm.call(function_name, args)
705    }
706
707    pub fn run_entry_script(&mut self) -> Result<()> {
708        let Some(entry) = &self.entry_script else {
709            return Err(LustError::RuntimeError {
710                message: "Embedded program has no entry script".into(),
711            });
712        };
713        let result = self.vm.call(entry, Vec::new())?;
714        match result {
715            Value::Nil => Ok(()),
716            other => Err(LustError::RuntimeError {
717                message: format!(
718                    "Entry script '{}' returned non-unit value: {:?}",
719                    entry, other
720                ),
721            }),
722        }
723    }
724
725    pub fn poll_async_tasks(&mut self) -> Result<()> {
726        let pending_ids: Vec<u64> = {
727            let registry = self.async_registry.borrow();
728            registry.pending.keys().copied().collect()
729        };
730
731        let mut completions: Vec<(TaskHandle, std::result::Result<Value, String>)> = Vec::new();
732        for id in pending_ids {
733            let handle = TaskHandle(id);
734            if self.vm.get_task_instance(handle).is_err() {
735                self.async_registry.borrow_mut().pending.remove(&id);
736                continue;
737            }
738
739            let maybe_outcome = {
740                let mut registry = self.async_registry.borrow_mut();
741                let entry = match registry.pending.get_mut(&id) {
742                    Some(entry) => entry,
743                    None => continue,
744                };
745
746                if !entry.take_should_poll() {
747                    continue;
748                }
749
750                let waker = entry.make_waker();
751                let mut cx = Context::from_waker(&waker);
752                match entry.future.as_mut().poll(&mut cx) {
753                    Poll::Ready(result) => {
754                        let handle = entry.handle;
755                        registry.pending.remove(&id);
756                        Some((handle, result))
757                    }
758
759                    Poll::Pending => None,
760                }
761            };
762
763            if let Some(outcome) = maybe_outcome {
764                completions.push(outcome);
765            }
766        }
767
768        for (handle, outcome) in completions {
769            match outcome {
770                Ok(value) => {
771                    self.vm.resume_task_handle(handle, Some(value))?;
772                }
773
774                Err(message) => {
775                    self.vm
776                        .fail_task_handle(handle, LustError::RuntimeError { message })?;
777                }
778            }
779        }
780
781        Ok(())
782    }
783
784    pub fn has_pending_async_tasks(&self) -> bool {
785        !self.async_registry.borrow().is_empty()
786    }
787}
788
789fn compile_in_memory(
790    base_dir: PathBuf,
791    entry_module: String,
792    overrides: HashMap<PathBuf, String>,
793    config: LustConfig,
794) -> Result<EmbeddedProgram> {
795    let mut loader = ModuleLoader::new(base_dir.clone());
796    loader.set_source_overrides(overrides);
797    let entry_path = module_path_to_file(&base_dir, &entry_module);
798    let entry_path_str = entry_path
799        .to_str()
800        .ok_or_else(|| LustError::Unknown("Entry path contained invalid UTF-8".into()))?
801        .to_string();
802    let program = loader.load_program_from_entry(&entry_path_str)?;
803    let mut imports_map: HashMap<String, ModuleImports> = HashMap::new();
804    for module in &program.modules {
805        imports_map.insert(module.path.clone(), module.imports.clone());
806    }
807
808    let mut wrapped_items: Vec<Item> = Vec::new();
809    for module in &program.modules {
810        wrapped_items.push(Item::new(
811            ItemKind::Module {
812                name: module.path.clone(),
813                items: module.items.clone(),
814            },
815            Span::new(0, 0, 0, 0),
816        ));
817    }
818
819    let mut typechecker = TypeChecker::with_config(&config);
820    typechecker.set_imports_by_module(imports_map.clone());
821    typechecker.check_program(&program.modules)?;
822    let struct_defs = typechecker.struct_definitions();
823    let enum_defs = typechecker.enum_definitions();
824    let mut signatures = typechecker.function_signatures();
825    let mut compiler = Compiler::new();
826    compiler.configure_stdlib(&config);
827    compiler.set_imports_by_module(imports_map);
828    compiler.set_entry_module(program.entry_module.clone());
829    let functions = compiler.compile_module(&wrapped_items)?;
830    let trait_impls = compiler.get_trait_impls().to_vec();
831    let mut init_funcs = Vec::new();
832    for module in &program.modules {
833        if module.path != program.entry_module {
834            if let Some(init) = &module.init_function {
835                init_funcs.push(init.clone());
836            }
837        }
838    }
839
840    let function_names: Vec<String> = functions.iter().map(|f| f.name.clone()).collect();
841    let entry_script = function_names
842        .iter()
843        .find(|name| name.as_str() == "__script")
844        .cloned();
845    if let Some(script_name) = &entry_script {
846        signatures
847            .entry(script_name.clone())
848            .or_insert_with(|| FunctionSignature {
849                params: Vec::new(),
850                return_type: Type::new(TypeKind::Unit, Span::new(0, 0, 0, 0)),
851                is_method: false,
852            });
853    }
854
855    let mut vm = VM::with_config(&config);
856    vm.load_functions(functions);
857    vm.register_structs(&struct_defs);
858    for (type_name, trait_name) in trait_impls {
859        vm.register_trait_impl(type_name, trait_name);
860    }
861
862    for init in init_funcs {
863        vm.call(&init, Vec::new())?;
864    }
865
866    Ok(EmbeddedProgram {
867        vm,
868        signatures,
869        struct_defs,
870        enum_defs,
871        entry_script,
872        entry_module: program.entry_module,
873        async_registry: Rc::new(RefCell::new(AsyncRegistry::new())),
874    })
875}
876
877fn module_path_to_file(base_dir: &Path, module_path: &str) -> PathBuf {
878    let mut path = base_dir.to_path_buf();
879    for segment in module_path.split('.') {
880        path.push(segment);
881    }
882
883    path.set_extension("lust");
884    path
885}
886
887fn normalize_global_name(name: &str) -> String {
888    if name.contains("::") {
889        name.to_string()
890    } else if let Some((module, identifier)) = name.rsplit_once('.') {
891        format!("{}::{}", module, identifier)
892    } else {
893        name.to_string()
894    }
895}
896
897fn ensure_return_type<R: FromLustValue>(function_name: &str, ty: &Type) -> Result<()> {
898    if matches!(ty.kind, TypeKind::Unknown) || R::matches_lust_type(ty) {
899        return Ok(());
900    }
901
902    Err(LustError::TypeError {
903        message: format!(
904            "Function '{}' reports return type '{}' which is incompatible with Rust receiver '{}'",
905            function_name,
906            ty,
907            R::type_description()
908        ),
909    })
910}
911
912pub struct TypedValue {
913    value: Value,
914    matcher: Box<dyn Fn(&Value, &Type) -> bool>,
915    description: &'static str,
916}
917
918impl TypedValue {
919    fn new<F>(value: Value, matcher: F, description: &'static str) -> Self
920    where
921        F: Fn(&Value, &Type) -> bool + 'static,
922    {
923        Self {
924            value,
925            matcher: Box::new(matcher),
926            description,
927        }
928    }
929
930    fn matches(&self, ty: &Type) -> bool {
931        match &ty.kind {
932            TypeKind::Union(types) => types.iter().any(|alt| (self.matcher)(&self.value, alt)),
933            _ => (self.matcher)(&self.value, ty),
934        }
935    }
936
937    fn description(&self) -> &'static str {
938        self.description
939    }
940
941    fn into_value(self) -> Value {
942        self.value
943    }
944}
945
946pub struct StructField {
947    name: String,
948    value: TypedValue,
949}
950
951impl StructField {
952    pub fn new(name: impl Into<String>, value: impl IntoTypedValue) -> Self {
953        Self {
954            name: name.into(),
955            value: value.into_typed_value(),
956        }
957    }
958
959    pub fn name(&self) -> &str {
960        &self.name
961    }
962
963    fn into_parts(self) -> (String, TypedValue) {
964        (self.name, self.value)
965    }
966}
967
968pub fn struct_field(name: impl Into<String>, value: impl IntoTypedValue) -> StructField {
969    StructField::new(name, value)
970}
971
972impl<K, V> From<(K, V)> for StructField
973where
974    K: Into<String>,
975    V: IntoTypedValue,
976{
977    fn from((name, value): (K, V)) -> Self {
978        StructField::new(name, value)
979    }
980}
981
982#[derive(Clone)]
983pub struct StructInstance {
984    type_name: String,
985    value: Value,
986}
987
988impl StructInstance {
989    fn new(type_name: String, value: Value) -> Self {
990        debug_assert!(matches!(value, Value::Struct { .. }));
991        Self { type_name, value }
992    }
993
994    pub fn type_name(&self) -> &str {
995        &self.type_name
996    }
997
998    pub fn field<T: FromLustValue>(&self, field: &str) -> Result<T> {
999        match &self.value {
1000            Value::Struct { layout, fields, .. } => {
1001                let index = layout
1002                    .index_of_str(field)
1003                    .ok_or_else(|| LustError::RuntimeError {
1004                        message: format!(
1005                            "Struct '{}' has no field named '{}'",
1006                            self.type_name, field
1007                        ),
1008                    })?;
1009                let stored =
1010                    fields
1011                        .borrow()
1012                        .get(index)
1013                        .cloned()
1014                        .ok_or_else(|| LustError::RuntimeError {
1015                            message: format!(
1016                                "Struct '{}' field '{}' is unavailable",
1017                                self.type_name, field
1018                            ),
1019                        })?;
1020                let materialized = layout.materialize_field_value(index, stored);
1021                T::from_value(materialized)
1022            }
1023
1024            _ => Err(LustError::RuntimeError {
1025                message: "StructInstance does not contain a struct value".to_string(),
1026            }),
1027        }
1028    }
1029
1030    pub fn set_field<V: IntoTypedValue>(&self, field: &str, value: V) -> Result<()> {
1031        match &self.value {
1032            Value::Struct { layout, fields, .. } => {
1033                let index = layout
1034                    .index_of_str(field)
1035                    .ok_or_else(|| LustError::RuntimeError {
1036                        message: format!(
1037                            "Struct '{}' has no field named '{}'",
1038                            self.type_name, field
1039                        ),
1040                    })?;
1041                let typed_value = value.into_typed_value();
1042                let matches_declared = typed_value.matches(layout.field_type(index));
1043                let matches_ref_inner = layout.is_weak(index)
1044                    && layout
1045                        .weak_target(index)
1046                        .map(|inner| typed_value.matches(inner))
1047                        .unwrap_or(false);
1048                if !(matches_declared || matches_ref_inner) {
1049                    return Err(LustError::TypeError {
1050                        message: format!(
1051                            "Struct '{}' field '{}' expects Lust type '{}' but Rust provided '{}'",
1052                            self.type_name,
1053                            field,
1054                            layout.field_type(index),
1055                            typed_value.description()
1056                        ),
1057                    });
1058                }
1059
1060                let canonical_value = layout
1061                    .canonicalize_field_value(index, typed_value.into_value())
1062                    .map_err(|message| LustError::TypeError { message })?;
1063                fields.borrow_mut()[index] = canonical_value;
1064                Ok(())
1065            }
1066
1067            _ => Err(LustError::RuntimeError {
1068                message: "StructInstance does not contain a struct value".to_string(),
1069            }),
1070        }
1071    }
1072
1073    pub fn update_field<F, V>(&self, field: &str, update: F) -> Result<()>
1074    where
1075        F: FnOnce(Value) -> Result<V>,
1076        V: IntoTypedValue,
1077    {
1078        match &self.value {
1079            Value::Struct { layout, fields, .. } => {
1080                let index = layout
1081                    .index_of_str(field)
1082                    .ok_or_else(|| LustError::RuntimeError {
1083                        message: format!(
1084                            "Struct '{}' has no field named '{}'",
1085                            self.type_name, field
1086                        ),
1087                    })?;
1088                let mut slots = fields.borrow_mut();
1089                let slot = slots
1090                    .get_mut(index)
1091                    .ok_or_else(|| LustError::RuntimeError {
1092                        message: format!(
1093                            "Struct '{}' field '{}' is unavailable",
1094                            self.type_name, field
1095                        ),
1096                    })?;
1097                let fallback = slot.clone();
1098                let current_canonical = std::mem::replace(slot, Value::Nil);
1099                let current_materialized = layout.materialize_field_value(index, current_canonical);
1100                let updated = match update(current_materialized) {
1101                    Ok(value) => value,
1102                    Err(err) => {
1103                        *slot = fallback;
1104                        return Err(err);
1105                    }
1106                };
1107                let typed_value = updated.into_typed_value();
1108                let matches_declared = typed_value.matches(layout.field_type(index));
1109                let matches_ref_inner = layout.is_weak(index)
1110                    && layout
1111                        .weak_target(index)
1112                        .map(|inner| typed_value.matches(inner))
1113                        .unwrap_or(false);
1114                if !(matches_declared || matches_ref_inner) {
1115                    *slot = fallback;
1116                    return Err(LustError::TypeError {
1117                        message: format!(
1118                            "Struct '{}' field '{}' expects Lust type '{}' but Rust provided '{}'",
1119                            self.type_name,
1120                            field,
1121                            layout.field_type(index),
1122                            typed_value.description()
1123                        ),
1124                    });
1125                }
1126
1127                let canonical_value = layout
1128                    .canonicalize_field_value(index, typed_value.into_value())
1129                    .map_err(|message| LustError::TypeError { message })?;
1130                *slot = canonical_value;
1131                Ok(())
1132            }
1133
1134            _ => Err(LustError::RuntimeError {
1135                message: "StructInstance does not contain a struct value".to_string(),
1136            }),
1137        }
1138    }
1139
1140    pub fn as_value(&self) -> &Value {
1141        &self.value
1142    }
1143}
1144
1145#[derive(Clone)]
1146pub struct EnumInstance {
1147    type_name: String,
1148    variant: String,
1149    value: Value,
1150}
1151
1152impl EnumInstance {
1153    fn new(type_name: String, variant: String, value: Value) -> Self {
1154        debug_assert!(matches!(value, Value::Enum { .. }));
1155        Self {
1156            type_name,
1157            variant,
1158            value,
1159        }
1160    }
1161
1162    pub fn type_name(&self) -> &str {
1163        &self.type_name
1164    }
1165
1166    pub fn variant(&self) -> &str {
1167        &self.variant
1168    }
1169
1170    pub fn payload_len(&self) -> usize {
1171        match &self.value {
1172            Value::Enum { values, .. } => values.as_ref().map(|v| v.len()).unwrap_or(0),
1173            _ => 0,
1174        }
1175    }
1176
1177    pub fn payload<T: FromLustValue>(&self, index: usize) -> Result<T> {
1178        match &self.value {
1179            Value::Enum { values, .. } => {
1180                let values = values.as_ref().ok_or_else(|| LustError::RuntimeError {
1181                    message: format!(
1182                        "Enum variant '{}.{}' carries no payload",
1183                        self.type_name, self.variant
1184                    ),
1185                })?;
1186                let stored = values
1187                    .get(index)
1188                    .cloned()
1189                    .ok_or_else(|| LustError::RuntimeError {
1190                        message: format!(
1191                            "Enum variant '{}.{}' payload index {} is out of bounds",
1192                            self.type_name, self.variant, index
1193                        ),
1194                    })?;
1195                T::from_value(stored)
1196            }
1197
1198            _ => Err(LustError::RuntimeError {
1199                message: "EnumInstance does not contain an enum value".to_string(),
1200            }),
1201        }
1202    }
1203
1204    pub fn as_value(&self) -> &Value {
1205        &self.value
1206    }
1207}
1208
1209pub trait IntoTypedValue {
1210    fn into_typed_value(self) -> TypedValue;
1211}
1212
1213impl IntoTypedValue for Value {
1214    fn into_typed_value(self) -> TypedValue {
1215        TypedValue::new(self, |_value, _ty| true, "Value")
1216    }
1217}
1218
1219impl IntoTypedValue for StructInstance {
1220    fn into_typed_value(self) -> TypedValue {
1221        let StructInstance {
1222            type_name: _,
1223            value,
1224        } = self;
1225        TypedValue::new(value, |v, ty| matches_lust_struct(v, ty), "struct")
1226    }
1227}
1228
1229impl IntoTypedValue for EnumInstance {
1230    fn into_typed_value(self) -> TypedValue {
1231        let EnumInstance {
1232            type_name: _,
1233            variant: _,
1234            value,
1235        } = self;
1236        TypedValue::new(value, |v, ty| matches_lust_enum(v, ty), "enum")
1237    }
1238}
1239
1240macro_rules! impl_into_typed_for_primitive {
1241    ($ty:ty, $desc:expr, $matcher:expr) => {
1242        impl IntoTypedValue for $ty {
1243            fn into_typed_value(self) -> TypedValue {
1244                let value = self.into_value();
1245                TypedValue::new(value, $matcher, $desc)
1246            }
1247        }
1248    };
1249}
1250
1251impl_into_typed_for_primitive!(LustInt, "int", |_, ty: &Type| match &ty.kind {
1252    TypeKind::Int | TypeKind::Unknown => true,
1253    TypeKind::Union(types) => types
1254        .iter()
1255        .any(|alt| matches!(&alt.kind, TypeKind::Int | TypeKind::Unknown)),
1256    _ => false,
1257});
1258impl_into_typed_for_primitive!(LustFloat, "float", |_, ty: &Type| match &ty.kind {
1259    TypeKind::Float | TypeKind::Unknown => true,
1260    TypeKind::Union(types) => types
1261        .iter()
1262        .any(|alt| matches!(&alt.kind, TypeKind::Float | TypeKind::Unknown)),
1263    _ => false,
1264});
1265impl_into_typed_for_primitive!(bool, "bool", |_, ty: &Type| match &ty.kind {
1266    TypeKind::Bool | TypeKind::Unknown => true,
1267    TypeKind::Union(types) => types
1268        .iter()
1269        .any(|alt| matches!(&alt.kind, TypeKind::Bool | TypeKind::Unknown)),
1270    _ => false,
1271});
1272impl IntoTypedValue for String {
1273    fn into_typed_value(self) -> TypedValue {
1274        let value = self.into_value();
1275        TypedValue::new(value, string_matcher, "string")
1276    }
1277}
1278
1279impl<'a> IntoTypedValue for &'a str {
1280    fn into_typed_value(self) -> TypedValue {
1281        let value = self.into_value();
1282        TypedValue::new(value, string_matcher, "string")
1283    }
1284}
1285
1286impl<'a> IntoTypedValue for &'a String {
1287    fn into_typed_value(self) -> TypedValue {
1288        let value = self.into_value();
1289        TypedValue::new(value, string_matcher, "string")
1290    }
1291}
1292
1293impl IntoTypedValue for () {
1294    fn into_typed_value(self) -> TypedValue {
1295        TypedValue::new(
1296            Value::Nil,
1297            |_, ty| matches!(ty.kind, TypeKind::Unit | TypeKind::Unknown),
1298            "unit",
1299        )
1300    }
1301}
1302
1303impl<T> IntoTypedValue for Vec<T>
1304where
1305    T: IntoLustValue,
1306{
1307    fn into_typed_value(self) -> TypedValue {
1308        let values = self.into_iter().map(|item| item.into_value()).collect();
1309        TypedValue::new(
1310            Value::array(values),
1311            |_, ty| matches_array_type(ty, &T::matches_lust_type),
1312            "array",
1313        )
1314    }
1315}
1316
1317fn string_matcher(_: &Value, ty: &Type) -> bool {
1318    match &ty.kind {
1319        TypeKind::String | TypeKind::Unknown => true,
1320        TypeKind::Union(types) => types
1321            .iter()
1322            .any(|alt| matches!(&alt.kind, TypeKind::String | TypeKind::Unknown)),
1323        _ => false,
1324    }
1325}
1326
1327#[cfg(test)]
1328mod tests {
1329    use super::*;
1330    use std::future::Future;
1331    use std::pin::Pin;
1332    use std::sync::{Arc, Mutex};
1333    use std::task::{Context, Poll, Waker};
1334
1335    #[derive(Default)]
1336    struct ManualAsyncState {
1337        result: Mutex<Option<std::result::Result<LustInt, String>>>,
1338        waker: Mutex<Option<Waker>>,
1339    }
1340
1341    impl ManualAsyncState {
1342        fn new() -> Arc<Self> {
1343            Arc::new(Self::default())
1344        }
1345
1346        fn future(self: &Arc<Self>) -> ManualFuture {
1347            ManualFuture {
1348                state: Arc::clone(self),
1349            }
1350        }
1351
1352        fn complete_ok(&self, value: LustInt) {
1353            self.complete(Ok(value));
1354        }
1355
1356        fn complete_err(&self, message: impl Into<String>) {
1357            self.complete(Err(message.into()));
1358        }
1359
1360        fn complete(&self, value: std::result::Result<LustInt, String>) {
1361            {
1362                let mut slot = self.result.lock().unwrap();
1363                *slot = Some(value);
1364            }
1365
1366            if let Some(waker) = self.waker.lock().unwrap().take() {
1367                waker.wake();
1368            }
1369        }
1370    }
1371
1372    struct ManualFuture {
1373        state: Arc<ManualAsyncState>,
1374    }
1375
1376    impl Future for ManualFuture {
1377        type Output = std::result::Result<LustInt, String>;
1378
1379        fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1380            {
1381                let mut slot = self.state.result.lock().unwrap();
1382                if let Some(result) = slot.take() {
1383                    return Poll::Ready(result);
1384                }
1385            }
1386
1387            let mut waker_slot = self.state.waker.lock().unwrap();
1388            *waker_slot = Some(cx.waker().clone());
1389            Poll::Pending
1390        }
1391    }
1392
1393    fn build_program(source: &str) -> EmbeddedProgram {
1394        EmbeddedProgram::builder()
1395            .module("main", source)
1396            .entry_module("main")
1397            .compile()
1398            .expect("compile embedded program")
1399    }
1400
1401    #[test]
1402    fn struct_instance_supports_mixed_field_types() {
1403        let source = r#"
1404            struct Mixed
1405                count: int
1406                label: string
1407                enabled: bool
1408            end
1409        "#;
1410
1411        let program = build_program(source);
1412        let mixed = program
1413            .struct_instance(
1414                "main.Mixed",
1415                [
1416                    struct_field("count", 7_i64),
1417                    struct_field("label", "hi"),
1418                    struct_field("enabled", true),
1419                ],
1420            )
1421            .expect("struct instance");
1422
1423        assert_eq!(mixed.field::<i64>("count").expect("count field"), 7);
1424        assert_eq!(mixed.field::<String>("label").expect("label field"), "hi");
1425        assert!(mixed.field::<bool>("enabled").expect("enabled field"));
1426    }
1427
1428    #[test]
1429    fn struct_instance_allows_setting_fields() {
1430        let source = r#"
1431            struct Mixed
1432                count: int
1433                label: string
1434                enabled: bool
1435            end
1436        "#;
1437
1438        let program = build_program(source);
1439        let mixed = program
1440            .struct_instance(
1441                "main.Mixed",
1442                [
1443                    struct_field("count", 1_i64),
1444                    struct_field("label", "start"),
1445                    struct_field("enabled", false),
1446                ],
1447            )
1448            .expect("struct instance");
1449
1450        mixed
1451            .set_field("count", 11_i64)
1452            .expect("update count field");
1453        assert_eq!(mixed.field::<i64>("count").expect("count field"), 11);
1454
1455        let err = mixed
1456            .set_field("count", "oops")
1457            .expect_err("type mismatch should fail");
1458        match err {
1459            LustError::TypeError { message } => {
1460                assert!(message.contains("count"));
1461                assert!(message.contains("int"));
1462            }
1463            other => panic!("unexpected error: {other:?}"),
1464        }
1465        assert_eq!(mixed.field::<i64>("count").expect("count field"), 11);
1466
1467        mixed
1468            .set_field("label", String::from("updated"))
1469            .expect("update label");
1470        assert_eq!(
1471            mixed.field::<String>("label").expect("label field"),
1472            "updated"
1473        );
1474
1475        mixed.set_field("enabled", true).expect("update enabled");
1476        assert!(mixed.field::<bool>("enabled").expect("enabled field"));
1477    }
1478
1479    #[test]
1480    fn struct_instance_accepts_nested_structs() {
1481        let source = r#"
1482            struct Child
1483                value: int
1484            end
1485
1486            struct Parent
1487                child: main.Child
1488            end
1489        "#;
1490
1491        let program = build_program(source);
1492        let child = program
1493            .struct_instance("main.Child", [struct_field("value", 42_i64)])
1494            .expect("child struct");
1495        let parent = program
1496            .struct_instance("main.Parent", [struct_field("child", child.clone())])
1497            .expect("parent struct");
1498
1499        let nested: StructInstance = parent.field("child").expect("child field");
1500        assert_eq!(nested.field::<i64>("value").expect("value field"), 42);
1501    }
1502
1503    #[test]
1504    fn globals_snapshot_exposes_lust_values() {
1505        let source = r#"
1506            struct Child
1507                value: int
1508            end
1509
1510            struct Parent
1511                child: unknown
1512            end
1513
1514            function make_parent(): Parent
1515                return Parent { child = Child { value = 3 } }
1516            end
1517        "#;
1518
1519        let mut program = build_program(source);
1520        program.run_entry_script().expect("run entry script");
1521        let parent: StructInstance = program
1522            .call_typed("main.make_parent", ())
1523            .expect("call make_parent");
1524        program.set_global_value("main.some_nested_structure", parent.clone());
1525
1526        let globals = program.globals();
1527        let (_, value) = globals
1528            .into_iter()
1529            .find(|(name, _)| name.ends_with("some_nested_structure"))
1530            .expect("global binding present");
1531        let stored = StructInstance::from_value(value).expect("convert to struct");
1532        let child_value = stored
1533            .field::<StructInstance>("child")
1534            .expect("nested child");
1535        assert_eq!(child_value.field::<i64>("value").expect("child value"), 3);
1536    }
1537
1538    #[test]
1539    fn update_field_modifies_value_in_place() {
1540        let source = r#"
1541            struct Counter
1542                value: int
1543            end
1544        "#;
1545
1546        let program = build_program(source);
1547        let counter = program
1548            .struct_instance("main.Counter", [struct_field("value", 10_i64)])
1549            .expect("counter struct");
1550
1551        counter
1552            .update_field("value", |current| match current {
1553                Value::Int(v) => Ok(v + 5),
1554                other => Err(LustError::RuntimeError {
1555                    message: format!("unexpected value {other:?}"),
1556                }),
1557            })
1558            .expect("update in place");
1559        assert_eq!(counter.field::<i64>("value").expect("value field"), 15);
1560
1561        let err = counter
1562            .update_field("value", |_| Ok(String::from("oops")))
1563            .expect_err("string should fail type check");
1564        match err {
1565            LustError::TypeError { message } => {
1566                assert!(message.contains("value"));
1567                assert!(message.contains("int"));
1568            }
1569            other => panic!("unexpected error: {other:?}"),
1570        }
1571        assert_eq!(counter.field::<i64>("value").expect("value field"), 15);
1572
1573        let err = counter
1574            .update_field("value", |_| -> Result<i64> {
1575                Err(LustError::RuntimeError {
1576                    message: "closure failure".to_string(),
1577                })
1578            })
1579            .expect_err("closure error should propagate");
1580        match err {
1581            LustError::RuntimeError { message } => assert_eq!(message, "closure failure"),
1582            other => panic!("unexpected error: {other:?}"),
1583        }
1584        assert_eq!(counter.field::<i64>("value").expect("value field"), 15);
1585    }
1586
1587    #[test]
1588    fn async_native_resumes_task_on_completion() {
1589        let source = r#"
1590            extern {
1591                function fetch_value(): int
1592            }
1593
1594            function compute(): int
1595                return fetch_value()
1596            end
1597        "#;
1598
1599        let mut program = build_program(source);
1600
1601        let state = ManualAsyncState::new();
1602        let register_state = Arc::clone(&state);
1603        program
1604            .register_async_typed_native::<(), LustInt, _, _>("fetch_value", move |_| {
1605                register_state.future()
1606            })
1607            .expect("register async native");
1608
1609        let handle = {
1610            let vm = program.vm_mut();
1611            let compute_fn = vm.function_value("main.compute").expect("compute function");
1612            vm.spawn_task_value(compute_fn, Vec::new())
1613                .expect("spawn task")
1614        };
1615
1616        assert!(program.has_pending_async_tasks());
1617        program.poll_async_tasks().expect("initial poll");
1618        assert!(program.has_pending_async_tasks());
1619
1620        state.complete_ok(123);
1621        program.poll_async_tasks().expect("resume after completion");
1622
1623        {
1624            let vm = program.vm_mut();
1625            let task = vm.get_task_instance(handle).expect("task exists");
1626            let result = task
1627                .last_result
1628                .as_ref()
1629                .and_then(|value| value.as_int())
1630                .expect("task produced result");
1631            assert_eq!(result, 123);
1632            assert!(task.error.is_none());
1633        }
1634
1635        assert!(!program.has_pending_async_tasks());
1636    }
1637
1638    #[test]
1639    fn async_native_failure_marks_task_failed() {
1640        let source = r#"
1641            extern {
1642                function fetch_value(): int
1643            }
1644
1645            function compute(): int
1646                return fetch_value()
1647            end
1648        "#;
1649
1650        let mut program = build_program(source);
1651
1652        let state = ManualAsyncState::new();
1653        let register_state = Arc::clone(&state);
1654        program
1655            .register_async_typed_native::<(), LustInt, _, _>("fetch_value", move |_| {
1656                register_state.future()
1657            })
1658            .expect("register async native");
1659
1660        let handle = {
1661            let vm = program.vm_mut();
1662            let compute_fn = vm.function_value("main.compute").expect("compute function");
1663            vm.spawn_task_value(compute_fn, Vec::new())
1664                .expect("spawn task")
1665        };
1666
1667        program.poll_async_tasks().expect("initial poll");
1668        state.complete_err("boom");
1669        let err = program
1670            .poll_async_tasks()
1671            .expect_err("poll should propagate failure");
1672        match err {
1673            LustError::RuntimeError { message } => assert_eq!(message, "boom"),
1674            other => panic!("unexpected error: {other:?}"),
1675        }
1676
1677        {
1678            let vm = program.vm_mut();
1679            let task = vm.get_task_instance(handle).expect("task exists");
1680            assert!(task.last_result.is_none());
1681            let error_message = task
1682                .error
1683                .as_ref()
1684                .map(|e| e.to_string())
1685                .expect("task should record error");
1686            assert!(error_message.contains("boom"));
1687        }
1688
1689        assert!(!program.has_pending_async_tasks());
1690    }
1691}
1692
1693fn matches_lust_struct(value: &Value, ty: &Type) -> bool {
1694    match (value, &ty.kind) {
1695        (Value::Struct { name, .. }, TypeKind::Named(expected)) => {
1696            lust_type_names_match(name, expected)
1697        }
1698        (Value::Struct { name, .. }, TypeKind::GenericInstance { name: expected, .. }) => {
1699            lust_type_names_match(name, expected)
1700        }
1701
1702        (value, TypeKind::Union(types)) => types.iter().any(|alt| matches_lust_struct(value, alt)),
1703        (_, TypeKind::Unknown) => true,
1704        _ => false,
1705    }
1706}
1707
1708fn matches_lust_enum(value: &Value, ty: &Type) -> bool {
1709    match (value, &ty.kind) {
1710        (Value::Enum { enum_name, .. }, TypeKind::Named(expected)) => {
1711            lust_type_names_match(enum_name, expected)
1712        }
1713        (Value::Enum { enum_name, .. }, TypeKind::GenericInstance { name: expected, .. }) => {
1714            lust_type_names_match(enum_name, expected)
1715        }
1716
1717        (value, TypeKind::Union(types)) => types.iter().any(|alt| matches_lust_enum(value, alt)),
1718        (_, TypeKind::Unknown) => true,
1719        _ => false,
1720    }
1721}
1722
1723fn lust_type_names_match(value: &str, expected: &str) -> bool {
1724    if value == expected {
1725        return true;
1726    }
1727
1728    let normalized_value = normalize_global_name(value);
1729    let normalized_expected = normalize_global_name(expected);
1730    if normalized_value == normalized_expected {
1731        return true;
1732    }
1733
1734    simple_type_name(&normalized_value) == simple_type_name(&normalized_expected)
1735}
1736
1737fn simple_type_name(name: &str) -> &str {
1738    name.rsplit(|c| c == '.' || c == ':').next().unwrap_or(name)
1739}
1740
1741fn matches_array_type<F>(ty: &Type, matcher: &F) -> bool
1742where
1743    F: Fn(&Type) -> bool,
1744{
1745    match &ty.kind {
1746        TypeKind::Array(inner) => matcher(inner),
1747        TypeKind::Unknown => true,
1748        TypeKind::Union(types) => types.iter().any(|alt| matches_array_type(alt, matcher)),
1749        _ => false,
1750    }
1751}
1752
1753pub trait FromLustArgs: Sized {
1754    fn from_values(values: &[Value]) -> std::result::Result<Self, String>;
1755    fn matches_signature(params: &[Type]) -> bool;
1756}
1757
1758macro_rules! impl_from_lust_args_tuple {
1759    ($( $name:ident ),+) => {
1760        impl<$($name),+> FromLustArgs for ($($name,)+)
1761        where
1762            $($name: FromLustValue,)+
1763        {
1764            fn from_values(values: &[Value]) -> std::result::Result<Self, String> {
1765                let expected = count_idents!($($name),+);
1766                if values.len() != expected {
1767                    return Err(format!(
1768                        "Native function expected {} argument(s) but received {}",
1769                        expected,
1770                        values.len()
1771                    ));
1772                }
1773
1774                let mut idx = 0;
1775                let result = (
1776                    $(
1777                        {
1778                            let value = $name::from_value(values[idx].clone()).map_err(|e| e.to_string())?;
1779                            idx += 1;
1780                            value
1781                        },
1782                    )+
1783                );
1784                let _ = idx;
1785                Ok(result)
1786            }
1787
1788            fn matches_signature(params: &[Type]) -> bool {
1789                let expected = count_idents!($($name),+);
1790                params.len() == expected && {
1791                    let mut idx = 0;
1792                    let mut ok = true;
1793                    $(
1794                        if ok && !$name::matches_lust_type(&params[idx]) {
1795                            ok = false;
1796                        }
1797
1798                        idx += 1;
1799                    )+
1800                    let _ = idx;
1801                    ok
1802                }
1803
1804            }
1805
1806        }
1807
1808    };
1809}
1810
1811macro_rules! count_idents {
1812    ($($name:ident),*) => {
1813        <[()]>::len(&[$(count_idents!(@sub $name)),*])
1814    };
1815    (@sub $name:ident) => { () };
1816}
1817
1818impl_from_lust_args_tuple!(A);
1819impl_from_lust_args_tuple!(A, B);
1820impl_from_lust_args_tuple!(A, B, C);
1821impl_from_lust_args_tuple!(A, B, C, D);
1822impl_from_lust_args_tuple!(A, B, C, D, E);
1823impl<T> FromLustArgs for T
1824where
1825    T: FromLustValue,
1826{
1827    fn from_values(values: &[Value]) -> std::result::Result<Self, String> {
1828        match values.len() {
1829            0 => T::from_value(Value::Nil).map_err(|e| e.to_string()),
1830            1 => T::from_value(values[0].clone()).map_err(|e| e.to_string()),
1831            count => Err(format!(
1832                "Native function expected 1 argument but received {}",
1833                count
1834            )),
1835        }
1836    }
1837
1838    fn matches_signature(params: &[Type]) -> bool {
1839        if params.is_empty() {
1840            let unit = Type::new(TypeKind::Unit, Span::new(0, 0, 0, 0));
1841            return T::matches_lust_type(&unit);
1842        }
1843
1844        params.len() == 1 && T::matches_lust_type(&params[0])
1845    }
1846}
1847
1848pub trait IntoLustValue: Sized {
1849    fn into_value(self) -> Value;
1850    fn matches_lust_type(ty: &Type) -> bool;
1851    fn type_description() -> &'static str;
1852}
1853
1854pub trait FromLustValue: Sized {
1855    fn from_value(value: Value) -> Result<Self>;
1856    fn matches_lust_type(ty: &Type) -> bool;
1857    fn type_description() -> &'static str;
1858}
1859
1860pub trait FunctionArgs {
1861    fn into_values(self) -> Vec<Value>;
1862    fn validate_signature(function_name: &str, params: &[Type]) -> Result<()>;
1863}
1864
1865impl IntoLustValue for Value {
1866    fn into_value(self) -> Value {
1867        self
1868    }
1869
1870    fn matches_lust_type(_: &Type) -> bool {
1871        true
1872    }
1873
1874    fn type_description() -> &'static str {
1875        "Value"
1876    }
1877}
1878
1879impl FromLustValue for Value {
1880    fn from_value(value: Value) -> Result<Self> {
1881        Ok(value)
1882    }
1883
1884    fn matches_lust_type(_: &Type) -> bool {
1885        true
1886    }
1887
1888    fn type_description() -> &'static str {
1889        "Value"
1890    }
1891}
1892
1893impl IntoLustValue for LustInt {
1894    fn into_value(self) -> Value {
1895        Value::Int(self)
1896    }
1897
1898    fn matches_lust_type(ty: &Type) -> bool {
1899        matches!(ty.kind, TypeKind::Int | TypeKind::Unknown)
1900    }
1901
1902    fn type_description() -> &'static str {
1903        "int"
1904    }
1905}
1906
1907impl FromLustValue for LustInt {
1908    fn from_value(value: Value) -> Result<Self> {
1909        match value {
1910            Value::Int(v) => Ok(v),
1911            other => Err(LustError::RuntimeError {
1912                message: format!("Expected Lust value 'int' but received '{:?}'", other),
1913            }),
1914        }
1915    }
1916
1917    fn matches_lust_type(ty: &Type) -> bool {
1918        matches!(ty.kind, TypeKind::Int | TypeKind::Unknown)
1919    }
1920
1921    fn type_description() -> &'static str {
1922        "int"
1923    }
1924}
1925
1926impl IntoLustValue for LustFloat {
1927    fn into_value(self) -> Value {
1928        Value::Float(self)
1929    }
1930
1931    fn matches_lust_type(ty: &Type) -> bool {
1932        matches!(ty.kind, TypeKind::Float | TypeKind::Unknown)
1933    }
1934
1935    fn type_description() -> &'static str {
1936        "float"
1937    }
1938}
1939
1940impl FromLustValue for LustFloat {
1941    fn from_value(value: Value) -> Result<Self> {
1942        match value {
1943            Value::Float(v) => Ok(v),
1944            other => Err(LustError::RuntimeError {
1945                message: format!("Expected Lust value 'float' but received '{:?}'", other),
1946            }),
1947        }
1948    }
1949
1950    fn matches_lust_type(ty: &Type) -> bool {
1951        matches!(ty.kind, TypeKind::Float | TypeKind::Unknown)
1952    }
1953
1954    fn type_description() -> &'static str {
1955        "float"
1956    }
1957}
1958
1959impl IntoLustValue for bool {
1960    fn into_value(self) -> Value {
1961        Value::Bool(self)
1962    }
1963
1964    fn matches_lust_type(ty: &Type) -> bool {
1965        matches!(ty.kind, TypeKind::Bool | TypeKind::Unknown)
1966    }
1967
1968    fn type_description() -> &'static str {
1969        "bool"
1970    }
1971}
1972
1973impl FromLustValue for bool {
1974    fn from_value(value: Value) -> Result<Self> {
1975        match value {
1976            Value::Bool(b) => Ok(b),
1977            other => Err(LustError::RuntimeError {
1978                message: format!("Expected Lust value 'bool' but received '{:?}'", other),
1979            }),
1980        }
1981    }
1982
1983    fn matches_lust_type(ty: &Type) -> bool {
1984        matches!(ty.kind, TypeKind::Bool | TypeKind::Unknown)
1985    }
1986
1987    fn type_description() -> &'static str {
1988        "bool"
1989    }
1990}
1991
1992impl IntoLustValue for String {
1993    fn into_value(self) -> Value {
1994        Value::String(Rc::new(self))
1995    }
1996
1997    fn matches_lust_type(ty: &Type) -> bool {
1998        matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
1999    }
2000
2001    fn type_description() -> &'static str {
2002        "string"
2003    }
2004}
2005
2006impl IntoLustValue for StructInstance {
2007    fn into_value(self) -> Value {
2008        self.value
2009    }
2010
2011    fn matches_lust_type(ty: &Type) -> bool {
2012        match &ty.kind {
2013            TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
2014            TypeKind::Union(types) => types
2015                .iter()
2016                .any(|alt| <Self as IntoLustValue>::matches_lust_type(alt)),
2017            _ => false,
2018        }
2019    }
2020
2021    fn type_description() -> &'static str {
2022        "struct"
2023    }
2024}
2025
2026impl FromLustValue for StructInstance {
2027    fn from_value(value: Value) -> Result<Self> {
2028        match &value {
2029            Value::Struct { name, .. } => Ok(StructInstance {
2030                type_name: name.clone(),
2031                value,
2032            }),
2033            other => Err(LustError::RuntimeError {
2034                message: format!("Expected Lust value 'struct' but received '{:?}'", other),
2035            }),
2036        }
2037    }
2038
2039    fn matches_lust_type(ty: &Type) -> bool {
2040        match &ty.kind {
2041            TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
2042            TypeKind::Union(types) => types
2043                .iter()
2044                .any(|alt| <Self as FromLustValue>::matches_lust_type(alt)),
2045            _ => false,
2046        }
2047    }
2048
2049    fn type_description() -> &'static str {
2050        "struct"
2051    }
2052}
2053
2054impl IntoLustValue for EnumInstance {
2055    fn into_value(self) -> Value {
2056        self.value
2057    }
2058
2059    fn matches_lust_type(ty: &Type) -> bool {
2060        match &ty.kind {
2061            TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
2062            TypeKind::Union(types) => types
2063                .iter()
2064                .any(|alt| <Self as IntoLustValue>::matches_lust_type(alt)),
2065            _ => false,
2066        }
2067    }
2068
2069    fn type_description() -> &'static str {
2070        "enum"
2071    }
2072}
2073
2074impl FromLustValue for EnumInstance {
2075    fn from_value(value: Value) -> Result<Self> {
2076        match &value {
2077            Value::Enum {
2078                enum_name, variant, ..
2079            } => Ok(EnumInstance {
2080                type_name: enum_name.clone(),
2081                variant: variant.clone(),
2082                value,
2083            }),
2084            other => Err(LustError::RuntimeError {
2085                message: format!("Expected Lust value 'enum' but received '{:?}'", other),
2086            }),
2087        }
2088    }
2089
2090    fn matches_lust_type(ty: &Type) -> bool {
2091        match &ty.kind {
2092            TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
2093            TypeKind::Union(types) => types
2094                .iter()
2095                .any(|alt| <Self as FromLustValue>::matches_lust_type(alt)),
2096            _ => false,
2097        }
2098    }
2099
2100    fn type_description() -> &'static str {
2101        "enum"
2102    }
2103}
2104
2105impl<T> IntoLustValue for Vec<T>
2106where
2107    T: IntoLustValue,
2108{
2109    fn into_value(self) -> Value {
2110        let values = self.into_iter().map(|item| item.into_value()).collect();
2111        Value::array(values)
2112    }
2113
2114    fn matches_lust_type(ty: &Type) -> bool {
2115        matches_array_type(ty, &T::matches_lust_type)
2116    }
2117
2118    fn type_description() -> &'static str {
2119        "array"
2120    }
2121}
2122
2123impl<T> FromLustValue for Vec<T>
2124where
2125    T: FromLustValue,
2126{
2127    fn from_value(value: Value) -> Result<Self> {
2128        match value {
2129            Value::Array(items) => {
2130                let borrowed = items.borrow();
2131                let mut result = Vec::with_capacity(borrowed.len());
2132                for item in borrowed.iter() {
2133                    result.push(T::from_value(item.clone())?);
2134                }
2135
2136                Ok(result)
2137            }
2138
2139            other => Err(LustError::RuntimeError {
2140                message: format!("Expected Lust value 'array' but received '{:?}'", other),
2141            }),
2142        }
2143    }
2144
2145    fn matches_lust_type(ty: &Type) -> bool {
2146        matches_array_type(ty, &T::matches_lust_type)
2147    }
2148
2149    fn type_description() -> &'static str {
2150        "array"
2151    }
2152}
2153
2154impl<'a> IntoLustValue for &'a str {
2155    fn into_value(self) -> Value {
2156        Value::String(Rc::new(self.to_owned()))
2157    }
2158
2159    fn matches_lust_type(ty: &Type) -> bool {
2160        matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
2161    }
2162
2163    fn type_description() -> &'static str {
2164        "string"
2165    }
2166}
2167
2168impl<'a> IntoLustValue for &'a String {
2169    fn into_value(self) -> Value {
2170        Value::String(Rc::new(self.clone()))
2171    }
2172
2173    fn matches_lust_type(ty: &Type) -> bool {
2174        matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
2175    }
2176
2177    fn type_description() -> &'static str {
2178        "string"
2179    }
2180}
2181
2182impl FromLustValue for String {
2183    fn from_value(value: Value) -> Result<Self> {
2184        match value {
2185            Value::String(s) => Ok((*s).clone()),
2186            other => Err(LustError::RuntimeError {
2187                message: format!("Expected Lust value 'string' but received '{:?}'", other),
2188            }),
2189        }
2190    }
2191
2192    fn matches_lust_type(ty: &Type) -> bool {
2193        matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
2194    }
2195
2196    fn type_description() -> &'static str {
2197        "string"
2198    }
2199}
2200
2201impl FromLustValue for () {
2202    fn from_value(value: Value) -> Result<Self> {
2203        match value {
2204            Value::Nil => Ok(()),
2205            other => Err(LustError::RuntimeError {
2206                message: format!("Expected Lust value 'unit' but received '{:?}'", other),
2207            }),
2208        }
2209    }
2210
2211    fn matches_lust_type(ty: &Type) -> bool {
2212        matches!(ty.kind, TypeKind::Unit | TypeKind::Unknown)
2213    }
2214
2215    fn type_description() -> &'static str {
2216        "unit"
2217    }
2218}
2219
2220impl FunctionArgs for () {
2221    fn into_values(self) -> Vec<Value> {
2222        Vec::new()
2223    }
2224
2225    fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
2226        ensure_arity(function_name, params, 0)
2227    }
2228}
2229
2230impl<T> FunctionArgs for T
2231where
2232    T: IntoLustValue,
2233{
2234    fn into_values(self) -> Vec<Value> {
2235        vec![self.into_value()]
2236    }
2237
2238    fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
2239        ensure_arity(function_name, params, 1)?;
2240        ensure_arg_type::<T>(function_name, params, 0)
2241    }
2242}
2243
2244impl<A, B> FunctionArgs for (A, B)
2245where
2246    A: IntoLustValue,
2247    B: IntoLustValue,
2248{
2249    fn into_values(self) -> Vec<Value> {
2250        vec![self.0.into_value(), self.1.into_value()]
2251    }
2252
2253    fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
2254        ensure_arity(function_name, params, 2)?;
2255        ensure_arg_type::<A>(function_name, params, 0)?;
2256        ensure_arg_type::<B>(function_name, params, 1)?;
2257        Ok(())
2258    }
2259}
2260
2261impl<A, B, C> FunctionArgs for (A, B, C)
2262where
2263    A: IntoLustValue,
2264    B: IntoLustValue,
2265    C: IntoLustValue,
2266{
2267    fn into_values(self) -> Vec<Value> {
2268        vec![
2269            self.0.into_value(),
2270            self.1.into_value(),
2271            self.2.into_value(),
2272        ]
2273    }
2274
2275    fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
2276        ensure_arity(function_name, params, 3)?;
2277        ensure_arg_type::<A>(function_name, params, 0)?;
2278        ensure_arg_type::<B>(function_name, params, 1)?;
2279        ensure_arg_type::<C>(function_name, params, 2)?;
2280        Ok(())
2281    }
2282}
2283
2284impl<A, B, C, D> FunctionArgs for (A, B, C, D)
2285where
2286    A: IntoLustValue,
2287    B: IntoLustValue,
2288    C: IntoLustValue,
2289    D: IntoLustValue,
2290{
2291    fn into_values(self) -> Vec<Value> {
2292        vec![
2293            self.0.into_value(),
2294            self.1.into_value(),
2295            self.2.into_value(),
2296            self.3.into_value(),
2297        ]
2298    }
2299
2300    fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
2301        ensure_arity(function_name, params, 4)?;
2302        ensure_arg_type::<A>(function_name, params, 0)?;
2303        ensure_arg_type::<B>(function_name, params, 1)?;
2304        ensure_arg_type::<C>(function_name, params, 2)?;
2305        ensure_arg_type::<D>(function_name, params, 3)?;
2306        Ok(())
2307    }
2308}
2309
2310impl<A, B, C, D, E> FunctionArgs for (A, B, C, D, E)
2311where
2312    A: IntoLustValue,
2313    B: IntoLustValue,
2314    C: IntoLustValue,
2315    D: IntoLustValue,
2316    E: IntoLustValue,
2317{
2318    fn into_values(self) -> Vec<Value> {
2319        vec![
2320            self.0.into_value(),
2321            self.1.into_value(),
2322            self.2.into_value(),
2323            self.3.into_value(),
2324            self.4.into_value(),
2325        ]
2326    }
2327
2328    fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
2329        ensure_arity(function_name, params, 5)?;
2330        ensure_arg_type::<A>(function_name, params, 0)?;
2331        ensure_arg_type::<B>(function_name, params, 1)?;
2332        ensure_arg_type::<C>(function_name, params, 2)?;
2333        ensure_arg_type::<D>(function_name, params, 3)?;
2334        ensure_arg_type::<E>(function_name, params, 4)?;
2335        Ok(())
2336    }
2337}
2338
2339fn ensure_arity(function_name: &str, params: &[Type], provided: usize) -> Result<()> {
2340    if params.len() == provided {
2341        Ok(())
2342    } else {
2343        Err(LustError::TypeError {
2344            message: format!(
2345                "Function '{}' expects {} argument(s) but {} were supplied",
2346                function_name,
2347                params.len(),
2348                provided
2349            ),
2350        })
2351    }
2352}
2353
2354fn ensure_arg_type<T: IntoLustValue>(
2355    function_name: &str,
2356    params: &[Type],
2357    index: usize,
2358) -> Result<()> {
2359    if <T as IntoLustValue>::matches_lust_type(&params[index]) {
2360        Ok(())
2361    } else {
2362        Err(argument_type_mismatch(
2363            function_name,
2364            index,
2365            <T as IntoLustValue>::type_description(),
2366            &params[index],
2367        ))
2368    }
2369}
2370
2371fn argument_type_mismatch(
2372    function_name: &str,
2373    index: usize,
2374    rust_type: &str,
2375    lust_type: &Type,
2376) -> LustError {
2377    LustError::TypeError {
2378        message: format!(
2379            "Function '{}' parameter {} expects Lust type '{}' but Rust provided '{}'",
2380            function_name,
2381            index + 1,
2382            lust_type,
2383            rust_type
2384        ),
2385    }
2386}