1use crate::ast::{EnumDef, FieldOwnership, Item, ItemKind, Span, StructDef, Type, TypeKind};
2use crate::bytecode::{Compiler, NativeCallResult, TaskHandle, Value};
3use crate::modules::{ModuleImports, ModuleLoader};
4use crate::number::{LustFloat, LustInt};
5use crate::typechecker::{FunctionSignature, TypeChecker};
6use crate::vm::VM;
7use crate::{LustConfig, LustError, Result};
8use std::cell::RefCell;
9use hashbrown::HashMap;
10use std::future::Future;
11use std::pin::Pin;
12use std::path::{Path, PathBuf};
13use std::rc::Rc;
14use std::sync::Arc;
15use std::sync::atomic::{AtomicBool, Ordering};
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 signature(&self, function_name: &str) -> Option<&FunctionSignature> {
259 self.find_signature(function_name).map(|(_, sig)| sig)
260 }
261
262 pub fn typed_functions(&self) -> impl Iterator<Item = (&String, &FunctionSignature)> {
263 self.signatures.iter()
264 }
265
266 pub fn struct_definition(&self, type_name: &str) -> Option<&StructDef> {
267 self.struct_defs.get(type_name)
268 }
269
270 pub fn enum_definition(&self, type_name: &str) -> Option<&EnumDef> {
271 self.enum_defs.get(type_name)
272 }
273
274 fn find_signature(&self, name: &str) -> Option<(String, &FunctionSignature)> {
275 if let Some(sig) = self.signatures.get(name) {
276 return Some((name.to_string(), sig));
277 }
278
279 for candidate in self.signature_lookup_candidates(name) {
280 if let Some(sig) = self.signatures.get(&candidate) {
281 return Some((candidate, sig));
282 }
283 }
284
285 let matches = self
286 .signatures
287 .iter()
288 .filter_map(|(key, sig)| {
289 if Self::simple_name(key) == name {
290 Some((key, sig))
291 } else {
292 None
293 }
294 })
295 .collect::<Vec<_>>();
296 if matches.len() == 1 {
297 let (key, sig) = matches[0];
298 return Some((key.clone(), sig));
299 }
300
301 None
302 }
303
304 fn resolve_signature(&self, name: &str) -> Result<(String, &FunctionSignature)> {
305 if let Some(found) = self.find_signature(name) {
306 return Ok(found);
307 }
308
309 let matches = self
310 .signatures
311 .keys()
312 .filter(|key| Self::simple_name(key) == name)
313 .count();
314 if matches > 1 {
315 return Err(LustError::TypeError {
316 message: format!(
317 "Cannot register native '{}': multiple matching functions found; specify a fully qualified name",
318 name
319 ),
320 });
321 }
322
323 Err(LustError::TypeError {
324 message: format!(
325 "Cannot register native '{}': function not declared in Lust source",
326 name
327 ),
328 })
329 }
330
331 fn signature_lookup_candidates(&self, name: &str) -> Vec<String> {
332 let mut candidates: Vec<String> = Vec::new();
333 if name.contains("::") {
334 candidates.push(name.replace("::", "."));
335 }
336
337 if name.contains('.') {
338 candidates.push(name.replace('.', "::"));
339 }
340
341 if !name.contains('.') && !name.contains("::") {
342 let module = &self.entry_module;
343 candidates.push(format!("{}.{}", module, name));
344 candidates.push(format!("{}::{}", module, name));
345 }
346
347 candidates
348 }
349
350 fn simple_name(name: &str) -> &str {
351 name.rsplit(|c| c == '.' || c == ':').next().unwrap_or(name)
352 }
353
354 fn register_native_with_aliases<F>(
355 &mut self,
356 requested_name: &str,
357 canonical: String,
358 func: F,
359 ) where
360 F: Fn(&[Value]) -> std::result::Result<NativeCallResult, String> + 'static,
361 {
362 let native_fn: Rc<dyn Fn(&[Value]) -> std::result::Result<NativeCallResult, String>> =
363 Rc::new(func);
364 let value = Value::NativeFunction(native_fn);
365 let mut aliases: Vec<String> = Vec::new();
366 aliases.push(canonical.clone());
367 let canonical_normalized = normalize_global_name(&canonical);
368 if canonical_normalized != canonical {
369 aliases.push(canonical_normalized);
370 }
371
372 if requested_name != canonical {
373 aliases.push(requested_name.to_string());
374 let normalized = normalize_global_name(requested_name);
375 if normalized != requested_name {
376 aliases.push(normalized);
377 }
378 }
379
380 aliases.sort();
381 aliases.dedup();
382 for key in aliases {
383 self.vm.register_native(key, value.clone());
384 }
385 }
386
387 pub fn get_global_value(&self, name: &str) -> Option<Value> {
388 let normalized = normalize_global_name(name);
389 self.vm.get_global(&normalized)
390 }
391
392 pub fn get_typed_global<T: FromLustValue>(&self, name: &str) -> Result<Option<T>> {
393 let normalized = normalize_global_name(name);
394 match self.vm.get_global(&normalized) {
395 Some(value) => T::from_value(value).map(Some),
396 None => Ok(None),
397 }
398 }
399
400 pub fn set_global_value<V: IntoTypedValue>(&mut self, name: impl Into<String>, value: V) {
401 let name_string = name.into();
402 let normalized = normalize_global_name(&name_string);
403 let value = value.into_typed_value().into_value();
404 self.vm.set_global(normalized, value);
405 }
406
407 pub fn struct_instance<I, K, V>(
408 &self,
409 type_name: impl Into<String>,
410 fields: I,
411 ) -> Result<StructInstance>
412 where
413 I: IntoIterator<Item = (K, V)>,
414 K: Into<String>,
415 V: IntoTypedValue,
416 {
417 let type_name = type_name.into();
418 let def = self
419 .struct_defs
420 .get(&type_name)
421 .ok_or_else(|| LustError::TypeError {
422 message: format!("Unknown struct '{}'", type_name),
423 })?;
424 let mut provided: HashMap<String, TypedValue> = fields
425 .into_iter()
426 .map(|(name, value)| (name.into(), value.into_typed_value()))
427 .collect();
428 let mut ordered_fields: Vec<(Rc<String>, Value)> = Vec::with_capacity(def.fields.len());
429 for field in &def.fields {
430 let typed_value = provided
431 .remove(&field.name)
432 .ok_or_else(|| LustError::TypeError {
433 message: format!(
434 "Struct '{}' is missing required field '{}'",
435 type_name, field.name
436 ),
437 })?;
438 let matches_declared = typed_value.matches(&field.ty);
439 let matches_ref_inner = matches!(field.ownership, FieldOwnership::Weak)
440 && field
441 .weak_target
442 .as_ref()
443 .map(|inner| typed_value.matches(inner))
444 .unwrap_or(false);
445 if !(matches_declared || matches_ref_inner) {
446 return Err(LustError::TypeError {
447 message: format!(
448 "Struct '{}' field '{}' expects Lust type '{}' but Rust provided '{}'",
449 type_name,
450 field.name,
451 field.ty,
452 typed_value.description()
453 ),
454 });
455 }
456
457 ordered_fields.push((Rc::new(field.name.clone()), typed_value.into_value()));
458 }
459
460 if !provided.is_empty() {
461 let extra = provided.keys().cloned().collect::<Vec<_>>().join(", ");
462 return Err(LustError::TypeError {
463 message: format!(
464 "Struct '{}' received unknown field(s): {}",
465 type_name, extra
466 ),
467 });
468 }
469
470 let value = self.vm.instantiate_struct(&type_name, ordered_fields)?;
471 Ok(StructInstance::new(type_name.clone(), value))
472 }
473
474 pub fn enum_variant(
475 &self,
476 type_name: impl Into<String>,
477 variant: impl Into<String>,
478 ) -> Result<EnumInstance> {
479 self.enum_variant_with(type_name, variant, std::iter::empty::<Value>())
480 }
481
482 pub fn enum_variant_with<I, V>(
483 &self,
484 type_name: impl Into<String>,
485 variant: impl Into<String>,
486 payload: I,
487 ) -> Result<EnumInstance>
488 where
489 I: IntoIterator<Item = V>,
490 V: IntoTypedValue,
491 {
492 let type_name = type_name.into();
493 let variant_name = variant.into();
494 let def = self
495 .enum_defs
496 .get(&type_name)
497 .ok_or_else(|| LustError::TypeError {
498 message: format!("Unknown enum '{}'", type_name),
499 })?;
500 let enum_variant = def
501 .variants
502 .iter()
503 .find(|v| v.name == variant_name)
504 .ok_or_else(|| LustError::TypeError {
505 message: format!(
506 "Enum '{}' has no variant named '{}'",
507 type_name, variant_name
508 ),
509 })?;
510 let mut values: Vec<TypedValue> =
511 payload.into_iter().map(|v| v.into_typed_value()).collect();
512 let coerced_values: Option<Rc<Vec<Value>>> = match &enum_variant.fields {
513 None => {
514 if !values.is_empty() {
515 return Err(LustError::TypeError {
516 message: format!(
517 "Enum variant '{}.{}' does not accept payload values",
518 type_name, variant_name
519 ),
520 });
521 }
522
523 None
524 }
525
526 Some(field_types) => {
527 if values.len() != field_types.len() {
528 return Err(LustError::TypeError {
529 message: format!(
530 "Enum variant '{}.{}' expects {} value(s) but {} were supplied",
531 type_name,
532 variant_name,
533 field_types.len(),
534 values.len()
535 ),
536 });
537 }
538
539 let mut collected = Vec::with_capacity(field_types.len());
540 for (idx, (typed_value, field_ty)) in
541 values.drain(..).zip(field_types.iter()).enumerate()
542 {
543 if !typed_value.matches(field_ty) {
544 return Err(LustError::TypeError {
545 message: format!(
546 "Enum variant '{}.{}' field {} expects Lust type '{}' but Rust provided '{}'",
547 type_name,
548 variant_name,
549 idx + 1,
550 field_ty,
551 typed_value.description()
552 ),
553 });
554 }
555
556 collected.push(typed_value.into_value());
557 }
558
559 Some(Rc::new(collected))
560 }
561 };
562 Ok(EnumInstance::new(
563 type_name.clone(),
564 variant_name.clone(),
565 Value::Enum {
566 enum_name: type_name,
567 variant: variant_name,
568 values: coerced_values,
569 },
570 ))
571 }
572
573 pub fn register_native_fn<F>(&mut self, name: impl Into<String>, func: F)
574 where
575 F: Fn(&[Value]) -> std::result::Result<NativeCallResult, String> + 'static,
576 {
577 let native = Value::NativeFunction(Rc::new(func));
578 self.vm.register_native(name, native);
579 }
580
581 pub fn register_async_native<F, Fut>(
582 &mut self,
583 name: impl Into<String>,
584 func: F,
585 ) -> Result<()>
586 where
587 F: Fn(Vec<Value>) -> Fut + 'static,
588 Fut: Future<Output = std::result::Result<Value, String>> + 'static,
589 {
590 let registry = self.async_registry.clone();
591 let name_string = name.into();
592 let handler = move |values: &[Value]| -> std::result::Result<NativeCallResult, String> {
593 let args: Vec<Value> = values.iter().cloned().collect();
594 let future: AsyncValueFuture = Box::pin(func(args));
595 VM::with_current(|vm| {
596 let handle = vm
597 .current_task_handle()
598 .ok_or_else(|| "Async native functions require a running task".to_string())?;
599 registry.borrow_mut().register(handle, future)?;
600 Ok(NativeCallResult::Yield(Value::Nil))
601 })
602 };
603 self.register_native_fn(name_string, handler);
604 Ok(())
605 }
606
607 pub fn register_typed_native<Args, R, F>(&mut self, name: &str, func: F) -> Result<()>
608 where
609 Args: FromLustArgs,
610 R: IntoLustValue + FromLustValue,
611 F: Fn(Args) -> std::result::Result<R, String> + 'static,
612 {
613 let (canonical, signature) = self.resolve_signature(name)?;
614 if !Args::matches_signature(&signature.params) {
615 return Err(LustError::TypeError {
616 message: format!(
617 "Native '{}' argument types do not match Lust signature",
618 name
619 ),
620 });
621 }
622
623 ensure_return_type::<R>(name, &signature.return_type)?;
624 let handler = move |values: &[Value]| -> std::result::Result<NativeCallResult, String> {
625 let args = Args::from_values(values)?;
626 let result = func(args)?;
627 Ok(NativeCallResult::Return(result.into_value()))
628 };
629 self.register_native_with_aliases(name, canonical, handler);
630 Ok(())
631 }
632
633 pub fn register_async_typed_native<Args, R, F, Fut>(
634 &mut self,
635 name: &str,
636 func: F,
637 ) -> Result<()>
638 where
639 Args: FromLustArgs,
640 R: IntoLustValue + FromLustValue,
641 F: Fn(Args) -> Fut + 'static,
642 Fut: Future<Output = std::result::Result<R, String>> + 'static,
643 {
644 let (canonical, signature) = self.resolve_signature(name)?;
645 let signature = signature.clone();
646 if !Args::matches_signature(&signature.params) {
647 return Err(LustError::TypeError {
648 message: format!(
649 "Native '{}' argument types do not match Lust signature",
650 name
651 ),
652 });
653 }
654
655 ensure_return_type::<R>(name, &signature.return_type)?;
656 let registry = self.async_registry.clone();
657 let handler = move |values: &[Value]| -> std::result::Result<NativeCallResult, String> {
658 let args = Args::from_values(values)?;
659 let future = func(args);
660 let mapped = async move {
661 match future.await {
662 Ok(result) => Ok(result.into_value()),
663 Err(err) => Err(err),
664 }
665 };
666 let future: AsyncValueFuture = Box::pin(mapped);
667 VM::with_current(|vm| {
668 let handle = vm
669 .current_task_handle()
670 .ok_or_else(|| "Async native functions require a running task".to_string())?;
671 registry.borrow_mut().register(handle, future)?;
672 Ok(NativeCallResult::Yield(Value::Nil))
673 })
674 };
675 self.register_native_with_aliases(name, canonical, handler);
676 Ok(())
677 }
678
679 pub fn call_typed<Args, R>(&mut self, function_name: &str, args: Args) -> Result<R>
680 where
681 Args: FunctionArgs,
682 R: FromLustValue,
683 {
684 let signature = self
685 .signatures
686 .get(function_name)
687 .ok_or_else(|| LustError::TypeError {
688 message: format!(
689 "No type information available for function '{}'; \
690 use call_raw if the function is dynamically typed",
691 function_name
692 ),
693 })?;
694 Args::validate_signature(function_name, &signature.params)?;
695 ensure_return_type::<R>(function_name, &signature.return_type)?;
696 let values = args.into_values();
697 let value = self.vm.call(function_name, values)?;
698 R::from_value(value)
699 }
700
701 pub fn call_raw(&mut self, function_name: &str, args: Vec<Value>) -> Result<Value> {
702 self.vm.call(function_name, args)
703 }
704
705 pub fn run_entry_script(&mut self) -> Result<()> {
706 let Some(entry) = &self.entry_script else {
707 return Err(LustError::RuntimeError {
708 message: "Embedded program has no entry script".into(),
709 });
710 };
711 let result = self.vm.call(entry, Vec::new())?;
712 match result {
713 Value::Nil => Ok(()),
714 other => Err(LustError::RuntimeError {
715 message: format!(
716 "Entry script '{}' returned non-unit value: {:?}",
717 entry, other
718 ),
719 }),
720 }
721 }
722
723 pub fn poll_async_tasks(&mut self) -> Result<()> {
724 let pending_ids: Vec<u64> = {
725 let registry = self.async_registry.borrow();
726 registry.pending.keys().copied().collect()
727 };
728
729 let mut completions: Vec<(TaskHandle, std::result::Result<Value, String>)> = Vec::new();
730 for id in pending_ids {
731 let handle = TaskHandle(id);
732 if self.vm.get_task_instance(handle).is_err() {
733 self.async_registry.borrow_mut().pending.remove(&id);
734 continue;
735 }
736
737 let maybe_outcome = {
738 let mut registry = self.async_registry.borrow_mut();
739 let entry = match registry.pending.get_mut(&id) {
740 Some(entry) => entry,
741 None => continue,
742 };
743
744 if !entry.take_should_poll() {
745 continue;
746 }
747
748 let waker = entry.make_waker();
749 let mut cx = Context::from_waker(&waker);
750 match entry.future.as_mut().poll(&mut cx) {
751 Poll::Ready(result) => {
752 let handle = entry.handle;
753 registry.pending.remove(&id);
754 Some((handle, result))
755 }
756
757 Poll::Pending => None,
758 }
759 };
760
761 if let Some(outcome) = maybe_outcome {
762 completions.push(outcome);
763 }
764 }
765
766 for (handle, outcome) in completions {
767 match outcome {
768 Ok(value) => {
769 self.vm.resume_task_handle(handle, Some(value))?;
770 }
771
772 Err(message) => {
773 self.vm.fail_task_handle(
774 handle,
775 LustError::RuntimeError { message },
776 )?;
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
946#[derive(Clone)]
947pub struct StructInstance {
948 type_name: String,
949 value: Value,
950}
951
952impl StructInstance {
953 fn new(type_name: String, value: Value) -> Self {
954 debug_assert!(matches!(value, Value::Struct { .. }));
955 Self { type_name, value }
956 }
957
958 pub fn type_name(&self) -> &str {
959 &self.type_name
960 }
961
962 pub fn field<T: FromLustValue>(&self, field: &str) -> Result<T> {
963 match &self.value {
964 Value::Struct { layout, fields, .. } => {
965 let index = layout
966 .index_of_str(field)
967 .ok_or_else(|| LustError::RuntimeError {
968 message: format!(
969 "Struct '{}' has no field named '{}'",
970 self.type_name, field
971 ),
972 })?;
973 let stored =
974 fields
975 .borrow()
976 .get(index)
977 .cloned()
978 .ok_or_else(|| LustError::RuntimeError {
979 message: format!(
980 "Struct '{}' field '{}' is unavailable",
981 self.type_name, field
982 ),
983 })?;
984 let materialized = layout.materialize_field_value(index, stored);
985 T::from_value(materialized)
986 }
987
988 _ => Err(LustError::RuntimeError {
989 message: "StructInstance does not contain a struct value".to_string(),
990 }),
991 }
992 }
993
994 pub fn as_value(&self) -> &Value {
995 &self.value
996 }
997}
998
999#[derive(Clone)]
1000pub struct EnumInstance {
1001 type_name: String,
1002 variant: String,
1003 value: Value,
1004}
1005
1006impl EnumInstance {
1007 fn new(type_name: String, variant: String, value: Value) -> Self {
1008 debug_assert!(matches!(value, Value::Enum { .. }));
1009 Self {
1010 type_name,
1011 variant,
1012 value,
1013 }
1014 }
1015
1016 pub fn type_name(&self) -> &str {
1017 &self.type_name
1018 }
1019
1020 pub fn variant(&self) -> &str {
1021 &self.variant
1022 }
1023
1024 pub fn payload_len(&self) -> usize {
1025 match &self.value {
1026 Value::Enum { values, .. } => values.as_ref().map(|v| v.len()).unwrap_or(0),
1027 _ => 0,
1028 }
1029 }
1030
1031 pub fn payload<T: FromLustValue>(&self, index: usize) -> Result<T> {
1032 match &self.value {
1033 Value::Enum { values, .. } => {
1034 let values = values.as_ref().ok_or_else(|| LustError::RuntimeError {
1035 message: format!(
1036 "Enum variant '{}.{}' carries no payload",
1037 self.type_name, self.variant
1038 ),
1039 })?;
1040 let stored = values
1041 .get(index)
1042 .cloned()
1043 .ok_or_else(|| LustError::RuntimeError {
1044 message: format!(
1045 "Enum variant '{}.{}' payload index {} is out of bounds",
1046 self.type_name, self.variant, index
1047 ),
1048 })?;
1049 T::from_value(stored)
1050 }
1051
1052 _ => Err(LustError::RuntimeError {
1053 message: "EnumInstance does not contain an enum value".to_string(),
1054 }),
1055 }
1056 }
1057
1058 pub fn as_value(&self) -> &Value {
1059 &self.value
1060 }
1061}
1062
1063pub trait IntoTypedValue {
1064 fn into_typed_value(self) -> TypedValue;
1065}
1066
1067impl IntoTypedValue for Value {
1068 fn into_typed_value(self) -> TypedValue {
1069 TypedValue::new(self, |_value, _ty| true, "Value")
1070 }
1071}
1072
1073impl IntoTypedValue for StructInstance {
1074 fn into_typed_value(self) -> TypedValue {
1075 let StructInstance {
1076 type_name: _,
1077 value,
1078 } = self;
1079 TypedValue::new(value, |v, ty| matches_lust_struct(v, ty), "struct")
1080 }
1081}
1082
1083impl IntoTypedValue for EnumInstance {
1084 fn into_typed_value(self) -> TypedValue {
1085 let EnumInstance {
1086 type_name: _,
1087 variant: _,
1088 value,
1089 } = self;
1090 TypedValue::new(value, |v, ty| matches_lust_enum(v, ty), "enum")
1091 }
1092}
1093
1094macro_rules! impl_into_typed_for_primitive {
1095 ($ty:ty, $desc:expr, $matcher:expr) => {
1096 impl IntoTypedValue for $ty {
1097 fn into_typed_value(self) -> TypedValue {
1098 let value = self.into_value();
1099 TypedValue::new(value, $matcher, $desc)
1100 }
1101 }
1102 };
1103}
1104
1105impl_into_typed_for_primitive!(LustInt, "int", |_, ty: &Type| match &ty.kind {
1106 TypeKind::Int | TypeKind::Unknown => true,
1107 TypeKind::Union(types) => types
1108 .iter()
1109 .any(|alt| matches!(&alt.kind, TypeKind::Int | TypeKind::Unknown)),
1110 _ => false,
1111});
1112impl_into_typed_for_primitive!(LustFloat, "float", |_, ty: &Type| match &ty.kind {
1113 TypeKind::Float | TypeKind::Unknown => true,
1114 TypeKind::Union(types) => types
1115 .iter()
1116 .any(|alt| matches!(&alt.kind, TypeKind::Float | TypeKind::Unknown)),
1117 _ => false,
1118});
1119impl_into_typed_for_primitive!(bool, "bool", |_, ty: &Type| match &ty.kind {
1120 TypeKind::Bool | TypeKind::Unknown => true,
1121 TypeKind::Union(types) => types
1122 .iter()
1123 .any(|alt| matches!(&alt.kind, TypeKind::Bool | TypeKind::Unknown)),
1124 _ => false,
1125});
1126impl IntoTypedValue for String {
1127 fn into_typed_value(self) -> TypedValue {
1128 let value = self.into_value();
1129 TypedValue::new(value, string_matcher, "string")
1130 }
1131}
1132
1133impl<'a> IntoTypedValue for &'a str {
1134 fn into_typed_value(self) -> TypedValue {
1135 let value = self.into_value();
1136 TypedValue::new(value, string_matcher, "string")
1137 }
1138}
1139
1140impl<'a> IntoTypedValue for &'a String {
1141 fn into_typed_value(self) -> TypedValue {
1142 let value = self.into_value();
1143 TypedValue::new(value, string_matcher, "string")
1144 }
1145}
1146
1147impl IntoTypedValue for () {
1148 fn into_typed_value(self) -> TypedValue {
1149 TypedValue::new(
1150 Value::Nil,
1151 |_, ty| matches!(ty.kind, TypeKind::Unit | TypeKind::Unknown),
1152 "unit",
1153 )
1154 }
1155}
1156
1157impl<T> IntoTypedValue for Vec<T>
1158where
1159 T: IntoLustValue,
1160{
1161 fn into_typed_value(self) -> TypedValue {
1162 let values = self.into_iter().map(|item| item.into_value()).collect();
1163 TypedValue::new(
1164 Value::array(values),
1165 |_, ty| matches_array_type(ty, &T::matches_lust_type),
1166 "array",
1167 )
1168 }
1169}
1170
1171fn string_matcher(_: &Value, ty: &Type) -> bool {
1172 match &ty.kind {
1173 TypeKind::String | TypeKind::Unknown => true,
1174 TypeKind::Union(types) => types
1175 .iter()
1176 .any(|alt| matches!(&alt.kind, TypeKind::String | TypeKind::Unknown)),
1177 _ => false,
1178 }
1179}
1180
1181#[cfg(test)]
1182mod tests {
1183 use super::*;
1184 use std::future::Future;
1185 use std::pin::Pin;
1186 use std::sync::{Arc, Mutex};
1187 use std::task::{Context, Poll, Waker};
1188
1189 #[derive(Default)]
1190 struct ManualAsyncState {
1191 result: Mutex<Option<std::result::Result<LustInt, String>>>,
1192 waker: Mutex<Option<Waker>>,
1193 }
1194
1195 impl ManualAsyncState {
1196 fn new() -> Arc<Self> {
1197 Arc::new(Self::default())
1198 }
1199
1200 fn future(self: &Arc<Self>) -> ManualFuture {
1201 ManualFuture {
1202 state: Arc::clone(self),
1203 }
1204 }
1205
1206 fn complete_ok(&self, value: LustInt) {
1207 self.complete(Ok(value));
1208 }
1209
1210 fn complete_err(&self, message: impl Into<String>) {
1211 self.complete(Err(message.into()));
1212 }
1213
1214 fn complete(&self, value: std::result::Result<LustInt, String>) {
1215 {
1216 let mut slot = self.result.lock().unwrap();
1217 *slot = Some(value);
1218 }
1219
1220 if let Some(waker) = self.waker.lock().unwrap().take() {
1221 waker.wake();
1222 }
1223 }
1224 }
1225
1226 struct ManualFuture {
1227 state: Arc<ManualAsyncState>,
1228 }
1229
1230 impl Future for ManualFuture {
1231 type Output = std::result::Result<LustInt, String>;
1232
1233 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1234 {
1235 let mut slot = self.state.result.lock().unwrap();
1236 if let Some(result) = slot.take() {
1237 return Poll::Ready(result);
1238 }
1239 }
1240
1241 let mut waker_slot = self.state.waker.lock().unwrap();
1242 *waker_slot = Some(cx.waker().clone());
1243 Poll::Pending
1244 }
1245 }
1246
1247 fn build_program(source: &str) -> EmbeddedProgram {
1248 EmbeddedProgram::builder()
1249 .module("main", source)
1250 .entry_module("main")
1251 .compile()
1252 .expect("compile embedded program")
1253 }
1254
1255 #[test]
1256 fn async_native_resumes_task_on_completion() {
1257 let source = r#"
1258 extern {
1259 function fetch_value(): int
1260 }
1261
1262 function compute(): int
1263 return fetch_value()
1264 end
1265 "#;
1266
1267 let mut program = build_program(source);
1268
1269 let state = ManualAsyncState::new();
1270 let register_state = Arc::clone(&state);
1271 program
1272 .register_async_typed_native::<(), LustInt, _, _>("fetch_value", move |_| {
1273 register_state.future()
1274 })
1275 .expect("register async native");
1276
1277 let handle = {
1278 let vm = program.vm_mut();
1279 let compute_fn = vm
1280 .function_value("main.compute")
1281 .expect("compute function");
1282 vm.spawn_task_value(compute_fn, Vec::new())
1283 .expect("spawn task")
1284 };
1285
1286 assert!(program.has_pending_async_tasks());
1287 program.poll_async_tasks().expect("initial poll");
1288 assert!(program.has_pending_async_tasks());
1289
1290 state.complete_ok(123);
1291 program
1292 .poll_async_tasks()
1293 .expect("resume after completion");
1294
1295 {
1296 let vm = program.vm_mut();
1297 let task = vm.get_task_instance(handle).expect("task exists");
1298 let result = task
1299 .last_result
1300 .as_ref()
1301 .and_then(|value| value.as_int())
1302 .expect("task produced result");
1303 assert_eq!(result, 123);
1304 assert!(task.error.is_none());
1305 }
1306
1307 assert!(!program.has_pending_async_tasks());
1308 }
1309
1310 #[test]
1311 fn async_native_failure_marks_task_failed() {
1312 let source = r#"
1313 extern {
1314 function fetch_value(): int
1315 }
1316
1317 function compute(): int
1318 return fetch_value()
1319 end
1320 "#;
1321
1322 let mut program = build_program(source);
1323
1324 let state = ManualAsyncState::new();
1325 let register_state = Arc::clone(&state);
1326 program
1327 .register_async_typed_native::<(), LustInt, _, _>("fetch_value", move |_| {
1328 register_state.future()
1329 })
1330 .expect("register async native");
1331
1332 let handle = {
1333 let vm = program.vm_mut();
1334 let compute_fn = vm
1335 .function_value("main.compute")
1336 .expect("compute function");
1337 vm.spawn_task_value(compute_fn, Vec::new())
1338 .expect("spawn task")
1339 };
1340
1341 program.poll_async_tasks().expect("initial poll");
1342 state.complete_err("boom");
1343 let err = program
1344 .poll_async_tasks()
1345 .expect_err("poll should propagate failure");
1346 match err {
1347 LustError::RuntimeError { message } => assert_eq!(message, "boom"),
1348 other => panic!("unexpected error: {other:?}"),
1349 }
1350
1351 {
1352 let vm = program.vm_mut();
1353 let task = vm.get_task_instance(handle).expect("task exists");
1354 assert!(task.last_result.is_none());
1355 let error_message = task
1356 .error
1357 .as_ref()
1358 .map(|e| e.to_string())
1359 .expect("task should record error");
1360 assert!(error_message.contains("boom"));
1361 }
1362
1363 assert!(!program.has_pending_async_tasks());
1364 }
1365}
1366
1367fn matches_lust_struct(value: &Value, ty: &Type) -> bool {
1368 match (value, &ty.kind) {
1369 (Value::Struct { name, .. }, TypeKind::Named(expected)) => name == expected,
1370 (Value::Struct { name, .. }, TypeKind::GenericInstance { name: expected, .. }) => {
1371 name == expected
1372 }
1373
1374 (value, TypeKind::Union(types)) => types.iter().any(|alt| matches_lust_struct(value, alt)),
1375 (_, TypeKind::Unknown) => true,
1376 _ => false,
1377 }
1378}
1379
1380fn matches_lust_enum(value: &Value, ty: &Type) -> bool {
1381 match (value, &ty.kind) {
1382 (Value::Enum { enum_name, .. }, TypeKind::Named(expected)) => enum_name == expected,
1383 (Value::Enum { enum_name, .. }, TypeKind::GenericInstance { name: expected, .. }) => {
1384 enum_name == expected
1385 }
1386
1387 (value, TypeKind::Union(types)) => types.iter().any(|alt| matches_lust_enum(value, alt)),
1388 (_, TypeKind::Unknown) => true,
1389 _ => false,
1390 }
1391}
1392
1393fn matches_array_type<F>(ty: &Type, matcher: &F) -> bool
1394where
1395 F: Fn(&Type) -> bool,
1396{
1397 match &ty.kind {
1398 TypeKind::Array(inner) => matcher(inner),
1399 TypeKind::Unknown => true,
1400 TypeKind::Union(types) => types.iter().any(|alt| matches_array_type(alt, matcher)),
1401 _ => false,
1402 }
1403}
1404
1405pub trait FromLustArgs: Sized {
1406 fn from_values(values: &[Value]) -> std::result::Result<Self, String>;
1407 fn matches_signature(params: &[Type]) -> bool;
1408}
1409
1410macro_rules! impl_from_lust_args_tuple {
1411 ($( $name:ident ),+) => {
1412 impl<$($name),+> FromLustArgs for ($($name,)+)
1413 where
1414 $($name: FromLustValue,)+
1415 {
1416 fn from_values(values: &[Value]) -> std::result::Result<Self, String> {
1417 let expected = count_idents!($($name),+);
1418 if values.len() != expected {
1419 return Err(format!(
1420 "Native function expected {} argument(s) but received {}",
1421 expected,
1422 values.len()
1423 ));
1424 }
1425
1426 let mut idx = 0;
1427 let result = (
1428 $(
1429 {
1430 let value = $name::from_value(values[idx].clone()).map_err(|e| e.to_string())?;
1431 idx += 1;
1432 value
1433 },
1434 )+
1435 );
1436 let _ = idx;
1437 Ok(result)
1438 }
1439
1440 fn matches_signature(params: &[Type]) -> bool {
1441 let expected = count_idents!($($name),+);
1442 params.len() == expected && {
1443 let mut idx = 0;
1444 let mut ok = true;
1445 $(
1446 if ok && !$name::matches_lust_type(¶ms[idx]) {
1447 ok = false;
1448 }
1449
1450 idx += 1;
1451 )+
1452 let _ = idx;
1453 ok
1454 }
1455
1456 }
1457
1458 }
1459
1460 };
1461}
1462
1463macro_rules! count_idents {
1464 ($($name:ident),*) => {
1465 <[()]>::len(&[$(count_idents!(@sub $name)),*])
1466 };
1467 (@sub $name:ident) => { () };
1468}
1469
1470impl_from_lust_args_tuple!(A);
1471impl_from_lust_args_tuple!(A, B);
1472impl_from_lust_args_tuple!(A, B, C);
1473impl_from_lust_args_tuple!(A, B, C, D);
1474impl_from_lust_args_tuple!(A, B, C, D, E);
1475impl<T> FromLustArgs for T
1476where
1477 T: FromLustValue,
1478{
1479 fn from_values(values: &[Value]) -> std::result::Result<Self, String> {
1480 match values.len() {
1481 0 => T::from_value(Value::Nil).map_err(|e| e.to_string()),
1482 1 => T::from_value(values[0].clone()).map_err(|e| e.to_string()),
1483 count => Err(format!(
1484 "Native function expected 1 argument but received {}",
1485 count
1486 )),
1487 }
1488 }
1489
1490 fn matches_signature(params: &[Type]) -> bool {
1491 if params.is_empty() {
1492 let unit = Type::new(TypeKind::Unit, Span::new(0, 0, 0, 0));
1493 return T::matches_lust_type(&unit);
1494 }
1495
1496 params.len() == 1 && T::matches_lust_type(¶ms[0])
1497 }
1498}
1499
1500pub trait IntoLustValue: Sized {
1501 fn into_value(self) -> Value;
1502 fn matches_lust_type(ty: &Type) -> bool;
1503 fn type_description() -> &'static str;
1504}
1505
1506pub trait FromLustValue: Sized {
1507 fn from_value(value: Value) -> Result<Self>;
1508 fn matches_lust_type(ty: &Type) -> bool;
1509 fn type_description() -> &'static str;
1510}
1511
1512pub trait FunctionArgs {
1513 fn into_values(self) -> Vec<Value>;
1514 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()>;
1515}
1516
1517impl IntoLustValue for Value {
1518 fn into_value(self) -> Value {
1519 self
1520 }
1521
1522 fn matches_lust_type(_: &Type) -> bool {
1523 true
1524 }
1525
1526 fn type_description() -> &'static str {
1527 "Value"
1528 }
1529}
1530
1531impl FromLustValue for Value {
1532 fn from_value(value: Value) -> Result<Self> {
1533 Ok(value)
1534 }
1535
1536 fn matches_lust_type(_: &Type) -> bool {
1537 true
1538 }
1539
1540 fn type_description() -> &'static str {
1541 "Value"
1542 }
1543}
1544
1545impl IntoLustValue for LustInt {
1546 fn into_value(self) -> Value {
1547 Value::Int(self)
1548 }
1549
1550 fn matches_lust_type(ty: &Type) -> bool {
1551 matches!(ty.kind, TypeKind::Int | TypeKind::Unknown)
1552 }
1553
1554 fn type_description() -> &'static str {
1555 "int"
1556 }
1557}
1558
1559impl FromLustValue for LustInt {
1560 fn from_value(value: Value) -> Result<Self> {
1561 match value {
1562 Value::Int(v) => Ok(v),
1563 other => Err(LustError::RuntimeError {
1564 message: format!("Expected Lust value 'int' but received '{:?}'", other),
1565 }),
1566 }
1567 }
1568
1569 fn matches_lust_type(ty: &Type) -> bool {
1570 matches!(ty.kind, TypeKind::Int | TypeKind::Unknown)
1571 }
1572
1573 fn type_description() -> &'static str {
1574 "int"
1575 }
1576}
1577
1578impl IntoLustValue for LustFloat {
1579 fn into_value(self) -> Value {
1580 Value::Float(self)
1581 }
1582
1583 fn matches_lust_type(ty: &Type) -> bool {
1584 matches!(ty.kind, TypeKind::Float | TypeKind::Unknown)
1585 }
1586
1587 fn type_description() -> &'static str {
1588 "float"
1589 }
1590}
1591
1592impl FromLustValue for LustFloat {
1593 fn from_value(value: Value) -> Result<Self> {
1594 match value {
1595 Value::Float(v) => Ok(v),
1596 other => Err(LustError::RuntimeError {
1597 message: format!("Expected Lust value 'float' but received '{:?}'", other),
1598 }),
1599 }
1600 }
1601
1602 fn matches_lust_type(ty: &Type) -> bool {
1603 matches!(ty.kind, TypeKind::Float | TypeKind::Unknown)
1604 }
1605
1606 fn type_description() -> &'static str {
1607 "float"
1608 }
1609}
1610
1611impl IntoLustValue for bool {
1612 fn into_value(self) -> Value {
1613 Value::Bool(self)
1614 }
1615
1616 fn matches_lust_type(ty: &Type) -> bool {
1617 matches!(ty.kind, TypeKind::Bool | TypeKind::Unknown)
1618 }
1619
1620 fn type_description() -> &'static str {
1621 "bool"
1622 }
1623}
1624
1625impl FromLustValue for bool {
1626 fn from_value(value: Value) -> Result<Self> {
1627 match value {
1628 Value::Bool(b) => Ok(b),
1629 other => Err(LustError::RuntimeError {
1630 message: format!("Expected Lust value 'bool' but received '{:?}'", other),
1631 }),
1632 }
1633 }
1634
1635 fn matches_lust_type(ty: &Type) -> bool {
1636 matches!(ty.kind, TypeKind::Bool | TypeKind::Unknown)
1637 }
1638
1639 fn type_description() -> &'static str {
1640 "bool"
1641 }
1642}
1643
1644impl IntoLustValue for String {
1645 fn into_value(self) -> Value {
1646 Value::String(Rc::new(self))
1647 }
1648
1649 fn matches_lust_type(ty: &Type) -> bool {
1650 matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
1651 }
1652
1653 fn type_description() -> &'static str {
1654 "string"
1655 }
1656}
1657
1658impl IntoLustValue for StructInstance {
1659 fn into_value(self) -> Value {
1660 self.value
1661 }
1662
1663 fn matches_lust_type(ty: &Type) -> bool {
1664 match &ty.kind {
1665 TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
1666 TypeKind::Union(types) => types
1667 .iter()
1668 .any(|alt| <Self as IntoLustValue>::matches_lust_type(alt)),
1669 _ => false,
1670 }
1671 }
1672
1673 fn type_description() -> &'static str {
1674 "struct"
1675 }
1676}
1677
1678impl FromLustValue for StructInstance {
1679 fn from_value(value: Value) -> Result<Self> {
1680 match &value {
1681 Value::Struct { name, .. } => Ok(StructInstance {
1682 type_name: name.clone(),
1683 value,
1684 }),
1685 other => Err(LustError::RuntimeError {
1686 message: format!("Expected Lust value 'struct' but received '{:?}'", other),
1687 }),
1688 }
1689 }
1690
1691 fn matches_lust_type(ty: &Type) -> bool {
1692 match &ty.kind {
1693 TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
1694 TypeKind::Union(types) => types
1695 .iter()
1696 .any(|alt| <Self as FromLustValue>::matches_lust_type(alt)),
1697 _ => false,
1698 }
1699 }
1700
1701 fn type_description() -> &'static str {
1702 "struct"
1703 }
1704}
1705
1706impl IntoLustValue for EnumInstance {
1707 fn into_value(self) -> Value {
1708 self.value
1709 }
1710
1711 fn matches_lust_type(ty: &Type) -> bool {
1712 match &ty.kind {
1713 TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
1714 TypeKind::Union(types) => types
1715 .iter()
1716 .any(|alt| <Self as IntoLustValue>::matches_lust_type(alt)),
1717 _ => false,
1718 }
1719 }
1720
1721 fn type_description() -> &'static str {
1722 "enum"
1723 }
1724}
1725
1726impl FromLustValue for EnumInstance {
1727 fn from_value(value: Value) -> Result<Self> {
1728 match &value {
1729 Value::Enum {
1730 enum_name, variant, ..
1731 } => Ok(EnumInstance {
1732 type_name: enum_name.clone(),
1733 variant: variant.clone(),
1734 value,
1735 }),
1736 other => Err(LustError::RuntimeError {
1737 message: format!("Expected Lust value 'enum' but received '{:?}'", other),
1738 }),
1739 }
1740 }
1741
1742 fn matches_lust_type(ty: &Type) -> bool {
1743 match &ty.kind {
1744 TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
1745 TypeKind::Union(types) => types
1746 .iter()
1747 .any(|alt| <Self as FromLustValue>::matches_lust_type(alt)),
1748 _ => false,
1749 }
1750 }
1751
1752 fn type_description() -> &'static str {
1753 "enum"
1754 }
1755}
1756
1757impl<T> IntoLustValue for Vec<T>
1758where
1759 T: IntoLustValue,
1760{
1761 fn into_value(self) -> Value {
1762 let values = self.into_iter().map(|item| item.into_value()).collect();
1763 Value::array(values)
1764 }
1765
1766 fn matches_lust_type(ty: &Type) -> bool {
1767 matches_array_type(ty, &T::matches_lust_type)
1768 }
1769
1770 fn type_description() -> &'static str {
1771 "array"
1772 }
1773}
1774
1775impl<T> FromLustValue for Vec<T>
1776where
1777 T: FromLustValue,
1778{
1779 fn from_value(value: Value) -> Result<Self> {
1780 match value {
1781 Value::Array(items) => {
1782 let borrowed = items.borrow();
1783 let mut result = Vec::with_capacity(borrowed.len());
1784 for item in borrowed.iter() {
1785 result.push(T::from_value(item.clone())?);
1786 }
1787
1788 Ok(result)
1789 }
1790
1791 other => Err(LustError::RuntimeError {
1792 message: format!("Expected Lust value 'array' but received '{:?}'", other),
1793 }),
1794 }
1795 }
1796
1797 fn matches_lust_type(ty: &Type) -> bool {
1798 matches_array_type(ty, &T::matches_lust_type)
1799 }
1800
1801 fn type_description() -> &'static str {
1802 "array"
1803 }
1804}
1805
1806impl<'a> IntoLustValue for &'a str {
1807 fn into_value(self) -> Value {
1808 Value::String(Rc::new(self.to_owned()))
1809 }
1810
1811 fn matches_lust_type(ty: &Type) -> bool {
1812 matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
1813 }
1814
1815 fn type_description() -> &'static str {
1816 "string"
1817 }
1818}
1819
1820impl<'a> IntoLustValue for &'a String {
1821 fn into_value(self) -> Value {
1822 Value::String(Rc::new(self.clone()))
1823 }
1824
1825 fn matches_lust_type(ty: &Type) -> bool {
1826 matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
1827 }
1828
1829 fn type_description() -> &'static str {
1830 "string"
1831 }
1832}
1833
1834impl FromLustValue for String {
1835 fn from_value(value: Value) -> Result<Self> {
1836 match value {
1837 Value::String(s) => Ok((*s).clone()),
1838 other => Err(LustError::RuntimeError {
1839 message: format!("Expected Lust value 'string' but received '{:?}'", other),
1840 }),
1841 }
1842 }
1843
1844 fn matches_lust_type(ty: &Type) -> bool {
1845 matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
1846 }
1847
1848 fn type_description() -> &'static str {
1849 "string"
1850 }
1851}
1852
1853impl FromLustValue for () {
1854 fn from_value(value: Value) -> Result<Self> {
1855 match value {
1856 Value::Nil => Ok(()),
1857 other => Err(LustError::RuntimeError {
1858 message: format!("Expected Lust value 'unit' but received '{:?}'", other),
1859 }),
1860 }
1861 }
1862
1863 fn matches_lust_type(ty: &Type) -> bool {
1864 matches!(ty.kind, TypeKind::Unit | TypeKind::Unknown)
1865 }
1866
1867 fn type_description() -> &'static str {
1868 "unit"
1869 }
1870}
1871
1872impl FunctionArgs for () {
1873 fn into_values(self) -> Vec<Value> {
1874 Vec::new()
1875 }
1876
1877 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
1878 ensure_arity(function_name, params, 0)
1879 }
1880}
1881
1882impl<T> FunctionArgs for T
1883where
1884 T: IntoLustValue,
1885{
1886 fn into_values(self) -> Vec<Value> {
1887 vec![self.into_value()]
1888 }
1889
1890 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
1891 ensure_arity(function_name, params, 1)?;
1892 ensure_arg_type::<T>(function_name, params, 0)
1893 }
1894}
1895
1896impl<A, B> FunctionArgs for (A, B)
1897where
1898 A: IntoLustValue,
1899 B: IntoLustValue,
1900{
1901 fn into_values(self) -> Vec<Value> {
1902 vec![self.0.into_value(), self.1.into_value()]
1903 }
1904
1905 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
1906 ensure_arity(function_name, params, 2)?;
1907 ensure_arg_type::<A>(function_name, params, 0)?;
1908 ensure_arg_type::<B>(function_name, params, 1)?;
1909 Ok(())
1910 }
1911}
1912
1913impl<A, B, C> FunctionArgs for (A, B, C)
1914where
1915 A: IntoLustValue,
1916 B: IntoLustValue,
1917 C: IntoLustValue,
1918{
1919 fn into_values(self) -> Vec<Value> {
1920 vec![
1921 self.0.into_value(),
1922 self.1.into_value(),
1923 self.2.into_value(),
1924 ]
1925 }
1926
1927 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
1928 ensure_arity(function_name, params, 3)?;
1929 ensure_arg_type::<A>(function_name, params, 0)?;
1930 ensure_arg_type::<B>(function_name, params, 1)?;
1931 ensure_arg_type::<C>(function_name, params, 2)?;
1932 Ok(())
1933 }
1934}
1935
1936impl<A, B, C, D> FunctionArgs for (A, B, C, D)
1937where
1938 A: IntoLustValue,
1939 B: IntoLustValue,
1940 C: IntoLustValue,
1941 D: IntoLustValue,
1942{
1943 fn into_values(self) -> Vec<Value> {
1944 vec![
1945 self.0.into_value(),
1946 self.1.into_value(),
1947 self.2.into_value(),
1948 self.3.into_value(),
1949 ]
1950 }
1951
1952 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
1953 ensure_arity(function_name, params, 4)?;
1954 ensure_arg_type::<A>(function_name, params, 0)?;
1955 ensure_arg_type::<B>(function_name, params, 1)?;
1956 ensure_arg_type::<C>(function_name, params, 2)?;
1957 ensure_arg_type::<D>(function_name, params, 3)?;
1958 Ok(())
1959 }
1960}
1961
1962impl<A, B, C, D, E> FunctionArgs for (A, B, C, D, E)
1963where
1964 A: IntoLustValue,
1965 B: IntoLustValue,
1966 C: IntoLustValue,
1967 D: IntoLustValue,
1968 E: IntoLustValue,
1969{
1970 fn into_values(self) -> Vec<Value> {
1971 vec![
1972 self.0.into_value(),
1973 self.1.into_value(),
1974 self.2.into_value(),
1975 self.3.into_value(),
1976 self.4.into_value(),
1977 ]
1978 }
1979
1980 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
1981 ensure_arity(function_name, params, 5)?;
1982 ensure_arg_type::<A>(function_name, params, 0)?;
1983 ensure_arg_type::<B>(function_name, params, 1)?;
1984 ensure_arg_type::<C>(function_name, params, 2)?;
1985 ensure_arg_type::<D>(function_name, params, 3)?;
1986 ensure_arg_type::<E>(function_name, params, 4)?;
1987 Ok(())
1988 }
1989}
1990
1991fn ensure_arity(function_name: &str, params: &[Type], provided: usize) -> Result<()> {
1992 if params.len() == provided {
1993 Ok(())
1994 } else {
1995 Err(LustError::TypeError {
1996 message: format!(
1997 "Function '{}' expects {} argument(s) but {} were supplied",
1998 function_name,
1999 params.len(),
2000 provided
2001 ),
2002 })
2003 }
2004}
2005
2006fn ensure_arg_type<T: IntoLustValue>(
2007 function_name: &str,
2008 params: &[Type],
2009 index: usize,
2010) -> Result<()> {
2011 if <T as IntoLustValue>::matches_lust_type(¶ms[index]) {
2012 Ok(())
2013 } else {
2014 Err(argument_type_mismatch(
2015 function_name,
2016 index,
2017 <T as IntoLustValue>::type_description(),
2018 ¶ms[index],
2019 ))
2020 }
2021}
2022
2023fn argument_type_mismatch(
2024 function_name: &str,
2025 index: usize,
2026 rust_type: &str,
2027 lust_type: &Type,
2028) -> LustError {
2029 LustError::TypeError {
2030 message: format!(
2031 "Function '{}' parameter {} expects Lust type '{}' but Rust provided '{}'",
2032 function_name,
2033 index + 1,
2034 lust_type,
2035 rust_type
2036 ),
2037 }
2038}