lust/
embed.rs

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(&params[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(&params[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(&params[index]) {
1448        Ok(())
1449    } else {
1450        Err(argument_type_mismatch(
1451            function_name,
1452            index,
1453            <T as IntoLustValue>::type_description(),
1454            &params[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}