1use crate::ast::{EnumDef, FieldOwnership, Item, ItemKind, Span, StructDef, Type, TypeKind};
2use crate::bytecode::{Compiler, FieldStorage, NativeCallResult, TaskHandle, Value, ValueKey};
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::{Ref, RefCell, RefMut};
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 option_coercions = typechecker.take_option_coercions();
823 let struct_defs = typechecker.struct_definitions();
824 let enum_defs = typechecker.enum_definitions();
825 let mut signatures = typechecker.function_signatures();
826 let mut compiler = Compiler::new();
827 compiler.set_option_coercions(option_coercions);
828 compiler.configure_stdlib(&config);
829 compiler.set_imports_by_module(imports_map);
830 compiler.set_entry_module(program.entry_module.clone());
831 let functions = compiler.compile_module(&wrapped_items)?;
832 let trait_impls = compiler.get_trait_impls().to_vec();
833 let mut init_funcs = Vec::new();
834 for module in &program.modules {
835 if module.path != program.entry_module {
836 if let Some(init) = &module.init_function {
837 init_funcs.push(init.clone());
838 }
839 }
840 }
841
842 let function_names: Vec<String> = functions.iter().map(|f| f.name.clone()).collect();
843 let entry_script = function_names
844 .iter()
845 .find(|name| name.as_str() == "__script")
846 .cloned();
847 if let Some(script_name) = &entry_script {
848 signatures
849 .entry(script_name.clone())
850 .or_insert_with(|| FunctionSignature {
851 params: Vec::new(),
852 return_type: Type::new(TypeKind::Unit, Span::new(0, 0, 0, 0)),
853 is_method: false,
854 });
855 }
856
857 let mut vm = VM::with_config(&config);
858 vm.load_functions(functions);
859 vm.register_structs(&struct_defs);
860 for (type_name, trait_name) in trait_impls {
861 vm.register_trait_impl(type_name, trait_name);
862 }
863
864 for init in init_funcs {
865 vm.call(&init, Vec::new())?;
866 }
867
868 Ok(EmbeddedProgram {
869 vm,
870 signatures,
871 struct_defs,
872 enum_defs,
873 entry_script,
874 entry_module: program.entry_module,
875 async_registry: Rc::new(RefCell::new(AsyncRegistry::new())),
876 })
877}
878
879fn module_path_to_file(base_dir: &Path, module_path: &str) -> PathBuf {
880 let mut path = base_dir.to_path_buf();
881 for segment in module_path.split('.') {
882 path.push(segment);
883 }
884
885 path.set_extension("lust");
886 path
887}
888
889fn normalize_global_name(name: &str) -> String {
890 if name.contains("::") {
891 name.to_string()
892 } else if let Some((module, identifier)) = name.rsplit_once('.') {
893 format!("{}::{}", module, identifier)
894 } else {
895 name.to_string()
896 }
897}
898
899fn ensure_return_type<R: FromLustValue>(function_name: &str, ty: &Type) -> Result<()> {
900 if matches!(ty.kind, TypeKind::Unknown) || R::matches_lust_type(ty) {
901 return Ok(());
902 }
903
904 Err(LustError::TypeError {
905 message: format!(
906 "Function '{}' reports return type '{}' which is incompatible with Rust receiver '{}'",
907 function_name,
908 ty,
909 R::type_description()
910 ),
911 })
912}
913
914pub struct TypedValue {
915 value: Value,
916 matcher: Box<dyn Fn(&Value, &Type) -> bool>,
917 description: &'static str,
918}
919
920impl TypedValue {
921 fn new<F>(value: Value, matcher: F, description: &'static str) -> Self
922 where
923 F: Fn(&Value, &Type) -> bool + 'static,
924 {
925 Self {
926 value,
927 matcher: Box::new(matcher),
928 description,
929 }
930 }
931
932 fn matches(&self, ty: &Type) -> bool {
933 match &ty.kind {
934 TypeKind::Union(types) => types.iter().any(|alt| (self.matcher)(&self.value, alt)),
935 _ => (self.matcher)(&self.value, ty),
936 }
937 }
938
939 fn description(&self) -> &'static str {
940 self.description
941 }
942
943 fn into_value(self) -> Value {
944 self.value
945 }
946}
947
948pub struct StructField {
949 name: String,
950 value: TypedValue,
951}
952
953impl StructField {
954 pub fn new(name: impl Into<String>, value: impl IntoTypedValue) -> Self {
955 Self {
956 name: name.into(),
957 value: value.into_typed_value(),
958 }
959 }
960
961 pub fn name(&self) -> &str {
962 &self.name
963 }
964
965 fn into_parts(self) -> (String, TypedValue) {
966 (self.name, self.value)
967 }
968}
969
970pub fn struct_field(name: impl Into<String>, value: impl IntoTypedValue) -> StructField {
971 StructField::new(name, value)
972}
973
974impl<K, V> From<(K, V)> for StructField
975where
976 K: Into<String>,
977 V: IntoTypedValue,
978{
979 fn from((name, value): (K, V)) -> Self {
980 StructField::new(name, value)
981 }
982}
983
984#[derive(Clone)]
985pub struct StructInstance {
986 type_name: String,
987 value: Value,
988}
989
990impl StructInstance {
991 fn new(type_name: String, value: Value) -> Self {
992 debug_assert!(matches!(value, Value::Struct { .. }));
993 Self { type_name, value }
994 }
995
996 pub fn type_name(&self) -> &str {
997 &self.type_name
998 }
999
1000 pub fn field<T: FromLustValue>(&self, field: &str) -> Result<T> {
1001 let value_ref = self.borrow_field(field)?;
1002 T::from_value(value_ref.into_owned())
1003 }
1004
1005 pub fn borrow_field(&self, field: &str) -> Result<ValueRef<'_>> {
1006 match &self.value {
1007 Value::Struct { layout, fields, .. } => {
1008 let index = layout
1009 .index_of_str(field)
1010 .ok_or_else(|| LustError::RuntimeError {
1011 message: format!(
1012 "Struct '{}' has no field named '{}'",
1013 self.type_name, field
1014 ),
1015 })?;
1016 match layout.field_storage(index) {
1017 FieldStorage::Strong => {
1018 let slots = fields.borrow();
1019 if slots.get(index).is_none() {
1020 return Err(LustError::RuntimeError {
1021 message: format!(
1022 "Struct '{}' field '{}' is unavailable",
1023 self.type_name, field
1024 ),
1025 });
1026 }
1027
1028 Ok(ValueRef::borrowed(Ref::map(slots, move |values| {
1029 &values[index]
1030 })))
1031 }
1032
1033 FieldStorage::Weak => {
1034 let stored = {
1035 let slots = fields.borrow();
1036 slots
1037 .get(index)
1038 .cloned()
1039 .ok_or_else(|| LustError::RuntimeError {
1040 message: format!(
1041 "Struct '{}' field '{}' is unavailable",
1042 self.type_name, field
1043 ),
1044 })?
1045 };
1046 let materialized = layout.materialize_field_value(index, stored);
1047 Ok(ValueRef::owned(materialized))
1048 }
1049 }
1050 }
1051
1052 _ => Err(LustError::RuntimeError {
1053 message: "StructInstance does not contain a struct value".to_string(),
1054 }),
1055 }
1056 }
1057
1058 pub fn set_field<V: IntoTypedValue>(&self, field: &str, value: V) -> Result<()> {
1059 match &self.value {
1060 Value::Struct { layout, fields, .. } => {
1061 let index = layout
1062 .index_of_str(field)
1063 .ok_or_else(|| LustError::RuntimeError {
1064 message: format!(
1065 "Struct '{}' has no field named '{}'",
1066 self.type_name, field
1067 ),
1068 })?;
1069 let typed_value = value.into_typed_value();
1070 let matches_declared = typed_value.matches(layout.field_type(index));
1071 let matches_ref_inner = layout.is_weak(index)
1072 && layout
1073 .weak_target(index)
1074 .map(|inner| typed_value.matches(inner))
1075 .unwrap_or(false);
1076 if !(matches_declared || matches_ref_inner) {
1077 return Err(LustError::TypeError {
1078 message: format!(
1079 "Struct '{}' field '{}' expects Lust type '{}' but Rust provided '{}'",
1080 self.type_name,
1081 field,
1082 layout.field_type(index),
1083 typed_value.description()
1084 ),
1085 });
1086 }
1087
1088 let canonical_value = layout
1089 .canonicalize_field_value(index, typed_value.into_value())
1090 .map_err(|message| LustError::TypeError { message })?;
1091 fields.borrow_mut()[index] = canonical_value;
1092 Ok(())
1093 }
1094
1095 _ => Err(LustError::RuntimeError {
1096 message: "StructInstance does not contain a struct value".to_string(),
1097 }),
1098 }
1099 }
1100
1101 pub fn update_field<F, V>(&self, field: &str, update: F) -> Result<()>
1102 where
1103 F: FnOnce(Value) -> Result<V>,
1104 V: IntoTypedValue,
1105 {
1106 match &self.value {
1107 Value::Struct { layout, fields, .. } => {
1108 let index = layout
1109 .index_of_str(field)
1110 .ok_or_else(|| LustError::RuntimeError {
1111 message: format!(
1112 "Struct '{}' has no field named '{}'",
1113 self.type_name, field
1114 ),
1115 })?;
1116 let mut slots = fields.borrow_mut();
1117 let slot = slots
1118 .get_mut(index)
1119 .ok_or_else(|| LustError::RuntimeError {
1120 message: format!(
1121 "Struct '{}' field '{}' is unavailable",
1122 self.type_name, field
1123 ),
1124 })?;
1125 let fallback = slot.clone();
1126 let current_canonical = std::mem::replace(slot, Value::Nil);
1127 let current_materialized = layout.materialize_field_value(index, current_canonical);
1128 let updated = match update(current_materialized) {
1129 Ok(value) => value,
1130 Err(err) => {
1131 *slot = fallback;
1132 return Err(err);
1133 }
1134 };
1135 let typed_value = updated.into_typed_value();
1136 let matches_declared = typed_value.matches(layout.field_type(index));
1137 let matches_ref_inner = layout.is_weak(index)
1138 && layout
1139 .weak_target(index)
1140 .map(|inner| typed_value.matches(inner))
1141 .unwrap_or(false);
1142 if !(matches_declared || matches_ref_inner) {
1143 *slot = fallback;
1144 return Err(LustError::TypeError {
1145 message: format!(
1146 "Struct '{}' field '{}' expects Lust type '{}' but Rust provided '{}'",
1147 self.type_name,
1148 field,
1149 layout.field_type(index),
1150 typed_value.description()
1151 ),
1152 });
1153 }
1154
1155 let canonical_value = layout
1156 .canonicalize_field_value(index, typed_value.into_value())
1157 .map_err(|message| LustError::TypeError { message })?;
1158 *slot = canonical_value;
1159 Ok(())
1160 }
1161
1162 _ => Err(LustError::RuntimeError {
1163 message: "StructInstance does not contain a struct value".to_string(),
1164 }),
1165 }
1166 }
1167
1168 pub fn as_value(&self) -> &Value {
1169 &self.value
1170 }
1171}
1172
1173pub enum ValueRef<'a> {
1174 Borrowed(Ref<'a, Value>),
1175 Owned(Value),
1176}
1177
1178impl<'a> ValueRef<'a> {
1179 fn borrowed(inner: Ref<'a, Value>) -> Self {
1180 Self::Borrowed(inner)
1181 }
1182
1183 fn owned(value: Value) -> Self {
1184 Self::Owned(value)
1185 }
1186
1187 pub fn as_value(&self) -> &Value {
1188 match self {
1189 ValueRef::Borrowed(inner) => &*inner,
1190 ValueRef::Owned(value) => value,
1191 }
1192 }
1193
1194 pub fn to_owned(&self) -> Value {
1195 self.as_value().clone()
1196 }
1197
1198 pub fn into_owned(self) -> Value {
1199 match self {
1200 ValueRef::Borrowed(inner) => inner.clone(),
1201 ValueRef::Owned(value) => value,
1202 }
1203 }
1204
1205 pub fn as_bool(&self) -> Option<bool> {
1206 match self.as_value() {
1207 Value::Bool(value) => Some(*value),
1208 _ => None,
1209 }
1210 }
1211
1212 pub fn as_int(&self) -> Option<LustInt> {
1213 self.as_value().as_int()
1214 }
1215
1216 pub fn as_float(&self) -> Option<LustFloat> {
1217 self.as_value().as_float()
1218 }
1219
1220 pub fn as_string(&self) -> Option<&str> {
1221 self.as_value().as_string()
1222 }
1223
1224 pub fn as_rc_string(&self) -> Option<Rc<String>> {
1225 match self.as_value() {
1226 Value::String(value) => Some(value.clone()),
1227 _ => None,
1228 }
1229 }
1230
1231 pub fn as_array_handle(&self) -> Option<ArrayHandle> {
1232 match self.as_value() {
1233 Value::Array(items) => Some(ArrayHandle::from_rc(items.clone())),
1234 _ => None,
1235 }
1236 }
1237
1238 pub fn as_map_handle(&self) -> Option<MapHandle> {
1239 match self.as_value() {
1240 Value::Map(map) => Some(MapHandle::from_rc(map.clone())),
1241 _ => None,
1242 }
1243 }
1244
1245 pub fn as_table_handle(&self) -> Option<TableHandle> {
1246 match self.as_value() {
1247 Value::Table(table) => Some(TableHandle::from_rc(table.clone())),
1248 _ => None,
1249 }
1250 }
1251}
1252
1253#[derive(Clone)]
1254pub struct ArrayHandle {
1255 inner: Rc<RefCell<Vec<Value>>>,
1256}
1257
1258impl ArrayHandle {
1259 fn from_rc(inner: Rc<RefCell<Vec<Value>>>) -> Self {
1260 Self { inner }
1261 }
1262
1263 pub fn len(&self) -> usize {
1264 self.inner.borrow().len()
1265 }
1266
1267 pub fn is_empty(&self) -> bool {
1268 self.len() == 0
1269 }
1270
1271 pub fn borrow(&self) -> Ref<'_, [Value]> {
1272 Ref::map(self.inner.borrow(), |values| values.as_slice())
1273 }
1274
1275 pub fn borrow_mut(&self) -> RefMut<'_, Vec<Value>> {
1276 self.inner.borrow_mut()
1277 }
1278
1279 pub fn push(&self, value: Value) {
1280 self.inner.borrow_mut().push(value);
1281 }
1282
1283 pub fn extend<I>(&self, iter: I)
1284 where
1285 I: IntoIterator<Item = Value>,
1286 {
1287 self.inner.borrow_mut().extend(iter);
1288 }
1289
1290 pub fn get(&self, index: usize) -> Option<ValueRef<'_>> {
1291 {
1292 let values = self.inner.borrow();
1293 if values.get(index).is_none() {
1294 return None;
1295 }
1296 }
1297
1298 let values = self.inner.borrow();
1299 Some(ValueRef::borrowed(Ref::map(values, move |items| {
1300 &items[index]
1301 })))
1302 }
1303
1304 pub fn with_ref<R>(&self, f: impl FnOnce(&[Value]) -> R) -> R {
1305 let values = self.inner.borrow();
1306 f(values.as_slice())
1307 }
1308
1309 pub fn with_mut<R>(&self, f: impl FnOnce(&mut Vec<Value>) -> R) -> R {
1310 let mut values = self.inner.borrow_mut();
1311 f(&mut values)
1312 }
1313}
1314
1315#[derive(Clone)]
1316pub struct MapHandle {
1317 inner: Rc<RefCell<HashMap<ValueKey, Value>>>,
1318}
1319
1320impl MapHandle {
1321 fn from_rc(inner: Rc<RefCell<HashMap<ValueKey, Value>>>) -> Self {
1322 Self { inner }
1323 }
1324
1325 pub fn len(&self) -> usize {
1326 self.inner.borrow().len()
1327 }
1328
1329 pub fn is_empty(&self) -> bool {
1330 self.len() == 0
1331 }
1332
1333 pub fn borrow(&self) -> Ref<'_, HashMap<ValueKey, Value>> {
1334 self.inner.borrow()
1335 }
1336
1337 pub fn borrow_mut(&self) -> RefMut<'_, HashMap<ValueKey, Value>> {
1338 self.inner.borrow_mut()
1339 }
1340
1341 pub fn contains_key<K>(&self, key: K) -> bool
1342 where
1343 K: Into<ValueKey>,
1344 {
1345 self.inner.borrow().contains_key(&key.into())
1346 }
1347
1348 pub fn get<K>(&self, key: K) -> Option<ValueRef<'_>>
1349 where
1350 K: Into<ValueKey>,
1351 {
1352 let key = key.into();
1353 {
1354 if !self.inner.borrow().contains_key(&key) {
1355 return None;
1356 }
1357 }
1358 let lookup = key.clone();
1359 let map = self.inner.borrow();
1360 Some(ValueRef::borrowed(Ref::map(map, move |values| {
1361 values
1362 .get(&lookup)
1363 .expect("lookup key should be present after contains_key")
1364 })))
1365 }
1366
1367 pub fn insert<K>(&self, key: K, value: Value) -> Option<Value>
1368 where
1369 K: Into<ValueKey>,
1370 {
1371 self.inner.borrow_mut().insert(key.into(), value)
1372 }
1373
1374 pub fn remove<K>(&self, key: K) -> Option<Value>
1375 where
1376 K: Into<ValueKey>,
1377 {
1378 self.inner.borrow_mut().remove(&key.into())
1379 }
1380
1381 pub fn with_ref<R>(&self, f: impl FnOnce(&HashMap<ValueKey, Value>) -> R) -> R {
1382 let map = self.inner.borrow();
1383 f(&map)
1384 }
1385
1386 pub fn with_mut<R>(&self, f: impl FnOnce(&mut HashMap<ValueKey, Value>) -> R) -> R {
1387 let mut map = self.inner.borrow_mut();
1388 f(&mut map)
1389 }
1390}
1391
1392#[derive(Clone)]
1393pub struct TableHandle {
1394 inner: Rc<RefCell<HashMap<ValueKey, Value>>>,
1395}
1396
1397impl TableHandle {
1398 fn from_rc(inner: Rc<RefCell<HashMap<ValueKey, Value>>>) -> Self {
1399 Self { inner }
1400 }
1401
1402 pub fn len(&self) -> usize {
1403 self.inner.borrow().len()
1404 }
1405
1406 pub fn is_empty(&self) -> bool {
1407 self.len() == 0
1408 }
1409
1410 pub fn borrow(&self) -> Ref<'_, HashMap<ValueKey, Value>> {
1411 self.inner.borrow()
1412 }
1413
1414 pub fn borrow_mut(&self) -> RefMut<'_, HashMap<ValueKey, Value>> {
1415 self.inner.borrow_mut()
1416 }
1417
1418 pub fn contains_key<K>(&self, key: K) -> bool
1419 where
1420 K: Into<ValueKey>,
1421 {
1422 self.inner.borrow().contains_key(&key.into())
1423 }
1424
1425 pub fn get<K>(&self, key: K) -> Option<ValueRef<'_>>
1426 where
1427 K: Into<ValueKey>,
1428 {
1429 let key = key.into();
1430 {
1431 if !self.inner.borrow().contains_key(&key) {
1432 return None;
1433 }
1434 }
1435 let lookup = key.clone();
1436 let table = self.inner.borrow();
1437 Some(ValueRef::borrowed(Ref::map(table, move |values| {
1438 values
1439 .get(&lookup)
1440 .expect("lookup key should be present after contains_key")
1441 })))
1442 }
1443
1444 pub fn insert<K>(&self, key: K, value: Value) -> Option<Value>
1445 where
1446 K: Into<ValueKey>,
1447 {
1448 self.inner.borrow_mut().insert(key.into(), value)
1449 }
1450
1451 pub fn remove<K>(&self, key: K) -> Option<Value>
1452 where
1453 K: Into<ValueKey>,
1454 {
1455 self.inner.borrow_mut().remove(&key.into())
1456 }
1457
1458 pub fn with_ref<R>(&self, f: impl FnOnce(&HashMap<ValueKey, Value>) -> R) -> R {
1459 let table = self.inner.borrow();
1460 f(&table)
1461 }
1462
1463 pub fn with_mut<R>(&self, f: impl FnOnce(&mut HashMap<ValueKey, Value>) -> R) -> R {
1464 let mut table = self.inner.borrow_mut();
1465 f(&mut table)
1466 }
1467}
1468
1469#[derive(Clone)]
1470pub struct EnumInstance {
1471 type_name: String,
1472 variant: String,
1473 value: Value,
1474}
1475
1476impl EnumInstance {
1477 fn new(type_name: String, variant: String, value: Value) -> Self {
1478 debug_assert!(matches!(value, Value::Enum { .. }));
1479 Self {
1480 type_name,
1481 variant,
1482 value,
1483 }
1484 }
1485
1486 pub fn type_name(&self) -> &str {
1487 &self.type_name
1488 }
1489
1490 pub fn variant(&self) -> &str {
1491 &self.variant
1492 }
1493
1494 pub fn payload_len(&self) -> usize {
1495 match &self.value {
1496 Value::Enum { values, .. } => values.as_ref().map(|v| v.len()).unwrap_or(0),
1497 _ => 0,
1498 }
1499 }
1500
1501 pub fn payload<T: FromLustValue>(&self, index: usize) -> Result<T> {
1502 match &self.value {
1503 Value::Enum { values, .. } => {
1504 let values = values.as_ref().ok_or_else(|| LustError::RuntimeError {
1505 message: format!(
1506 "Enum variant '{}.{}' carries no payload",
1507 self.type_name, self.variant
1508 ),
1509 })?;
1510 let stored = values
1511 .get(index)
1512 .cloned()
1513 .ok_or_else(|| LustError::RuntimeError {
1514 message: format!(
1515 "Enum variant '{}.{}' payload index {} is out of bounds",
1516 self.type_name, self.variant, index
1517 ),
1518 })?;
1519 T::from_value(stored)
1520 }
1521
1522 _ => Err(LustError::RuntimeError {
1523 message: "EnumInstance does not contain an enum value".to_string(),
1524 }),
1525 }
1526 }
1527
1528 pub fn as_value(&self) -> &Value {
1529 &self.value
1530 }
1531}
1532
1533pub trait IntoTypedValue {
1534 fn into_typed_value(self) -> TypedValue;
1535}
1536
1537impl IntoTypedValue for Value {
1538 fn into_typed_value(self) -> TypedValue {
1539 TypedValue::new(self, |_value, _ty| true, "Value")
1540 }
1541}
1542
1543impl IntoTypedValue for StructInstance {
1544 fn into_typed_value(self) -> TypedValue {
1545 let StructInstance {
1546 type_name: _,
1547 value,
1548 } = self;
1549 TypedValue::new(value, |v, ty| matches_lust_struct(v, ty), "struct")
1550 }
1551}
1552
1553impl IntoTypedValue for EnumInstance {
1554 fn into_typed_value(self) -> TypedValue {
1555 let EnumInstance {
1556 type_name: _,
1557 variant: _,
1558 value,
1559 } = self;
1560 TypedValue::new(value, |v, ty| matches_lust_enum(v, ty), "enum")
1561 }
1562}
1563
1564macro_rules! impl_into_typed_for_primitive {
1565 ($ty:ty, $desc:expr, $matcher:expr) => {
1566 impl IntoTypedValue for $ty {
1567 fn into_typed_value(self) -> TypedValue {
1568 let value = self.into_value();
1569 TypedValue::new(value, $matcher, $desc)
1570 }
1571 }
1572 };
1573}
1574
1575impl_into_typed_for_primitive!(LustInt, "int", |_, ty: &Type| match &ty.kind {
1576 TypeKind::Int | TypeKind::Unknown => true,
1577 TypeKind::Union(types) => types
1578 .iter()
1579 .any(|alt| matches!(&alt.kind, TypeKind::Int | TypeKind::Unknown)),
1580 _ => false,
1581});
1582impl_into_typed_for_primitive!(LustFloat, "float", |_, ty: &Type| match &ty.kind {
1583 TypeKind::Float | TypeKind::Unknown => true,
1584 TypeKind::Union(types) => types
1585 .iter()
1586 .any(|alt| matches!(&alt.kind, TypeKind::Float | TypeKind::Unknown)),
1587 _ => false,
1588});
1589impl_into_typed_for_primitive!(bool, "bool", |_, ty: &Type| match &ty.kind {
1590 TypeKind::Bool | TypeKind::Unknown => true,
1591 TypeKind::Union(types) => types
1592 .iter()
1593 .any(|alt| matches!(&alt.kind, TypeKind::Bool | TypeKind::Unknown)),
1594 _ => false,
1595});
1596impl IntoTypedValue for String {
1597 fn into_typed_value(self) -> TypedValue {
1598 let value = self.into_value();
1599 TypedValue::new(value, string_matcher, "string")
1600 }
1601}
1602
1603impl<'a> IntoTypedValue for &'a str {
1604 fn into_typed_value(self) -> TypedValue {
1605 let value = self.into_value();
1606 TypedValue::new(value, string_matcher, "string")
1607 }
1608}
1609
1610impl<'a> IntoTypedValue for &'a String {
1611 fn into_typed_value(self) -> TypedValue {
1612 let value = self.into_value();
1613 TypedValue::new(value, string_matcher, "string")
1614 }
1615}
1616
1617impl IntoTypedValue for () {
1618 fn into_typed_value(self) -> TypedValue {
1619 TypedValue::new(
1620 Value::Nil,
1621 |_, ty| matches!(ty.kind, TypeKind::Unit | TypeKind::Unknown),
1622 "unit",
1623 )
1624 }
1625}
1626
1627impl<T> IntoTypedValue for Vec<T>
1628where
1629 T: IntoLustValue,
1630{
1631 fn into_typed_value(self) -> TypedValue {
1632 let values = self.into_iter().map(|item| item.into_value()).collect();
1633 TypedValue::new(
1634 Value::array(values),
1635 |_, ty| matches_array_type(ty, &T::matches_lust_type),
1636 "array",
1637 )
1638 }
1639}
1640
1641impl IntoTypedValue for ArrayHandle {
1642 fn into_typed_value(self) -> TypedValue {
1643 let value = self.into_value();
1644 TypedValue::new(value, |_, ty| matches_array_handle_type(ty), "array")
1645 }
1646}
1647
1648impl IntoTypedValue for MapHandle {
1649 fn into_typed_value(self) -> TypedValue {
1650 let value = self.into_value();
1651 TypedValue::new(value, |_, ty| matches_map_handle_type(ty), "map")
1652 }
1653}
1654
1655impl IntoTypedValue for TableHandle {
1656 fn into_typed_value(self) -> TypedValue {
1657 let value = self.into_value();
1658 TypedValue::new(value, |_, ty| matches_table_handle_type(ty), "table")
1659 }
1660}
1661
1662fn string_matcher(_: &Value, ty: &Type) -> bool {
1663 match &ty.kind {
1664 TypeKind::String | TypeKind::Unknown => true,
1665 TypeKind::Union(types) => types
1666 .iter()
1667 .any(|alt| matches!(&alt.kind, TypeKind::String | TypeKind::Unknown)),
1668 _ => false,
1669 }
1670}
1671
1672#[cfg(test)]
1673mod tests {
1674 use super::*;
1675 use std::future::Future;
1676 use std::pin::Pin;
1677 use std::sync::{Arc, Mutex};
1678 use std::task::{Context, Poll, Waker};
1679
1680 #[derive(Default)]
1681 struct ManualAsyncState {
1682 result: Mutex<Option<std::result::Result<LustInt, String>>>,
1683 waker: Mutex<Option<Waker>>,
1684 }
1685
1686 impl ManualAsyncState {
1687 fn new() -> Arc<Self> {
1688 Arc::new(Self::default())
1689 }
1690
1691 fn future(self: &Arc<Self>) -> ManualFuture {
1692 ManualFuture {
1693 state: Arc::clone(self),
1694 }
1695 }
1696
1697 fn complete_ok(&self, value: LustInt) {
1698 self.complete(Ok(value));
1699 }
1700
1701 fn complete_err(&self, message: impl Into<String>) {
1702 self.complete(Err(message.into()));
1703 }
1704
1705 fn complete(&self, value: std::result::Result<LustInt, String>) {
1706 {
1707 let mut slot = self.result.lock().unwrap();
1708 *slot = Some(value);
1709 }
1710
1711 if let Some(waker) = self.waker.lock().unwrap().take() {
1712 waker.wake();
1713 }
1714 }
1715 }
1716
1717 struct ManualFuture {
1718 state: Arc<ManualAsyncState>,
1719 }
1720
1721 impl Future for ManualFuture {
1722 type Output = std::result::Result<LustInt, String>;
1723
1724 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1725 {
1726 let mut slot = self.state.result.lock().unwrap();
1727 if let Some(result) = slot.take() {
1728 return Poll::Ready(result);
1729 }
1730 }
1731
1732 let mut waker_slot = self.state.waker.lock().unwrap();
1733 *waker_slot = Some(cx.waker().clone());
1734 Poll::Pending
1735 }
1736 }
1737
1738 fn build_program(source: &str) -> EmbeddedProgram {
1739 EmbeddedProgram::builder()
1740 .module("main", source)
1741 .entry_module("main")
1742 .compile()
1743 .expect("compile embedded program")
1744 }
1745
1746 #[test]
1747 fn struct_instance_supports_mixed_field_types() {
1748 let source = r#"
1749 struct Mixed
1750 count: int
1751 label: string
1752 enabled: bool
1753 end
1754 "#;
1755
1756 let program = build_program(source);
1757 let mixed = program
1758 .struct_instance(
1759 "main.Mixed",
1760 [
1761 struct_field("count", 7_i64),
1762 struct_field("label", "hi"),
1763 struct_field("enabled", true),
1764 ],
1765 )
1766 .expect("struct instance");
1767
1768 assert_eq!(mixed.field::<i64>("count").expect("count field"), 7);
1769 assert_eq!(mixed.field::<String>("label").expect("label field"), "hi");
1770 assert!(mixed.field::<bool>("enabled").expect("enabled field"));
1771 }
1772
1773 #[test]
1774 fn struct_instance_borrow_field_provides_reference_view() {
1775 let source = r#"
1776 struct Sample
1777 name: string
1778 end
1779 "#;
1780
1781 let program = build_program(source);
1782 let sample = program
1783 .struct_instance("main.Sample", [struct_field("name", "Borrowed")])
1784 .expect("struct instance");
1785
1786 let name_ref = sample.borrow_field("name").expect("borrow name field");
1787 assert_eq!(name_ref.as_string().unwrap(), "Borrowed");
1788 assert!(name_ref.as_array_handle().is_none());
1789 }
1790
1791 #[test]
1792 fn array_handle_allows_in_place_mutation() {
1793 let value = Value::array(vec![Value::Int(1)]);
1794 let handle = ArrayHandle::from_value(value).expect("array handle");
1795
1796 {
1797 let mut slots = handle.borrow_mut();
1798 slots.push(Value::Int(2));
1799 slots.push(Value::Int(3));
1800 }
1801
1802 let snapshot: Vec<_> = handle
1803 .borrow()
1804 .iter()
1805 .map(|value| value.as_int().expect("int value"))
1806 .collect();
1807 assert_eq!(snapshot, vec![1, 2, 3]);
1808 }
1809
1810 #[test]
1811 fn struct_instance_allows_setting_fields() {
1812 let source = r#"
1813 struct Mixed
1814 count: int
1815 label: string
1816 enabled: bool
1817 end
1818 "#;
1819
1820 let program = build_program(source);
1821 let mixed = program
1822 .struct_instance(
1823 "main.Mixed",
1824 [
1825 struct_field("count", 1_i64),
1826 struct_field("label", "start"),
1827 struct_field("enabled", false),
1828 ],
1829 )
1830 .expect("struct instance");
1831
1832 mixed
1833 .set_field("count", 11_i64)
1834 .expect("update count field");
1835 assert_eq!(mixed.field::<i64>("count").expect("count field"), 11);
1836
1837 let err = mixed
1838 .set_field("count", "oops")
1839 .expect_err("type mismatch should fail");
1840 match err {
1841 LustError::TypeError { message } => {
1842 assert!(message.contains("count"));
1843 assert!(message.contains("int"));
1844 }
1845 other => panic!("unexpected error: {other:?}"),
1846 }
1847 assert_eq!(mixed.field::<i64>("count").expect("count field"), 11);
1848
1849 mixed
1850 .set_field("label", String::from("updated"))
1851 .expect("update label");
1852 assert_eq!(
1853 mixed.field::<String>("label").expect("label field"),
1854 "updated"
1855 );
1856
1857 mixed.set_field("enabled", true).expect("update enabled");
1858 assert!(mixed.field::<bool>("enabled").expect("enabled field"));
1859 }
1860
1861 #[test]
1862 fn struct_instance_accepts_nested_structs() {
1863 let source = r#"
1864 struct Child
1865 value: int
1866 end
1867
1868 struct Parent
1869 child: main.Child
1870 end
1871 "#;
1872
1873 let program = build_program(source);
1874 let child = program
1875 .struct_instance("main.Child", [struct_field("value", 42_i64)])
1876 .expect("child struct");
1877 let parent = program
1878 .struct_instance("main.Parent", [struct_field("child", child.clone())])
1879 .expect("parent struct");
1880
1881 let nested: StructInstance = parent.field("child").expect("child field");
1882 assert_eq!(nested.field::<i64>("value").expect("value field"), 42);
1883 }
1884
1885 #[test]
1886 fn globals_snapshot_exposes_lust_values() {
1887 let source = r#"
1888 struct Child
1889 value: int
1890 end
1891
1892 struct Parent
1893 child: unknown
1894 end
1895
1896 function make_parent(): Parent
1897 return Parent { child = Child { value = 3 } }
1898 end
1899 "#;
1900
1901 let mut program = build_program(source);
1902 program.run_entry_script().expect("run entry script");
1903 let parent: StructInstance = program
1904 .call_typed("main.make_parent", ())
1905 .expect("call make_parent");
1906 program.set_global_value("main.some_nested_structure", parent.clone());
1907
1908 let globals = program.globals();
1909 let (_, value) = globals
1910 .into_iter()
1911 .find(|(name, _)| name.ends_with("some_nested_structure"))
1912 .expect("global binding present");
1913 let stored = StructInstance::from_value(value).expect("convert to struct");
1914 let child_value = stored
1915 .field::<StructInstance>("child")
1916 .expect("nested child");
1917 assert_eq!(child_value.field::<i64>("value").expect("child value"), 3);
1918 }
1919
1920 #[test]
1921 fn update_field_modifies_value_in_place() {
1922 let source = r#"
1923 struct Counter
1924 value: int
1925 end
1926 "#;
1927
1928 let program = build_program(source);
1929 let counter = program
1930 .struct_instance("main.Counter", [struct_field("value", 10_i64)])
1931 .expect("counter struct");
1932
1933 counter
1934 .update_field("value", |current| match current {
1935 Value::Int(v) => Ok(v + 5),
1936 other => Err(LustError::RuntimeError {
1937 message: format!("unexpected value {other:?}"),
1938 }),
1939 })
1940 .expect("update in place");
1941 assert_eq!(counter.field::<i64>("value").expect("value field"), 15);
1942
1943 let err = counter
1944 .update_field("value", |_| Ok(String::from("oops")))
1945 .expect_err("string should fail type check");
1946 match err {
1947 LustError::TypeError { message } => {
1948 assert!(message.contains("value"));
1949 assert!(message.contains("int"));
1950 }
1951 other => panic!("unexpected error: {other:?}"),
1952 }
1953 assert_eq!(counter.field::<i64>("value").expect("value field"), 15);
1954
1955 let err = counter
1956 .update_field("value", |_| -> Result<i64> {
1957 Err(LustError::RuntimeError {
1958 message: "closure failure".to_string(),
1959 })
1960 })
1961 .expect_err("closure error should propagate");
1962 match err {
1963 LustError::RuntimeError { message } => assert_eq!(message, "closure failure"),
1964 other => panic!("unexpected error: {other:?}"),
1965 }
1966 assert_eq!(counter.field::<i64>("value").expect("value field"), 15);
1967 }
1968
1969 #[test]
1970 fn async_native_resumes_task_on_completion() {
1971 let source = r#"
1972 extern {
1973 function fetch_value(): int
1974 }
1975
1976 function compute(): int
1977 return fetch_value()
1978 end
1979 "#;
1980
1981 let mut program = build_program(source);
1982
1983 let state = ManualAsyncState::new();
1984 let register_state = Arc::clone(&state);
1985 program
1986 .register_async_typed_native::<(), LustInt, _, _>("fetch_value", move |_| {
1987 register_state.future()
1988 })
1989 .expect("register async native");
1990
1991 let handle = {
1992 let vm = program.vm_mut();
1993 let compute_fn = vm.function_value("main.compute").expect("compute function");
1994 vm.spawn_task_value(compute_fn, Vec::new())
1995 .expect("spawn task")
1996 };
1997
1998 assert!(program.has_pending_async_tasks());
1999 program.poll_async_tasks().expect("initial poll");
2000 assert!(program.has_pending_async_tasks());
2001
2002 state.complete_ok(123);
2003 program.poll_async_tasks().expect("resume after completion");
2004
2005 {
2006 let vm = program.vm_mut();
2007 let task = vm.get_task_instance(handle).expect("task exists");
2008 let result = task
2009 .last_result
2010 .as_ref()
2011 .and_then(|value| value.as_int())
2012 .expect("task produced result");
2013 assert_eq!(result, 123);
2014 assert!(task.error.is_none());
2015 }
2016
2017 assert!(!program.has_pending_async_tasks());
2018 }
2019
2020 #[test]
2021 fn async_native_failure_marks_task_failed() {
2022 let source = r#"
2023 extern {
2024 function fetch_value(): int
2025 }
2026
2027 function compute(): int
2028 return fetch_value()
2029 end
2030 "#;
2031
2032 let mut program = build_program(source);
2033
2034 let state = ManualAsyncState::new();
2035 let register_state = Arc::clone(&state);
2036 program
2037 .register_async_typed_native::<(), LustInt, _, _>("fetch_value", move |_| {
2038 register_state.future()
2039 })
2040 .expect("register async native");
2041
2042 let handle = {
2043 let vm = program.vm_mut();
2044 let compute_fn = vm.function_value("main.compute").expect("compute function");
2045 vm.spawn_task_value(compute_fn, Vec::new())
2046 .expect("spawn task")
2047 };
2048
2049 program.poll_async_tasks().expect("initial poll");
2050 state.complete_err("boom");
2051 let err = program
2052 .poll_async_tasks()
2053 .expect_err("poll should propagate failure");
2054 match err {
2055 LustError::RuntimeError { message } => assert_eq!(message, "boom"),
2056 other => panic!("unexpected error: {other:?}"),
2057 }
2058
2059 {
2060 let vm = program.vm_mut();
2061 let task = vm.get_task_instance(handle).expect("task exists");
2062 assert!(task.last_result.is_none());
2063 let error_message = task
2064 .error
2065 .as_ref()
2066 .map(|e| e.to_string())
2067 .expect("task should record error");
2068 assert!(error_message.contains("boom"));
2069 }
2070
2071 assert!(!program.has_pending_async_tasks());
2072 }
2073}
2074
2075fn matches_lust_struct(value: &Value, ty: &Type) -> bool {
2076 match (value, &ty.kind) {
2077 (Value::Struct { name, .. }, TypeKind::Named(expected)) => {
2078 lust_type_names_match(name, expected)
2079 }
2080 (Value::Struct { name, .. }, TypeKind::GenericInstance { name: expected, .. }) => {
2081 lust_type_names_match(name, expected)
2082 }
2083
2084 (value, TypeKind::Union(types)) => types.iter().any(|alt| matches_lust_struct(value, alt)),
2085 (_, TypeKind::Unknown) => true,
2086 _ => false,
2087 }
2088}
2089
2090fn matches_lust_enum(value: &Value, ty: &Type) -> bool {
2091 match (value, &ty.kind) {
2092 (Value::Enum { enum_name, .. }, TypeKind::Named(expected)) => {
2093 lust_type_names_match(enum_name, expected)
2094 }
2095 (Value::Enum { enum_name, .. }, TypeKind::GenericInstance { name: expected, .. }) => {
2096 lust_type_names_match(enum_name, expected)
2097 }
2098
2099 (value, TypeKind::Union(types)) => types.iter().any(|alt| matches_lust_enum(value, alt)),
2100 (_, TypeKind::Unknown) => true,
2101 _ => false,
2102 }
2103}
2104
2105fn lust_type_names_match(value: &str, expected: &str) -> bool {
2106 if value == expected {
2107 return true;
2108 }
2109
2110 let normalized_value = normalize_global_name(value);
2111 let normalized_expected = normalize_global_name(expected);
2112 if normalized_value == normalized_expected {
2113 return true;
2114 }
2115
2116 simple_type_name(&normalized_value) == simple_type_name(&normalized_expected)
2117}
2118
2119fn simple_type_name(name: &str) -> &str {
2120 name.rsplit(|c| c == '.' || c == ':').next().unwrap_or(name)
2121}
2122
2123fn matches_array_type<F>(ty: &Type, matcher: &F) -> bool
2124where
2125 F: Fn(&Type) -> bool,
2126{
2127 match &ty.kind {
2128 TypeKind::Array(inner) => matcher(inner),
2129 TypeKind::Unknown => true,
2130 TypeKind::Union(types) => types.iter().any(|alt| matches_array_type(alt, matcher)),
2131 _ => false,
2132 }
2133}
2134
2135fn matches_array_handle_type(ty: &Type) -> bool {
2136 match &ty.kind {
2137 TypeKind::Array(_) | TypeKind::Unknown => true,
2138 TypeKind::Union(types) => types.iter().any(|alt| matches_array_handle_type(alt)),
2139 _ => false,
2140 }
2141}
2142
2143fn matches_map_handle_type(ty: &Type) -> bool {
2144 match &ty.kind {
2145 TypeKind::Map(_, _) | TypeKind::Unknown => true,
2146 TypeKind::Union(types) => types.iter().any(|alt| matches_map_handle_type(alt)),
2147 _ => false,
2148 }
2149}
2150
2151fn matches_table_handle_type(ty: &Type) -> bool {
2152 match &ty.kind {
2153 TypeKind::Table | TypeKind::Unknown => true,
2154 TypeKind::Union(types) => types.iter().any(|alt| matches_table_handle_type(alt)),
2155 _ => false,
2156 }
2157}
2158
2159pub trait FromLustArgs: Sized {
2160 fn from_values(values: &[Value]) -> std::result::Result<Self, String>;
2161 fn matches_signature(params: &[Type]) -> bool;
2162}
2163
2164macro_rules! impl_from_lust_args_tuple {
2165 ($( $name:ident ),+) => {
2166 impl<$($name),+> FromLustArgs for ($($name,)+)
2167 where
2168 $($name: FromLustValue,)+
2169 {
2170 fn from_values(values: &[Value]) -> std::result::Result<Self, String> {
2171 let expected = count_idents!($($name),+);
2172 if values.len() != expected {
2173 return Err(format!(
2174 "Native function expected {} argument(s) but received {}",
2175 expected,
2176 values.len()
2177 ));
2178 }
2179
2180 let mut idx = 0;
2181 let result = (
2182 $(
2183 {
2184 let value = $name::from_value(values[idx].clone()).map_err(|e| e.to_string())?;
2185 idx += 1;
2186 value
2187 },
2188 )+
2189 );
2190 let _ = idx;
2191 Ok(result)
2192 }
2193
2194 fn matches_signature(params: &[Type]) -> bool {
2195 let expected = count_idents!($($name),+);
2196 params.len() == expected && {
2197 let mut idx = 0;
2198 let mut ok = true;
2199 $(
2200 if ok && !$name::matches_lust_type(¶ms[idx]) {
2201 ok = false;
2202 }
2203
2204 idx += 1;
2205 )+
2206 let _ = idx;
2207 ok
2208 }
2209
2210 }
2211
2212 }
2213
2214 };
2215}
2216
2217macro_rules! count_idents {
2218 ($($name:ident),*) => {
2219 <[()]>::len(&[$(count_idents!(@sub $name)),*])
2220 };
2221 (@sub $name:ident) => { () };
2222}
2223
2224impl_from_lust_args_tuple!(A);
2225impl_from_lust_args_tuple!(A, B);
2226impl_from_lust_args_tuple!(A, B, C);
2227impl_from_lust_args_tuple!(A, B, C, D);
2228impl_from_lust_args_tuple!(A, B, C, D, E);
2229impl<T> FromLustArgs for T
2230where
2231 T: FromLustValue,
2232{
2233 fn from_values(values: &[Value]) -> std::result::Result<Self, String> {
2234 match values.len() {
2235 0 => T::from_value(Value::Nil).map_err(|e| e.to_string()),
2236 1 => T::from_value(values[0].clone()).map_err(|e| e.to_string()),
2237 count => Err(format!(
2238 "Native function expected 1 argument but received {}",
2239 count
2240 )),
2241 }
2242 }
2243
2244 fn matches_signature(params: &[Type]) -> bool {
2245 if params.is_empty() {
2246 let unit = Type::new(TypeKind::Unit, Span::new(0, 0, 0, 0));
2247 return T::matches_lust_type(&unit);
2248 }
2249
2250 params.len() == 1 && T::matches_lust_type(¶ms[0])
2251 }
2252}
2253
2254pub trait IntoLustValue: Sized {
2255 fn into_value(self) -> Value;
2256 fn matches_lust_type(ty: &Type) -> bool;
2257 fn type_description() -> &'static str;
2258}
2259
2260pub trait FromLustValue: Sized {
2261 fn from_value(value: Value) -> Result<Self>;
2262 fn matches_lust_type(ty: &Type) -> bool;
2263 fn type_description() -> &'static str;
2264}
2265
2266pub trait FunctionArgs {
2267 fn into_values(self) -> Vec<Value>;
2268 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()>;
2269}
2270
2271impl IntoLustValue for Value {
2272 fn into_value(self) -> Value {
2273 self
2274 }
2275
2276 fn matches_lust_type(_: &Type) -> bool {
2277 true
2278 }
2279
2280 fn type_description() -> &'static str {
2281 "Value"
2282 }
2283}
2284
2285impl FromLustValue for Value {
2286 fn from_value(value: Value) -> Result<Self> {
2287 Ok(value)
2288 }
2289
2290 fn matches_lust_type(_: &Type) -> bool {
2291 true
2292 }
2293
2294 fn type_description() -> &'static str {
2295 "Value"
2296 }
2297}
2298
2299impl IntoLustValue for LustInt {
2300 fn into_value(self) -> Value {
2301 Value::Int(self)
2302 }
2303
2304 fn matches_lust_type(ty: &Type) -> bool {
2305 matches!(ty.kind, TypeKind::Int | TypeKind::Unknown)
2306 }
2307
2308 fn type_description() -> &'static str {
2309 "int"
2310 }
2311}
2312
2313impl FromLustValue for LustInt {
2314 fn from_value(value: Value) -> Result<Self> {
2315 match value {
2316 Value::Int(v) => Ok(v),
2317 other => Err(LustError::RuntimeError {
2318 message: format!("Expected Lust value 'int' but received '{:?}'", other),
2319 }),
2320 }
2321 }
2322
2323 fn matches_lust_type(ty: &Type) -> bool {
2324 matches!(ty.kind, TypeKind::Int | TypeKind::Unknown)
2325 }
2326
2327 fn type_description() -> &'static str {
2328 "int"
2329 }
2330}
2331
2332impl IntoLustValue for LustFloat {
2333 fn into_value(self) -> Value {
2334 Value::Float(self)
2335 }
2336
2337 fn matches_lust_type(ty: &Type) -> bool {
2338 matches!(ty.kind, TypeKind::Float | TypeKind::Unknown)
2339 }
2340
2341 fn type_description() -> &'static str {
2342 "float"
2343 }
2344}
2345
2346impl FromLustValue for LustFloat {
2347 fn from_value(value: Value) -> Result<Self> {
2348 match value {
2349 Value::Float(v) => Ok(v),
2350 other => Err(LustError::RuntimeError {
2351 message: format!("Expected Lust value 'float' but received '{:?}'", other),
2352 }),
2353 }
2354 }
2355
2356 fn matches_lust_type(ty: &Type) -> bool {
2357 matches!(ty.kind, TypeKind::Float | TypeKind::Unknown)
2358 }
2359
2360 fn type_description() -> &'static str {
2361 "float"
2362 }
2363}
2364
2365impl IntoLustValue for bool {
2366 fn into_value(self) -> Value {
2367 Value::Bool(self)
2368 }
2369
2370 fn matches_lust_type(ty: &Type) -> bool {
2371 matches!(ty.kind, TypeKind::Bool | TypeKind::Unknown)
2372 }
2373
2374 fn type_description() -> &'static str {
2375 "bool"
2376 }
2377}
2378
2379impl FromLustValue for bool {
2380 fn from_value(value: Value) -> Result<Self> {
2381 match value {
2382 Value::Bool(b) => Ok(b),
2383 other => Err(LustError::RuntimeError {
2384 message: format!("Expected Lust value 'bool' but received '{:?}'", other),
2385 }),
2386 }
2387 }
2388
2389 fn matches_lust_type(ty: &Type) -> bool {
2390 matches!(ty.kind, TypeKind::Bool | TypeKind::Unknown)
2391 }
2392
2393 fn type_description() -> &'static str {
2394 "bool"
2395 }
2396}
2397
2398impl IntoLustValue for String {
2399 fn into_value(self) -> Value {
2400 Value::String(Rc::new(self))
2401 }
2402
2403 fn matches_lust_type(ty: &Type) -> bool {
2404 matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
2405 }
2406
2407 fn type_description() -> &'static str {
2408 "string"
2409 }
2410}
2411
2412impl IntoLustValue for Rc<String> {
2413 fn into_value(self) -> Value {
2414 Value::String(self)
2415 }
2416
2417 fn matches_lust_type(ty: &Type) -> bool {
2418 matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
2419 }
2420
2421 fn type_description() -> &'static str {
2422 "string"
2423 }
2424}
2425
2426impl IntoLustValue for StructInstance {
2427 fn into_value(self) -> Value {
2428 self.value
2429 }
2430
2431 fn matches_lust_type(ty: &Type) -> bool {
2432 match &ty.kind {
2433 TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
2434 TypeKind::Union(types) => types
2435 .iter()
2436 .any(|alt| <Self as IntoLustValue>::matches_lust_type(alt)),
2437 _ => false,
2438 }
2439 }
2440
2441 fn type_description() -> &'static str {
2442 "struct"
2443 }
2444}
2445
2446impl FromLustValue for StructInstance {
2447 fn from_value(value: Value) -> Result<Self> {
2448 match &value {
2449 Value::Struct { name, .. } => Ok(StructInstance {
2450 type_name: name.clone(),
2451 value,
2452 }),
2453 other => Err(LustError::RuntimeError {
2454 message: format!("Expected Lust value 'struct' but received '{:?}'", other),
2455 }),
2456 }
2457 }
2458
2459 fn matches_lust_type(ty: &Type) -> bool {
2460 match &ty.kind {
2461 TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
2462 TypeKind::Union(types) => types
2463 .iter()
2464 .any(|alt| <Self as FromLustValue>::matches_lust_type(alt)),
2465 _ => false,
2466 }
2467 }
2468
2469 fn type_description() -> &'static str {
2470 "struct"
2471 }
2472}
2473
2474impl IntoLustValue for EnumInstance {
2475 fn into_value(self) -> Value {
2476 self.value
2477 }
2478
2479 fn matches_lust_type(ty: &Type) -> bool {
2480 match &ty.kind {
2481 TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
2482 TypeKind::Union(types) => types
2483 .iter()
2484 .any(|alt| <Self as IntoLustValue>::matches_lust_type(alt)),
2485 _ => false,
2486 }
2487 }
2488
2489 fn type_description() -> &'static str {
2490 "enum"
2491 }
2492}
2493
2494impl FromLustValue for EnumInstance {
2495 fn from_value(value: Value) -> Result<Self> {
2496 match &value {
2497 Value::Enum {
2498 enum_name, variant, ..
2499 } => Ok(EnumInstance {
2500 type_name: enum_name.clone(),
2501 variant: variant.clone(),
2502 value,
2503 }),
2504 other => Err(LustError::RuntimeError {
2505 message: format!("Expected Lust value 'enum' but received '{:?}'", other),
2506 }),
2507 }
2508 }
2509
2510 fn matches_lust_type(ty: &Type) -> bool {
2511 match &ty.kind {
2512 TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
2513 TypeKind::Union(types) => types
2514 .iter()
2515 .any(|alt| <Self as FromLustValue>::matches_lust_type(alt)),
2516 _ => false,
2517 }
2518 }
2519
2520 fn type_description() -> &'static str {
2521 "enum"
2522 }
2523}
2524
2525impl<T> IntoLustValue for Vec<T>
2526where
2527 T: IntoLustValue,
2528{
2529 fn into_value(self) -> Value {
2530 let values = self.into_iter().map(|item| item.into_value()).collect();
2531 Value::array(values)
2532 }
2533
2534 fn matches_lust_type(ty: &Type) -> bool {
2535 matches_array_type(ty, &T::matches_lust_type)
2536 }
2537
2538 fn type_description() -> &'static str {
2539 "array"
2540 }
2541}
2542
2543impl IntoLustValue for ArrayHandle {
2544 fn into_value(self) -> Value {
2545 Value::Array(self.inner)
2546 }
2547
2548 fn matches_lust_type(ty: &Type) -> bool {
2549 matches_array_handle_type(ty)
2550 }
2551
2552 fn type_description() -> &'static str {
2553 "array"
2554 }
2555}
2556
2557impl IntoLustValue for MapHandle {
2558 fn into_value(self) -> Value {
2559 Value::Map(self.inner)
2560 }
2561
2562 fn matches_lust_type(ty: &Type) -> bool {
2563 matches_map_handle_type(ty)
2564 }
2565
2566 fn type_description() -> &'static str {
2567 "map"
2568 }
2569}
2570
2571impl IntoLustValue for TableHandle {
2572 fn into_value(self) -> Value {
2573 Value::Table(self.inner)
2574 }
2575
2576 fn matches_lust_type(ty: &Type) -> bool {
2577 matches_table_handle_type(ty)
2578 }
2579
2580 fn type_description() -> &'static str {
2581 "table"
2582 }
2583}
2584
2585impl<T> FromLustValue for Vec<T>
2586where
2587 T: FromLustValue,
2588{
2589 fn from_value(value: Value) -> Result<Self> {
2590 match value {
2591 Value::Array(items) => {
2592 let borrowed = items.borrow();
2593 let mut result = Vec::with_capacity(borrowed.len());
2594 for item in borrowed.iter() {
2595 result.push(T::from_value(item.clone())?);
2596 }
2597
2598 Ok(result)
2599 }
2600
2601 other => Err(LustError::RuntimeError {
2602 message: format!("Expected Lust value 'array' but received '{:?}'", other),
2603 }),
2604 }
2605 }
2606
2607 fn matches_lust_type(ty: &Type) -> bool {
2608 matches_array_type(ty, &T::matches_lust_type)
2609 }
2610
2611 fn type_description() -> &'static str {
2612 "array"
2613 }
2614}
2615
2616impl FromLustValue for ArrayHandle {
2617 fn from_value(value: Value) -> Result<Self> {
2618 match value {
2619 Value::Array(items) => Ok(ArrayHandle::from_rc(items)),
2620 other => Err(LustError::RuntimeError {
2621 message: format!("Expected Lust value 'array' but received '{:?}'", other),
2622 }),
2623 }
2624 }
2625
2626 fn matches_lust_type(ty: &Type) -> bool {
2627 matches_array_handle_type(ty)
2628 }
2629
2630 fn type_description() -> &'static str {
2631 "array"
2632 }
2633}
2634
2635impl FromLustValue for MapHandle {
2636 fn from_value(value: Value) -> Result<Self> {
2637 match value {
2638 Value::Map(map) => Ok(MapHandle::from_rc(map)),
2639 other => Err(LustError::RuntimeError {
2640 message: format!("Expected Lust value 'map' but received '{:?}'", other),
2641 }),
2642 }
2643 }
2644
2645 fn matches_lust_type(ty: &Type) -> bool {
2646 matches_map_handle_type(ty)
2647 }
2648
2649 fn type_description() -> &'static str {
2650 "map"
2651 }
2652}
2653
2654impl FromLustValue for TableHandle {
2655 fn from_value(value: Value) -> Result<Self> {
2656 match value {
2657 Value::Table(table) => Ok(TableHandle::from_rc(table)),
2658 other => Err(LustError::RuntimeError {
2659 message: format!("Expected Lust value 'table' but received '{:?}'", other),
2660 }),
2661 }
2662 }
2663
2664 fn matches_lust_type(ty: &Type) -> bool {
2665 matches_table_handle_type(ty)
2666 }
2667
2668 fn type_description() -> &'static str {
2669 "table"
2670 }
2671}
2672
2673impl<'a> IntoLustValue for &'a str {
2674 fn into_value(self) -> Value {
2675 Value::String(Rc::new(self.to_owned()))
2676 }
2677
2678 fn matches_lust_type(ty: &Type) -> bool {
2679 matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
2680 }
2681
2682 fn type_description() -> &'static str {
2683 "string"
2684 }
2685}
2686
2687impl<'a> IntoLustValue for &'a String {
2688 fn into_value(self) -> Value {
2689 Value::String(Rc::new(self.clone()))
2690 }
2691
2692 fn matches_lust_type(ty: &Type) -> bool {
2693 matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
2694 }
2695
2696 fn type_description() -> &'static str {
2697 "string"
2698 }
2699}
2700
2701impl FromLustValue for String {
2702 fn from_value(value: Value) -> Result<Self> {
2703 match value {
2704 Value::String(s) => Ok((*s).clone()),
2705 other => Err(LustError::RuntimeError {
2706 message: format!("Expected Lust value 'string' but received '{:?}'", other),
2707 }),
2708 }
2709 }
2710
2711 fn matches_lust_type(ty: &Type) -> bool {
2712 matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
2713 }
2714
2715 fn type_description() -> &'static str {
2716 "string"
2717 }
2718}
2719
2720impl FromLustValue for Rc<String> {
2721 fn from_value(value: Value) -> Result<Self> {
2722 match value {
2723 Value::String(s) => Ok(s),
2724 other => Err(LustError::RuntimeError {
2725 message: format!("Expected Lust value 'string' but received '{:?}'", other),
2726 }),
2727 }
2728 }
2729
2730 fn matches_lust_type(ty: &Type) -> bool {
2731 matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
2732 }
2733
2734 fn type_description() -> &'static str {
2735 "string"
2736 }
2737}
2738
2739impl FromLustValue for () {
2740 fn from_value(value: Value) -> Result<Self> {
2741 match value {
2742 Value::Nil => Ok(()),
2743 other => Err(LustError::RuntimeError {
2744 message: format!("Expected Lust value 'unit' but received '{:?}'", other),
2745 }),
2746 }
2747 }
2748
2749 fn matches_lust_type(ty: &Type) -> bool {
2750 matches!(ty.kind, TypeKind::Unit | TypeKind::Unknown)
2751 }
2752
2753 fn type_description() -> &'static str {
2754 "unit"
2755 }
2756}
2757
2758impl FunctionArgs for () {
2759 fn into_values(self) -> Vec<Value> {
2760 Vec::new()
2761 }
2762
2763 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
2764 ensure_arity(function_name, params, 0)
2765 }
2766}
2767
2768impl<T> FunctionArgs for T
2769where
2770 T: IntoLustValue,
2771{
2772 fn into_values(self) -> Vec<Value> {
2773 vec![self.into_value()]
2774 }
2775
2776 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
2777 ensure_arity(function_name, params, 1)?;
2778 ensure_arg_type::<T>(function_name, params, 0)
2779 }
2780}
2781
2782impl<A, B> FunctionArgs for (A, B)
2783where
2784 A: IntoLustValue,
2785 B: IntoLustValue,
2786{
2787 fn into_values(self) -> Vec<Value> {
2788 vec![self.0.into_value(), self.1.into_value()]
2789 }
2790
2791 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
2792 ensure_arity(function_name, params, 2)?;
2793 ensure_arg_type::<A>(function_name, params, 0)?;
2794 ensure_arg_type::<B>(function_name, params, 1)?;
2795 Ok(())
2796 }
2797}
2798
2799impl<A, B, C> FunctionArgs for (A, B, C)
2800where
2801 A: IntoLustValue,
2802 B: IntoLustValue,
2803 C: IntoLustValue,
2804{
2805 fn into_values(self) -> Vec<Value> {
2806 vec![
2807 self.0.into_value(),
2808 self.1.into_value(),
2809 self.2.into_value(),
2810 ]
2811 }
2812
2813 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
2814 ensure_arity(function_name, params, 3)?;
2815 ensure_arg_type::<A>(function_name, params, 0)?;
2816 ensure_arg_type::<B>(function_name, params, 1)?;
2817 ensure_arg_type::<C>(function_name, params, 2)?;
2818 Ok(())
2819 }
2820}
2821
2822impl<A, B, C, D> FunctionArgs for (A, B, C, D)
2823where
2824 A: IntoLustValue,
2825 B: IntoLustValue,
2826 C: IntoLustValue,
2827 D: IntoLustValue,
2828{
2829 fn into_values(self) -> Vec<Value> {
2830 vec![
2831 self.0.into_value(),
2832 self.1.into_value(),
2833 self.2.into_value(),
2834 self.3.into_value(),
2835 ]
2836 }
2837
2838 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
2839 ensure_arity(function_name, params, 4)?;
2840 ensure_arg_type::<A>(function_name, params, 0)?;
2841 ensure_arg_type::<B>(function_name, params, 1)?;
2842 ensure_arg_type::<C>(function_name, params, 2)?;
2843 ensure_arg_type::<D>(function_name, params, 3)?;
2844 Ok(())
2845 }
2846}
2847
2848impl<A, B, C, D, E> FunctionArgs for (A, B, C, D, E)
2849where
2850 A: IntoLustValue,
2851 B: IntoLustValue,
2852 C: IntoLustValue,
2853 D: IntoLustValue,
2854 E: IntoLustValue,
2855{
2856 fn into_values(self) -> Vec<Value> {
2857 vec![
2858 self.0.into_value(),
2859 self.1.into_value(),
2860 self.2.into_value(),
2861 self.3.into_value(),
2862 self.4.into_value(),
2863 ]
2864 }
2865
2866 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
2867 ensure_arity(function_name, params, 5)?;
2868 ensure_arg_type::<A>(function_name, params, 0)?;
2869 ensure_arg_type::<B>(function_name, params, 1)?;
2870 ensure_arg_type::<C>(function_name, params, 2)?;
2871 ensure_arg_type::<D>(function_name, params, 3)?;
2872 ensure_arg_type::<E>(function_name, params, 4)?;
2873 Ok(())
2874 }
2875}
2876
2877fn ensure_arity(function_name: &str, params: &[Type], provided: usize) -> Result<()> {
2878 if params.len() == provided {
2879 Ok(())
2880 } else {
2881 Err(LustError::TypeError {
2882 message: format!(
2883 "Function '{}' expects {} argument(s) but {} were supplied",
2884 function_name,
2885 params.len(),
2886 provided
2887 ),
2888 })
2889 }
2890}
2891
2892fn ensure_arg_type<T: IntoLustValue>(
2893 function_name: &str,
2894 params: &[Type],
2895 index: usize,
2896) -> Result<()> {
2897 if <T as IntoLustValue>::matches_lust_type(¶ms[index]) {
2898 Ok(())
2899 } else {
2900 Err(argument_type_mismatch(
2901 function_name,
2902 index,
2903 <T as IntoLustValue>::type_description(),
2904 ¶ms[index],
2905 ))
2906 }
2907}
2908
2909fn argument_type_mismatch(
2910 function_name: &str,
2911 index: usize,
2912 rust_type: &str,
2913 lust_type: &Type,
2914) -> LustError {
2915 LustError::TypeError {
2916 message: format!(
2917 "Function '{}' parameter {} expects Lust type '{}' but Rust provided '{}'",
2918 function_name,
2919 index + 1,
2920 lust_type,
2921 rust_type
2922 ),
2923 }
2924}