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