1use crate::ast::{EnumDef, FieldOwnership, Item, ItemKind, Span, StructDef, Type, TypeKind};
2use crate::bytecode::{Compiler, NativeCallResult, Value};
3use crate::modules::{ModuleImports, ModuleLoader};
4use crate::typechecker::{FunctionSignature, TypeChecker};
5use crate::vm::VM;
6use crate::{LustConfig, LustError, Result};
7use std::collections::HashMap;
8use std::path::{Path, PathBuf};
9use std::rc::Rc;
10pub struct EmbeddedBuilder {
11 base_dir: PathBuf,
12 modules: HashMap<String, String>,
13 entry_module: Option<String>,
14 config: LustConfig,
15}
16
17impl Default for EmbeddedBuilder {
18 fn default() -> Self {
19 Self {
20 base_dir: PathBuf::from("__embedded__"),
21 modules: HashMap::new(),
22 entry_module: None,
23 config: LustConfig::default(),
24 }
25 }
26}
27
28impl EmbeddedBuilder {
29 pub fn new() -> Self {
30 Self::default()
31 }
32
33 pub fn with_base_dir(self, base_dir: impl Into<PathBuf>) -> Self {
34 self.set_base_dir(base_dir)
35 }
36
37 pub fn set_base_dir(mut self, base_dir: impl Into<PathBuf>) -> Self {
38 self.base_dir = base_dir.into();
39 self
40 }
41
42 pub fn module(mut self, module_path: impl Into<String>, source: impl Into<String>) -> Self {
43 self.modules.insert(module_path.into(), source.into());
44 self
45 }
46
47 pub fn enable_stdlib_module<S: AsRef<str>>(mut self, module: S) -> Self {
48 self.config.enable_module(module);
49 self
50 }
51
52 pub fn add_stdlib_module<S: AsRef<str>>(mut self, module: S) -> Self {
53 self.config.enable_module(module);
54 self
55 }
56
57 pub fn with_config(mut self, config: LustConfig) -> Self {
58 self.config = config;
59 self
60 }
61
62 pub fn set_config(mut self, config: LustConfig) -> Self {
63 self.config = config;
64 self
65 }
66
67 pub fn add_module(
68 &mut self,
69 module_path: impl Into<String>,
70 source: impl Into<String>,
71 ) -> &mut Self {
72 self.modules.insert(module_path.into(), source.into());
73 self
74 }
75
76 pub fn entry_module(mut self, module_path: impl Into<String>) -> Self {
77 self.set_entry_module(module_path);
78 self
79 }
80
81 pub fn set_entry_module(&mut self, module_path: impl Into<String>) -> &mut Self {
82 self.entry_module = Some(module_path.into());
83 self
84 }
85
86 pub fn compile(self) -> Result<EmbeddedProgram> {
87 let entry_module = self
88 .entry_module
89 .ok_or_else(|| LustError::Unknown("No entry module configured for embedding".into()))?;
90 let has_entry = self.modules.contains_key(&entry_module);
91 if !has_entry {
92 return Err(LustError::Unknown(format!(
93 "Entry module '{}' was not provided via EmbeddedBuilder::module",
94 entry_module
95 )));
96 }
97
98 let overrides: HashMap<PathBuf, String> = self
99 .modules
100 .into_iter()
101 .map(|(module, source)| (module_path_to_file(&self.base_dir, &module), source))
102 .collect();
103 compile_in_memory(self.base_dir, entry_module, overrides, self.config)
104 }
105}
106
107pub struct EmbeddedProgram {
108 vm: VM,
109 signatures: HashMap<String, FunctionSignature>,
110 struct_defs: HashMap<String, StructDef>,
111 enum_defs: HashMap<String, EnumDef>,
112 entry_script: Option<String>,
113}
114
115impl EmbeddedProgram {
116 pub fn builder() -> EmbeddedBuilder {
117 EmbeddedBuilder::default()
118 }
119
120 pub fn vm_mut(&mut self) -> &mut VM {
121 &mut self.vm
122 }
123
124 pub fn signature(&self, function_name: &str) -> Option<&FunctionSignature> {
125 self.signatures.get(function_name)
126 }
127
128 pub fn typed_functions(&self) -> impl Iterator<Item = (&String, &FunctionSignature)> {
129 self.signatures.iter()
130 }
131
132 pub fn struct_definition(&self, type_name: &str) -> Option<&StructDef> {
133 self.struct_defs.get(type_name)
134 }
135
136 pub fn enum_definition(&self, type_name: &str) -> Option<&EnumDef> {
137 self.enum_defs.get(type_name)
138 }
139
140 pub fn get_global_value(&self, name: &str) -> Option<Value> {
141 let normalized = normalize_global_name(name);
142 self.vm.get_global(&normalized)
143 }
144
145 pub fn get_typed_global<T: FromLustValue>(&self, name: &str) -> Result<Option<T>> {
146 let normalized = normalize_global_name(name);
147 match self.vm.get_global(&normalized) {
148 Some(value) => T::from_value(value).map(Some),
149 None => Ok(None),
150 }
151 }
152
153 pub fn set_global_value<V: IntoTypedValue>(&mut self, name: impl Into<String>, value: V) {
154 let name_string = name.into();
155 let normalized = normalize_global_name(&name_string);
156 let value = value.into_typed_value().into_value();
157 self.vm.set_global(normalized, value);
158 }
159
160 pub fn struct_instance<I, K, V>(
161 &self,
162 type_name: impl Into<String>,
163 fields: I,
164 ) -> Result<StructInstance>
165 where
166 I: IntoIterator<Item = (K, V)>,
167 K: Into<String>,
168 V: IntoTypedValue,
169 {
170 let type_name = type_name.into();
171 let def = self
172 .struct_defs
173 .get(&type_name)
174 .ok_or_else(|| LustError::TypeError {
175 message: format!("Unknown struct '{}'", type_name),
176 })?;
177 let mut provided: HashMap<String, TypedValue> = fields
178 .into_iter()
179 .map(|(name, value)| (name.into(), value.into_typed_value()))
180 .collect();
181 let mut ordered_fields: Vec<(Rc<String>, Value)> = Vec::with_capacity(def.fields.len());
182 for field in &def.fields {
183 let typed_value = provided
184 .remove(&field.name)
185 .ok_or_else(|| LustError::TypeError {
186 message: format!(
187 "Struct '{}' is missing required field '{}'",
188 type_name, field.name
189 ),
190 })?;
191 let matches_declared = typed_value.matches(&field.ty);
192 let matches_ref_inner = matches!(field.ownership, FieldOwnership::Weak)
193 && field
194 .weak_target
195 .as_ref()
196 .map(|inner| typed_value.matches(inner))
197 .unwrap_or(false);
198 if !(matches_declared || matches_ref_inner) {
199 return Err(LustError::TypeError {
200 message: format!(
201 "Struct '{}' field '{}' expects Lust type '{}' but Rust provided '{}'",
202 type_name,
203 field.name,
204 field.ty,
205 typed_value.description()
206 ),
207 });
208 }
209
210 ordered_fields.push((Rc::new(field.name.clone()), typed_value.into_value()));
211 }
212
213 if !provided.is_empty() {
214 let extra = provided.keys().cloned().collect::<Vec<_>>().join(", ");
215 return Err(LustError::TypeError {
216 message: format!(
217 "Struct '{}' received unknown field(s): {}",
218 type_name, extra
219 ),
220 });
221 }
222
223 let value = self.vm.instantiate_struct(&type_name, ordered_fields)?;
224 Ok(StructInstance::new(type_name.clone(), value))
225 }
226
227 pub fn enum_variant(
228 &self,
229 type_name: impl Into<String>,
230 variant: impl Into<String>,
231 ) -> Result<EnumInstance> {
232 self.enum_variant_with(type_name, variant, std::iter::empty::<Value>())
233 }
234
235 pub fn enum_variant_with<I, V>(
236 &self,
237 type_name: impl Into<String>,
238 variant: impl Into<String>,
239 payload: I,
240 ) -> Result<EnumInstance>
241 where
242 I: IntoIterator<Item = V>,
243 V: IntoTypedValue,
244 {
245 let type_name = type_name.into();
246 let variant_name = variant.into();
247 let def = self
248 .enum_defs
249 .get(&type_name)
250 .ok_or_else(|| LustError::TypeError {
251 message: format!("Unknown enum '{}'", type_name),
252 })?;
253 let enum_variant = def
254 .variants
255 .iter()
256 .find(|v| v.name == variant_name)
257 .ok_or_else(|| LustError::TypeError {
258 message: format!(
259 "Enum '{}' has no variant named '{}'",
260 type_name, variant_name
261 ),
262 })?;
263 let mut values: Vec<TypedValue> =
264 payload.into_iter().map(|v| v.into_typed_value()).collect();
265 let coerced_values: Option<Rc<Vec<Value>>> = match &enum_variant.fields {
266 None => {
267 if !values.is_empty() {
268 return Err(LustError::TypeError {
269 message: format!(
270 "Enum variant '{}.{}' does not accept payload values",
271 type_name, variant_name
272 ),
273 });
274 }
275
276 None
277 }
278
279 Some(field_types) => {
280 if values.len() != field_types.len() {
281 return Err(LustError::TypeError {
282 message: format!(
283 "Enum variant '{}.{}' expects {} value(s) but {} were supplied",
284 type_name,
285 variant_name,
286 field_types.len(),
287 values.len()
288 ),
289 });
290 }
291
292 let mut collected = Vec::with_capacity(field_types.len());
293 for (idx, (typed_value, field_ty)) in
294 values.drain(..).zip(field_types.iter()).enumerate()
295 {
296 if !typed_value.matches(field_ty) {
297 return Err(LustError::TypeError {
298 message: format!(
299 "Enum variant '{}.{}' field {} expects Lust type '{}' but Rust provided '{}'",
300 type_name,
301 variant_name,
302 idx + 1,
303 field_ty,
304 typed_value.description()
305 ),
306 });
307 }
308
309 collected.push(typed_value.into_value());
310 }
311
312 Some(Rc::new(collected))
313 }
314 };
315 Ok(EnumInstance::new(
316 type_name.clone(),
317 variant_name.clone(),
318 Value::Enum {
319 enum_name: type_name,
320 variant: variant_name,
321 values: coerced_values,
322 },
323 ))
324 }
325
326 pub fn register_native_fn<F>(&mut self, name: impl Into<String>, func: F)
327 where
328 F: Fn(&[Value]) -> std::result::Result<NativeCallResult, String> + 'static,
329 {
330 let native = Value::NativeFunction(Rc::new(func));
331 self.vm.register_native(name, native);
332 }
333
334 pub fn register_typed_native<Args, R, F>(&mut self, name: &str, func: F) -> Result<()>
335 where
336 Args: FromLustArgs,
337 R: IntoLustValue + FromLustValue,
338 F: Fn(Args) -> std::result::Result<R, String> + 'static,
339 {
340 let signature = self
341 .signatures
342 .get(name)
343 .ok_or_else(|| LustError::TypeError {
344 message: format!(
345 "Cannot register native '{}': function not declared in Lust source",
346 name
347 ),
348 })?;
349 if !Args::matches_signature(&signature.params) {
350 return Err(LustError::TypeError {
351 message: format!(
352 "Native '{}' argument types do not match Lust signature",
353 name
354 ),
355 });
356 }
357
358 ensure_return_type::<R>(name, &signature.return_type)?;
359 let handler = move |values: &[Value]| -> std::result::Result<NativeCallResult, String> {
360 let args = Args::from_values(values)?;
361 let result = func(args)?;
362 Ok(NativeCallResult::Return(result.into_value()))
363 };
364 self.register_native_fn(name.to_string(), handler);
365 Ok(())
366 }
367
368 pub fn call_typed<Args, R>(&mut self, function_name: &str, args: Args) -> Result<R>
369 where
370 Args: FunctionArgs,
371 R: FromLustValue,
372 {
373 let signature = self
374 .signatures
375 .get(function_name)
376 .ok_or_else(|| LustError::TypeError {
377 message: format!(
378 "No type information available for function '{}'; \
379 use call_raw if the function is dynamically typed",
380 function_name
381 ),
382 })?;
383 Args::validate_signature(function_name, &signature.params)?;
384 ensure_return_type::<R>(function_name, &signature.return_type)?;
385 let values = args.into_values();
386 let value = self.vm.call(function_name, values)?;
387 R::from_value(value)
388 }
389
390 pub fn call_raw(&mut self, function_name: &str, args: Vec<Value>) -> Result<Value> {
391 self.vm.call(function_name, args)
392 }
393
394 pub fn run_entry_script(&mut self) -> Result<()> {
395 let Some(entry) = &self.entry_script else {
396 return Err(LustError::RuntimeError {
397 message: "Embedded program has no entry script".into(),
398 });
399 };
400 let result = self.vm.call(entry, Vec::new())?;
401 match result {
402 Value::Nil => Ok(()),
403 other => Err(LustError::RuntimeError {
404 message: format!(
405 "Entry script '{}' returned non-unit value: {:?}",
406 entry, other
407 ),
408 }),
409 }
410 }
411}
412
413fn compile_in_memory(
414 base_dir: PathBuf,
415 entry_module: String,
416 overrides: HashMap<PathBuf, String>,
417 config: LustConfig,
418) -> Result<EmbeddedProgram> {
419 let mut loader = ModuleLoader::new(base_dir.clone());
420 loader.set_source_overrides(overrides);
421 let entry_path = module_path_to_file(&base_dir, &entry_module);
422 let entry_path_str = entry_path
423 .to_str()
424 .ok_or_else(|| LustError::Unknown("Entry path contained invalid UTF-8".into()))?
425 .to_string();
426 let program = loader.load_program_from_entry(&entry_path_str)?;
427 let mut imports_map: HashMap<String, ModuleImports> = HashMap::new();
428 for module in &program.modules {
429 imports_map.insert(module.path.clone(), module.imports.clone());
430 }
431
432 let mut wrapped_items: Vec<Item> = Vec::new();
433 for module in &program.modules {
434 wrapped_items.push(Item::new(
435 ItemKind::Module {
436 name: module.path.clone(),
437 items: module.items.clone(),
438 },
439 Span::new(0, 0, 0, 0),
440 ));
441 }
442
443 let mut typechecker = TypeChecker::with_config(&config);
444 typechecker.set_imports_by_module(imports_map.clone());
445 typechecker.check_program(&program.modules)?;
446 let struct_defs = typechecker.struct_definitions();
447 let enum_defs = typechecker.enum_definitions();
448 let mut signatures = typechecker.function_signatures();
449 let mut compiler = Compiler::new();
450 compiler.configure_stdlib(&config);
451 compiler.set_imports_by_module(imports_map);
452 compiler.set_entry_module(program.entry_module.clone());
453 let functions = compiler.compile_module(&wrapped_items)?;
454 let trait_impls = compiler.get_trait_impls().to_vec();
455 let mut init_funcs = Vec::new();
456 for module in &program.modules {
457 if module.path != program.entry_module {
458 if let Some(init) = &module.init_function {
459 init_funcs.push(init.clone());
460 }
461 }
462 }
463
464 let function_names: Vec<String> = functions.iter().map(|f| f.name.clone()).collect();
465 let entry_script = function_names
466 .iter()
467 .find(|name| name.as_str() == "__script")
468 .cloned();
469 if let Some(script_name) = &entry_script {
470 signatures
471 .entry(script_name.clone())
472 .or_insert_with(|| FunctionSignature {
473 params: Vec::new(),
474 return_type: Type::new(TypeKind::Unit, Span::new(0, 0, 0, 0)),
475 is_method: false,
476 });
477 }
478
479 let mut vm = VM::with_config(&config);
480 vm.load_functions(functions);
481 vm.register_structs(&struct_defs);
482 for (type_name, trait_name) in trait_impls {
483 vm.register_trait_impl(type_name, trait_name);
484 }
485
486 for init in init_funcs {
487 vm.call(&init, Vec::new())?;
488 }
489
490 Ok(EmbeddedProgram {
491 vm,
492 signatures,
493 struct_defs,
494 enum_defs,
495 entry_script,
496 })
497}
498
499fn module_path_to_file(base_dir: &Path, module_path: &str) -> PathBuf {
500 let mut path = base_dir.to_path_buf();
501 for segment in module_path.split('.') {
502 path.push(segment);
503 }
504
505 path.set_extension("lust");
506 path
507}
508
509fn normalize_global_name(name: &str) -> String {
510 if name.contains("::") {
511 name.to_string()
512 } else if let Some((module, identifier)) = name.rsplit_once('.') {
513 format!("{}::{}", module, identifier)
514 } else {
515 name.to_string()
516 }
517}
518
519fn ensure_return_type<R: FromLustValue>(function_name: &str, ty: &Type) -> Result<()> {
520 if matches!(ty.kind, TypeKind::Unknown) || R::matches_lust_type(ty) {
521 return Ok(());
522 }
523
524 Err(LustError::TypeError {
525 message: format!(
526 "Function '{}' reports return type '{}' which is incompatible with Rust receiver '{}'",
527 function_name,
528 ty,
529 R::type_description()
530 ),
531 })
532}
533
534pub struct TypedValue {
535 value: Value,
536 matcher: Box<dyn Fn(&Value, &Type) -> bool>,
537 description: &'static str,
538}
539
540impl TypedValue {
541 fn new<F>(value: Value, matcher: F, description: &'static str) -> Self
542 where
543 F: Fn(&Value, &Type) -> bool + 'static,
544 {
545 Self {
546 value,
547 matcher: Box::new(matcher),
548 description,
549 }
550 }
551
552 fn matches(&self, ty: &Type) -> bool {
553 match &ty.kind {
554 TypeKind::Union(types) => types.iter().any(|alt| (self.matcher)(&self.value, alt)),
555 _ => (self.matcher)(&self.value, ty),
556 }
557 }
558
559 fn description(&self) -> &'static str {
560 self.description
561 }
562
563 fn into_value(self) -> Value {
564 self.value
565 }
566}
567
568#[derive(Clone)]
569pub struct StructInstance {
570 type_name: String,
571 value: Value,
572}
573
574impl StructInstance {
575 fn new(type_name: String, value: Value) -> Self {
576 debug_assert!(matches!(value, Value::Struct { .. }));
577 Self { type_name, value }
578 }
579
580 pub fn type_name(&self) -> &str {
581 &self.type_name
582 }
583
584 pub fn field<T: FromLustValue>(&self, field: &str) -> Result<T> {
585 match &self.value {
586 Value::Struct { layout, fields, .. } => {
587 let index = layout
588 .index_of_str(field)
589 .ok_or_else(|| LustError::RuntimeError {
590 message: format!(
591 "Struct '{}' has no field named '{}'",
592 self.type_name, field
593 ),
594 })?;
595 let stored =
596 fields
597 .borrow()
598 .get(index)
599 .cloned()
600 .ok_or_else(|| LustError::RuntimeError {
601 message: format!(
602 "Struct '{}' field '{}' is unavailable",
603 self.type_name, field
604 ),
605 })?;
606 let materialized = layout.materialize_field_value(index, stored);
607 T::from_value(materialized)
608 }
609
610 _ => Err(LustError::RuntimeError {
611 message: "StructInstance does not contain a struct value".to_string(),
612 }),
613 }
614 }
615
616 pub fn as_value(&self) -> &Value {
617 &self.value
618 }
619}
620
621#[derive(Clone)]
622pub struct EnumInstance {
623 type_name: String,
624 variant: String,
625 value: Value,
626}
627
628impl EnumInstance {
629 fn new(type_name: String, variant: String, value: Value) -> Self {
630 debug_assert!(matches!(value, Value::Enum { .. }));
631 Self {
632 type_name,
633 variant,
634 value,
635 }
636 }
637
638 pub fn type_name(&self) -> &str {
639 &self.type_name
640 }
641
642 pub fn variant(&self) -> &str {
643 &self.variant
644 }
645
646 pub fn payload_len(&self) -> usize {
647 match &self.value {
648 Value::Enum { values, .. } => values.as_ref().map(|v| v.len()).unwrap_or(0),
649 _ => 0,
650 }
651 }
652
653 pub fn payload<T: FromLustValue>(&self, index: usize) -> Result<T> {
654 match &self.value {
655 Value::Enum { values, .. } => {
656 let values = values.as_ref().ok_or_else(|| LustError::RuntimeError {
657 message: format!(
658 "Enum variant '{}.{}' carries no payload",
659 self.type_name, self.variant
660 ),
661 })?;
662 let stored = values
663 .get(index)
664 .cloned()
665 .ok_or_else(|| LustError::RuntimeError {
666 message: format!(
667 "Enum variant '{}.{}' payload index {} is out of bounds",
668 self.type_name, self.variant, index
669 ),
670 })?;
671 T::from_value(stored)
672 }
673
674 _ => Err(LustError::RuntimeError {
675 message: "EnumInstance does not contain an enum value".to_string(),
676 }),
677 }
678 }
679
680 pub fn as_value(&self) -> &Value {
681 &self.value
682 }
683}
684
685pub trait IntoTypedValue {
686 fn into_typed_value(self) -> TypedValue;
687}
688
689impl IntoTypedValue for Value {
690 fn into_typed_value(self) -> TypedValue {
691 TypedValue::new(self, |_value, _ty| true, "Value")
692 }
693}
694
695impl IntoTypedValue for StructInstance {
696 fn into_typed_value(self) -> TypedValue {
697 let StructInstance {
698 type_name: _,
699 value,
700 } = self;
701 TypedValue::new(value, |v, ty| matches_lust_struct(v, ty), "struct")
702 }
703}
704
705impl IntoTypedValue for EnumInstance {
706 fn into_typed_value(self) -> TypedValue {
707 let EnumInstance {
708 type_name: _,
709 variant: _,
710 value,
711 } = self;
712 TypedValue::new(value, |v, ty| matches_lust_enum(v, ty), "enum")
713 }
714}
715
716macro_rules! impl_into_typed_for_primitive {
717 ($ty:ty, $desc:expr, $matcher:expr) => {
718 impl IntoTypedValue for $ty {
719 fn into_typed_value(self) -> TypedValue {
720 let value = self.into_value();
721 TypedValue::new(value, $matcher, $desc)
722 }
723 }
724 };
725}
726
727impl_into_typed_for_primitive!(i64, "int", |_, ty: &Type| match &ty.kind {
728 TypeKind::Int | TypeKind::Unknown => true,
729 TypeKind::Union(types) => types
730 .iter()
731 .any(|alt| matches!(&alt.kind, TypeKind::Int | TypeKind::Unknown)),
732 _ => false,
733});
734impl_into_typed_for_primitive!(f64, "float", |_, ty: &Type| match &ty.kind {
735 TypeKind::Float | TypeKind::Unknown => true,
736 TypeKind::Union(types) => types
737 .iter()
738 .any(|alt| matches!(&alt.kind, TypeKind::Float | TypeKind::Unknown)),
739 _ => false,
740});
741impl_into_typed_for_primitive!(bool, "bool", |_, ty: &Type| match &ty.kind {
742 TypeKind::Bool | TypeKind::Unknown => true,
743 TypeKind::Union(types) => types
744 .iter()
745 .any(|alt| matches!(&alt.kind, TypeKind::Bool | TypeKind::Unknown)),
746 _ => false,
747});
748impl IntoTypedValue for String {
749 fn into_typed_value(self) -> TypedValue {
750 let value = self.into_value();
751 TypedValue::new(value, string_matcher, "string")
752 }
753}
754
755impl<'a> IntoTypedValue for &'a str {
756 fn into_typed_value(self) -> TypedValue {
757 let value = self.into_value();
758 TypedValue::new(value, string_matcher, "string")
759 }
760}
761
762impl<'a> IntoTypedValue for &'a String {
763 fn into_typed_value(self) -> TypedValue {
764 let value = self.into_value();
765 TypedValue::new(value, string_matcher, "string")
766 }
767}
768
769impl IntoTypedValue for () {
770 fn into_typed_value(self) -> TypedValue {
771 TypedValue::new(
772 Value::Nil,
773 |_, ty| matches!(ty.kind, TypeKind::Unit | TypeKind::Unknown),
774 "unit",
775 )
776 }
777}
778
779impl<T> IntoTypedValue for Vec<T>
780where
781 T: IntoLustValue,
782{
783 fn into_typed_value(self) -> TypedValue {
784 let values = self.into_iter().map(|item| item.into_value()).collect();
785 TypedValue::new(
786 Value::array(values),
787 |_, ty| matches_array_type(ty, &T::matches_lust_type),
788 "array",
789 )
790 }
791}
792
793fn string_matcher(_: &Value, ty: &Type) -> bool {
794 match &ty.kind {
795 TypeKind::String | TypeKind::Unknown => true,
796 TypeKind::Union(types) => types
797 .iter()
798 .any(|alt| matches!(&alt.kind, TypeKind::String | TypeKind::Unknown)),
799 _ => false,
800 }
801}
802
803fn matches_lust_struct(value: &Value, ty: &Type) -> bool {
804 match (value, &ty.kind) {
805 (Value::Struct { name, .. }, TypeKind::Named(expected)) => name == expected,
806 (Value::Struct { name, .. }, TypeKind::GenericInstance { name: expected, .. }) => {
807 name == expected
808 }
809
810 (value, TypeKind::Union(types)) => types.iter().any(|alt| matches_lust_struct(value, alt)),
811 (_, TypeKind::Unknown) => true,
812 _ => false,
813 }
814}
815
816fn matches_lust_enum(value: &Value, ty: &Type) -> bool {
817 match (value, &ty.kind) {
818 (Value::Enum { enum_name, .. }, TypeKind::Named(expected)) => enum_name == expected,
819 (Value::Enum { enum_name, .. }, TypeKind::GenericInstance { name: expected, .. }) => {
820 enum_name == expected
821 }
822
823 (value, TypeKind::Union(types)) => types.iter().any(|alt| matches_lust_enum(value, alt)),
824 (_, TypeKind::Unknown) => true,
825 _ => false,
826 }
827}
828
829fn matches_array_type<F>(ty: &Type, matcher: &F) -> bool
830where
831 F: Fn(&Type) -> bool,
832{
833 match &ty.kind {
834 TypeKind::Array(inner) => matcher(inner),
835 TypeKind::Unknown => true,
836 TypeKind::Union(types) => types.iter().any(|alt| matches_array_type(alt, matcher)),
837 _ => false,
838 }
839}
840
841pub trait FromLustArgs: Sized {
842 fn from_values(values: &[Value]) -> std::result::Result<Self, String>;
843 fn matches_signature(params: &[Type]) -> bool;
844}
845
846macro_rules! impl_from_lust_args_tuple {
847 ($( $name:ident ),+) => {
848 impl<$($name),+> FromLustArgs for ($($name,)+)
849 where
850 $($name: FromLustValue,)+
851 {
852 fn from_values(values: &[Value]) -> std::result::Result<Self, String> {
853 let expected = count_idents!($($name),+);
854 if values.len() != expected {
855 return Err(format!(
856 "Native function expected {} argument(s) but received {}",
857 expected,
858 values.len()
859 ));
860 }
861
862 let mut idx = 0;
863 let result = (
864 $(
865 {
866 let value = $name::from_value(values[idx].clone()).map_err(|e| e.to_string())?;
867 idx += 1;
868 value
869 },
870 )+
871 );
872 let _ = idx;
873 Ok(result)
874 }
875
876 fn matches_signature(params: &[Type]) -> bool {
877 let expected = count_idents!($($name),+);
878 params.len() == expected && {
879 let mut idx = 0;
880 let mut ok = true;
881 $(
882 if ok && !$name::matches_lust_type(¶ms[idx]) {
883 ok = false;
884 }
885
886 idx += 1;
887 )+
888 let _ = idx;
889 ok
890 }
891
892 }
893
894 }
895
896 };
897}
898
899macro_rules! count_idents {
900 ($($name:ident),*) => {
901 <[()]>::len(&[$(count_idents!(@sub $name)),*])
902 };
903 (@sub $name:ident) => { () };
904}
905
906impl_from_lust_args_tuple!(A);
907impl_from_lust_args_tuple!(A, B);
908impl_from_lust_args_tuple!(A, B, C);
909impl_from_lust_args_tuple!(A, B, C, D);
910impl_from_lust_args_tuple!(A, B, C, D, E);
911impl<T> FromLustArgs for T
912where
913 T: FromLustValue,
914{
915 fn from_values(values: &[Value]) -> std::result::Result<Self, String> {
916 match values.len() {
917 0 => T::from_value(Value::Nil).map_err(|e| e.to_string()),
918 1 => T::from_value(values[0].clone()).map_err(|e| e.to_string()),
919 count => Err(format!(
920 "Native function expected 1 argument but received {}",
921 count
922 )),
923 }
924 }
925
926 fn matches_signature(params: &[Type]) -> bool {
927 if params.is_empty() {
928 let unit = Type::new(TypeKind::Unit, Span::new(0, 0, 0, 0));
929 return T::matches_lust_type(&unit);
930 }
931
932 params.len() == 1 && T::matches_lust_type(¶ms[0])
933 }
934}
935
936pub trait IntoLustValue: Sized {
937 fn into_value(self) -> Value;
938 fn matches_lust_type(ty: &Type) -> bool;
939 fn type_description() -> &'static str;
940}
941
942pub trait FromLustValue: Sized {
943 fn from_value(value: Value) -> Result<Self>;
944 fn matches_lust_type(ty: &Type) -> bool;
945 fn type_description() -> &'static str;
946}
947
948pub trait FunctionArgs {
949 fn into_values(self) -> Vec<Value>;
950 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()>;
951}
952
953impl IntoLustValue for Value {
954 fn into_value(self) -> Value {
955 self
956 }
957
958 fn matches_lust_type(_: &Type) -> bool {
959 true
960 }
961
962 fn type_description() -> &'static str {
963 "Value"
964 }
965}
966
967impl FromLustValue for Value {
968 fn from_value(value: Value) -> Result<Self> {
969 Ok(value)
970 }
971
972 fn matches_lust_type(_: &Type) -> bool {
973 true
974 }
975
976 fn type_description() -> &'static str {
977 "Value"
978 }
979}
980
981impl IntoLustValue for i64 {
982 fn into_value(self) -> Value {
983 Value::Int(self)
984 }
985
986 fn matches_lust_type(ty: &Type) -> bool {
987 matches!(ty.kind, TypeKind::Int | TypeKind::Unknown)
988 }
989
990 fn type_description() -> &'static str {
991 "int"
992 }
993}
994
995impl FromLustValue for i64 {
996 fn from_value(value: Value) -> Result<Self> {
997 match value {
998 Value::Int(v) => Ok(v),
999 other => Err(LustError::RuntimeError {
1000 message: format!("Expected Lust value 'int' but received '{:?}'", other),
1001 }),
1002 }
1003 }
1004
1005 fn matches_lust_type(ty: &Type) -> bool {
1006 matches!(ty.kind, TypeKind::Int | TypeKind::Unknown)
1007 }
1008
1009 fn type_description() -> &'static str {
1010 "int"
1011 }
1012}
1013
1014impl IntoLustValue for f64 {
1015 fn into_value(self) -> Value {
1016 Value::Float(self)
1017 }
1018
1019 fn matches_lust_type(ty: &Type) -> bool {
1020 matches!(ty.kind, TypeKind::Float | TypeKind::Unknown)
1021 }
1022
1023 fn type_description() -> &'static str {
1024 "float"
1025 }
1026}
1027
1028impl FromLustValue for f64 {
1029 fn from_value(value: Value) -> Result<Self> {
1030 match value {
1031 Value::Float(v) => Ok(v),
1032 other => Err(LustError::RuntimeError {
1033 message: format!("Expected Lust value 'float' but received '{:?}'", other),
1034 }),
1035 }
1036 }
1037
1038 fn matches_lust_type(ty: &Type) -> bool {
1039 matches!(ty.kind, TypeKind::Float | TypeKind::Unknown)
1040 }
1041
1042 fn type_description() -> &'static str {
1043 "float"
1044 }
1045}
1046
1047impl IntoLustValue for bool {
1048 fn into_value(self) -> Value {
1049 Value::Bool(self)
1050 }
1051
1052 fn matches_lust_type(ty: &Type) -> bool {
1053 matches!(ty.kind, TypeKind::Bool | TypeKind::Unknown)
1054 }
1055
1056 fn type_description() -> &'static str {
1057 "bool"
1058 }
1059}
1060
1061impl FromLustValue for bool {
1062 fn from_value(value: Value) -> Result<Self> {
1063 match value {
1064 Value::Bool(b) => Ok(b),
1065 other => Err(LustError::RuntimeError {
1066 message: format!("Expected Lust value 'bool' but received '{:?}'", other),
1067 }),
1068 }
1069 }
1070
1071 fn matches_lust_type(ty: &Type) -> bool {
1072 matches!(ty.kind, TypeKind::Bool | TypeKind::Unknown)
1073 }
1074
1075 fn type_description() -> &'static str {
1076 "bool"
1077 }
1078}
1079
1080impl IntoLustValue for String {
1081 fn into_value(self) -> Value {
1082 Value::String(Rc::new(self))
1083 }
1084
1085 fn matches_lust_type(ty: &Type) -> bool {
1086 matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
1087 }
1088
1089 fn type_description() -> &'static str {
1090 "string"
1091 }
1092}
1093
1094impl IntoLustValue for StructInstance {
1095 fn into_value(self) -> Value {
1096 self.value
1097 }
1098
1099 fn matches_lust_type(ty: &Type) -> bool {
1100 match &ty.kind {
1101 TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
1102 TypeKind::Union(types) => types
1103 .iter()
1104 .any(|alt| <Self as IntoLustValue>::matches_lust_type(alt)),
1105 _ => false,
1106 }
1107 }
1108
1109 fn type_description() -> &'static str {
1110 "struct"
1111 }
1112}
1113
1114impl FromLustValue for StructInstance {
1115 fn from_value(value: Value) -> Result<Self> {
1116 match &value {
1117 Value::Struct { name, .. } => Ok(StructInstance {
1118 type_name: name.clone(),
1119 value,
1120 }),
1121 other => Err(LustError::RuntimeError {
1122 message: format!("Expected Lust value 'struct' but received '{:?}'", other),
1123 }),
1124 }
1125 }
1126
1127 fn matches_lust_type(ty: &Type) -> bool {
1128 match &ty.kind {
1129 TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
1130 TypeKind::Union(types) => types
1131 .iter()
1132 .any(|alt| <Self as FromLustValue>::matches_lust_type(alt)),
1133 _ => false,
1134 }
1135 }
1136
1137 fn type_description() -> &'static str {
1138 "struct"
1139 }
1140}
1141
1142impl IntoLustValue for EnumInstance {
1143 fn into_value(self) -> Value {
1144 self.value
1145 }
1146
1147 fn matches_lust_type(ty: &Type) -> bool {
1148 match &ty.kind {
1149 TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
1150 TypeKind::Union(types) => types
1151 .iter()
1152 .any(|alt| <Self as IntoLustValue>::matches_lust_type(alt)),
1153 _ => false,
1154 }
1155 }
1156
1157 fn type_description() -> &'static str {
1158 "enum"
1159 }
1160}
1161
1162impl FromLustValue for EnumInstance {
1163 fn from_value(value: Value) -> Result<Self> {
1164 match &value {
1165 Value::Enum {
1166 enum_name, variant, ..
1167 } => Ok(EnumInstance {
1168 type_name: enum_name.clone(),
1169 variant: variant.clone(),
1170 value,
1171 }),
1172 other => Err(LustError::RuntimeError {
1173 message: format!("Expected Lust value 'enum' but received '{:?}'", other),
1174 }),
1175 }
1176 }
1177
1178 fn matches_lust_type(ty: &Type) -> bool {
1179 match &ty.kind {
1180 TypeKind::Unknown | TypeKind::Named(_) | TypeKind::GenericInstance { .. } => true,
1181 TypeKind::Union(types) => types
1182 .iter()
1183 .any(|alt| <Self as FromLustValue>::matches_lust_type(alt)),
1184 _ => false,
1185 }
1186 }
1187
1188 fn type_description() -> &'static str {
1189 "enum"
1190 }
1191}
1192
1193impl<T> IntoLustValue for Vec<T>
1194where
1195 T: IntoLustValue,
1196{
1197 fn into_value(self) -> Value {
1198 let values = self.into_iter().map(|item| item.into_value()).collect();
1199 Value::array(values)
1200 }
1201
1202 fn matches_lust_type(ty: &Type) -> bool {
1203 matches_array_type(ty, &T::matches_lust_type)
1204 }
1205
1206 fn type_description() -> &'static str {
1207 "array"
1208 }
1209}
1210
1211impl<T> FromLustValue for Vec<T>
1212where
1213 T: FromLustValue,
1214{
1215 fn from_value(value: Value) -> Result<Self> {
1216 match value {
1217 Value::Array(items) => {
1218 let borrowed = items.borrow();
1219 let mut result = Vec::with_capacity(borrowed.len());
1220 for item in borrowed.iter() {
1221 result.push(T::from_value(item.clone())?);
1222 }
1223
1224 Ok(result)
1225 }
1226
1227 other => Err(LustError::RuntimeError {
1228 message: format!("Expected Lust value 'array' but received '{:?}'", other),
1229 }),
1230 }
1231 }
1232
1233 fn matches_lust_type(ty: &Type) -> bool {
1234 matches_array_type(ty, &T::matches_lust_type)
1235 }
1236
1237 fn type_description() -> &'static str {
1238 "array"
1239 }
1240}
1241
1242impl<'a> IntoLustValue for &'a str {
1243 fn into_value(self) -> Value {
1244 Value::String(Rc::new(self.to_owned()))
1245 }
1246
1247 fn matches_lust_type(ty: &Type) -> bool {
1248 matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
1249 }
1250
1251 fn type_description() -> &'static str {
1252 "string"
1253 }
1254}
1255
1256impl<'a> IntoLustValue for &'a String {
1257 fn into_value(self) -> Value {
1258 Value::String(Rc::new(self.clone()))
1259 }
1260
1261 fn matches_lust_type(ty: &Type) -> bool {
1262 matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
1263 }
1264
1265 fn type_description() -> &'static str {
1266 "string"
1267 }
1268}
1269
1270impl FromLustValue for String {
1271 fn from_value(value: Value) -> Result<Self> {
1272 match value {
1273 Value::String(s) => Ok((*s).clone()),
1274 other => Err(LustError::RuntimeError {
1275 message: format!("Expected Lust value 'string' but received '{:?}'", other),
1276 }),
1277 }
1278 }
1279
1280 fn matches_lust_type(ty: &Type) -> bool {
1281 matches!(ty.kind, TypeKind::String | TypeKind::Unknown)
1282 }
1283
1284 fn type_description() -> &'static str {
1285 "string"
1286 }
1287}
1288
1289impl FromLustValue for () {
1290 fn from_value(value: Value) -> Result<Self> {
1291 match value {
1292 Value::Nil => Ok(()),
1293 other => Err(LustError::RuntimeError {
1294 message: format!("Expected Lust value 'unit' but received '{:?}'", other),
1295 }),
1296 }
1297 }
1298
1299 fn matches_lust_type(ty: &Type) -> bool {
1300 matches!(ty.kind, TypeKind::Unit | TypeKind::Unknown)
1301 }
1302
1303 fn type_description() -> &'static str {
1304 "unit"
1305 }
1306}
1307
1308impl FunctionArgs for () {
1309 fn into_values(self) -> Vec<Value> {
1310 Vec::new()
1311 }
1312
1313 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
1314 ensure_arity(function_name, params, 0)
1315 }
1316}
1317
1318impl<T> FunctionArgs for T
1319where
1320 T: IntoLustValue,
1321{
1322 fn into_values(self) -> Vec<Value> {
1323 vec![self.into_value()]
1324 }
1325
1326 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
1327 ensure_arity(function_name, params, 1)?;
1328 ensure_arg_type::<T>(function_name, params, 0)
1329 }
1330}
1331
1332impl<A, B> FunctionArgs for (A, B)
1333where
1334 A: IntoLustValue,
1335 B: IntoLustValue,
1336{
1337 fn into_values(self) -> Vec<Value> {
1338 vec![self.0.into_value(), self.1.into_value()]
1339 }
1340
1341 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
1342 ensure_arity(function_name, params, 2)?;
1343 ensure_arg_type::<A>(function_name, params, 0)?;
1344 ensure_arg_type::<B>(function_name, params, 1)?;
1345 Ok(())
1346 }
1347}
1348
1349impl<A, B, C> FunctionArgs for (A, B, C)
1350where
1351 A: IntoLustValue,
1352 B: IntoLustValue,
1353 C: IntoLustValue,
1354{
1355 fn into_values(self) -> Vec<Value> {
1356 vec![
1357 self.0.into_value(),
1358 self.1.into_value(),
1359 self.2.into_value(),
1360 ]
1361 }
1362
1363 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
1364 ensure_arity(function_name, params, 3)?;
1365 ensure_arg_type::<A>(function_name, params, 0)?;
1366 ensure_arg_type::<B>(function_name, params, 1)?;
1367 ensure_arg_type::<C>(function_name, params, 2)?;
1368 Ok(())
1369 }
1370}
1371
1372impl<A, B, C, D> FunctionArgs for (A, B, C, D)
1373where
1374 A: IntoLustValue,
1375 B: IntoLustValue,
1376 C: IntoLustValue,
1377 D: IntoLustValue,
1378{
1379 fn into_values(self) -> Vec<Value> {
1380 vec![
1381 self.0.into_value(),
1382 self.1.into_value(),
1383 self.2.into_value(),
1384 self.3.into_value(),
1385 ]
1386 }
1387
1388 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
1389 ensure_arity(function_name, params, 4)?;
1390 ensure_arg_type::<A>(function_name, params, 0)?;
1391 ensure_arg_type::<B>(function_name, params, 1)?;
1392 ensure_arg_type::<C>(function_name, params, 2)?;
1393 ensure_arg_type::<D>(function_name, params, 3)?;
1394 Ok(())
1395 }
1396}
1397
1398impl<A, B, C, D, E> FunctionArgs for (A, B, C, D, E)
1399where
1400 A: IntoLustValue,
1401 B: IntoLustValue,
1402 C: IntoLustValue,
1403 D: IntoLustValue,
1404 E: IntoLustValue,
1405{
1406 fn into_values(self) -> Vec<Value> {
1407 vec![
1408 self.0.into_value(),
1409 self.1.into_value(),
1410 self.2.into_value(),
1411 self.3.into_value(),
1412 self.4.into_value(),
1413 ]
1414 }
1415
1416 fn validate_signature(function_name: &str, params: &[Type]) -> Result<()> {
1417 ensure_arity(function_name, params, 5)?;
1418 ensure_arg_type::<A>(function_name, params, 0)?;
1419 ensure_arg_type::<B>(function_name, params, 1)?;
1420 ensure_arg_type::<C>(function_name, params, 2)?;
1421 ensure_arg_type::<D>(function_name, params, 3)?;
1422 ensure_arg_type::<E>(function_name, params, 4)?;
1423 Ok(())
1424 }
1425}
1426
1427fn ensure_arity(function_name: &str, params: &[Type], provided: usize) -> Result<()> {
1428 if params.len() == provided {
1429 Ok(())
1430 } else {
1431 Err(LustError::TypeError {
1432 message: format!(
1433 "Function '{}' expects {} argument(s) but {} were supplied",
1434 function_name,
1435 params.len(),
1436 provided
1437 ),
1438 })
1439 }
1440}
1441
1442fn ensure_arg_type<T: IntoLustValue>(
1443 function_name: &str,
1444 params: &[Type],
1445 index: usize,
1446) -> Result<()> {
1447 if <T as IntoLustValue>::matches_lust_type(¶ms[index]) {
1448 Ok(())
1449 } else {
1450 Err(argument_type_mismatch(
1451 function_name,
1452 index,
1453 <T as IntoLustValue>::type_description(),
1454 ¶ms[index],
1455 ))
1456 }
1457}
1458
1459fn argument_type_mismatch(
1460 function_name: &str,
1461 index: usize,
1462 rust_type: &str,
1463 lust_type: &Type,
1464) -> LustError {
1465 LustError::TypeError {
1466 message: format!(
1467 "Function '{}' parameter {} expects Lust type '{}' but Rust provided '{}'",
1468 function_name,
1469 index + 1,
1470 lust_type,
1471 rust_type
1472 ),
1473 }
1474}