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