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