1#![allow(unpredictable_function_pointer_comparisons)]
2
3use crate::{
18 Filter, Visibility,
19 context::Context,
20 meta::Meta,
21 registry::Registry,
22 types::{Type, TypeHandle, TypeQuery},
23};
24use intuicio_data::data_stack::DataStackPack;
25use rustc_hash::FxHasher;
26use std::{
27 borrow::Cow,
28 hash::{Hash, Hasher},
29 sync::Arc,
30};
31
32pub type FunctionHandle = Arc<Function>;
34pub type FunctionMetaQuery = fn(&Meta) -> bool;
36
37pub enum FunctionBody {
42 Pointer(fn(&mut Context, &Registry)),
44 #[allow(clippy::type_complexity)]
46 Closure(Arc<dyn Fn(&mut Context, &Registry) + Send + Sync>),
47}
48
49impl FunctionBody {
50 pub fn pointer(pointer: fn(&mut Context, &Registry)) -> Self {
52 Self::Pointer(pointer)
53 }
54
55 pub fn closure<T>(closure: T) -> Self
57 where
58 T: Fn(&mut Context, &Registry) + Send + Sync + 'static,
59 {
60 Self::Closure(Arc::new(closure))
61 }
62
63 pub fn invoke(&self, context: &mut Context, registry: &Registry) {
65 match self {
66 Self::Pointer(pointer) => pointer(context, registry),
67 Self::Closure(closure) => closure(context, registry),
68 }
69 }
70}
71
72impl std::fmt::Debug for FunctionBody {
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 match self {
75 Self::Pointer(_) => write!(f, "<Pointer>"),
76 Self::Closure(_) => write!(f, "<Closure>"),
77 }
78 }
79}
80
81#[derive(Clone, PartialEq)]
83pub struct FunctionParameter {
84 pub meta: Option<Meta>,
86 pub name: String,
88 pub type_handle: TypeHandle,
90}
91
92impl FunctionParameter {
93 pub fn new(name: impl ToString, type_handle: TypeHandle) -> Self {
95 Self {
96 meta: None,
97 name: name.to_string(),
98 type_handle,
99 }
100 }
101
102 pub fn with_meta(mut self, meta: Meta) -> Self {
104 self.meta = Some(meta);
105 self
106 }
107}
108
109impl std::fmt::Debug for FunctionParameter {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 f.debug_struct("FunctionParameter")
112 .field("meta", &self.meta)
113 .field("name", &self.name)
114 .field("type_handle", &self.type_handle.name())
115 .finish()
116 }
117}
118
119#[derive(Clone, PartialEq)]
127pub struct FunctionSignature {
128 pub meta: Option<Meta>,
130 pub name: String,
132 pub module_name: Option<String>,
134 pub type_handle: Option<TypeHandle>,
136 pub visibility: Visibility,
138 pub inputs: Vec<FunctionParameter>,
140 pub outputs: Vec<FunctionParameter>,
142}
143
144impl FunctionSignature {
145 pub fn new(name: impl ToString) -> Self {
147 Self {
148 meta: None,
149 name: name.to_string(),
150 module_name: None,
151 type_handle: None,
152 visibility: Visibility::default(),
153 inputs: vec![],
154 outputs: vec![],
155 }
156 }
157
158 pub fn with_meta(mut self, meta: Meta) -> Self {
160 self.meta = Some(meta);
161 self
162 }
163
164 pub fn with_module_name(mut self, name: impl ToString) -> Self {
166 self.module_name = Some(name.to_string());
167 self
168 }
169
170 pub fn with_type_handle(mut self, handle: TypeHandle) -> Self {
172 self.type_handle = Some(handle);
173 self
174 }
175
176 pub fn with_visibility(mut self, visibility: Visibility) -> Self {
178 self.visibility = visibility;
179 self
180 }
181
182 pub fn with_input(mut self, parameter: FunctionParameter) -> Self {
184 self.inputs.push(parameter);
185 self
186 }
187
188 pub fn with_output(mut self, parameter: FunctionParameter) -> Self {
190 self.outputs.push(parameter);
191 self
192 }
193}
194
195impl std::fmt::Debug for FunctionSignature {
196 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
197 f.debug_struct("FunctionSignature")
198 .field("meta", &self.meta)
199 .field("name", &self.name)
200 .field("module_name", &self.module_name)
201 .field(
202 "type_handle",
203 &match self.type_handle.as_ref() {
204 Some(type_handle) => type_handle.name().to_owned(),
205 None => "!".to_owned(),
206 },
207 )
208 .field("visibility", &self.visibility)
209 .field("inputs", &self.inputs)
210 .field("outputs", &self.outputs)
211 .finish()
212 }
213}
214
215impl std::fmt::Display for FunctionSignature {
216 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
217 if let Some(meta) = self.meta.as_ref() {
218 write!(f, "#{meta} ")?;
219 }
220 if let Some(module_name) = self.module_name.as_ref() {
221 write!(f, "mod {module_name} ")?;
222 }
223 if let Some(type_handle) = self.type_handle.as_ref() {
224 match &**type_handle {
225 Type::Struct(value) => {
226 write!(f, "struct {} ", value.type_name())?;
227 }
228 Type::Enum(value) => {
229 write!(f, "enum {} ", value.type_name())?;
230 }
231 }
232 }
233 write!(f, "fn {}(", self.name)?;
234 for (index, parameter) in self.inputs.iter().enumerate() {
235 if index > 0 {
236 write!(f, ", ")?;
237 }
238 write!(
239 f,
240 "{}: {}",
241 parameter.name,
242 parameter.type_handle.type_name()
243 )?;
244 }
245 write!(f, ") -> (")?;
246 for (index, parameter) in self.outputs.iter().enumerate() {
247 if index > 0 {
248 write!(f, ", ")?;
249 }
250 write!(
251 f,
252 "{}: {}",
253 parameter.name,
254 parameter.type_handle.type_name()
255 )?;
256 }
257 write!(f, ")")
258 }
259}
260
261#[derive(Debug)]
265pub struct Function {
266 signature: FunctionSignature,
267 body: FunctionBody,
268}
269
270impl Function {
271 pub fn new(signature: FunctionSignature, body: FunctionBody) -> Self {
273 Self { signature, body }
274 }
275
276 pub fn signature(&self) -> &FunctionSignature {
278 &self.signature
279 }
280
281 pub fn invoke(&self, context: &mut Context, registry: &Registry) {
287 context.store_registers();
288 self.body.invoke(context, registry);
289 context.restore_registers();
290 }
291
292 pub fn call<O: DataStackPack, I: DataStackPack>(
302 &self,
303 context: &mut Context,
304 registry: &Registry,
305 inputs: I,
306 verify: bool,
307 ) -> O {
308 if verify {
309 self.verify_inputs_outputs::<O, I>();
310 }
311 inputs.stack_push_reversed(context.stack());
312 self.invoke(context, registry);
313 O::stack_pop(context.stack())
314 }
315
316 pub fn verify_inputs_outputs<O: DataStackPack, I: DataStackPack>(&self) {
322 let input_types = I::pack_types();
323 if input_types.len() != self.signature.inputs.len() {
324 panic!("Function: {} got wrong inputs number!", self.signature.name);
325 }
326 let output_types = O::pack_types();
327 if output_types.len() != self.signature.outputs.len() {
328 panic!(
329 "Function: {} got wrong outputs number!",
330 self.signature.name
331 );
332 }
333 for (parameter, type_hash) in self.signature.inputs.iter().zip(input_types) {
334 if parameter.type_handle.type_hash() != type_hash {
335 panic!(
336 "Function: {} input parameter: {} got wrong value type!",
337 self.signature.name, parameter.name
338 );
339 }
340 }
341 for (parameter, type_hash) in self.signature.outputs.iter().zip(output_types) {
342 if parameter.type_handle.type_hash() != type_hash {
343 panic!(
344 "Function: {} output parameter: {} got wrong value type!",
345 self.signature.name, parameter.name
346 );
347 }
348 }
349 }
350
351 pub fn into_handle(self) -> FunctionHandle {
353 self.into()
354 }
355}
356
357#[derive(Debug, Default, Clone, PartialEq, Hash)]
361pub struct FunctionQueryParameter<'a> {
362 pub name: Option<Cow<'a, str>>,
364 pub type_query: Option<TypeQuery<'a>>,
366 pub meta: Option<FunctionMetaQuery>,
368}
369
370impl FunctionQueryParameter<'_> {
371 pub fn is_valid(&self, parameter: &FunctionParameter) -> bool {
373 self.name
374 .as_ref()
375 .map(|name| name.as_ref() == parameter.name)
376 .unwrap_or(true)
377 && self
378 .type_query
379 .as_ref()
380 .map(|query| query.is_valid(¶meter.type_handle))
381 .unwrap_or(true)
382 && self
383 .meta
384 .as_ref()
385 .map(|query| parameter.meta.as_ref().map(query).unwrap_or(false))
386 .unwrap_or(true)
387 }
388
389 pub fn to_static(&self) -> FunctionQueryParameter<'static> {
391 FunctionQueryParameter {
392 name: self
393 .name
394 .as_ref()
395 .map(|name| name.as_ref().to_owned().into()),
396 type_query: self.type_query.as_ref().map(|query| query.to_static()),
397 meta: self.meta,
398 }
399 }
400}
401
402#[derive(Debug, Default, Clone, PartialEq, Hash)]
418pub enum Parameters<'a> {
419 #[default]
421 Any,
422 Prefix(Cow<'a, [FunctionQueryParameter<'a>]>),
424 Exact(Cow<'a, [FunctionQueryParameter<'a>]>),
426}
427
428impl<'a> From<Vec<FunctionQueryParameter<'a>>> for Parameters<'a> {
431 fn from(value: Vec<FunctionQueryParameter<'a>>) -> Self {
432 Self::Prefix(value.into())
433 }
434}
435
436impl<'a> From<Cow<'a, [FunctionQueryParameter<'a>]>> for Parameters<'a> {
437 fn from(value: Cow<'a, [FunctionQueryParameter<'a>]>) -> Self {
438 Self::Prefix(value)
439 }
440}
441
442impl<'a> From<&'a [FunctionQueryParameter<'a>]> for Parameters<'a> {
443 fn from(value: &'a [FunctionQueryParameter<'a>]) -> Self {
444 Self::Prefix(value.into())
445 }
446}
447
448impl<'a> Parameters<'a> {
449 pub fn is_valid(&self, parameters: &[FunctionParameter]) -> bool {
451 let (queries, exact) = match self {
452 Self::Any => return true,
453 Self::Prefix(queries) => (queries, false),
454 Self::Exact(queries) => (queries, true),
455 };
456 let fits = if exact {
457 queries.len() == parameters.len()
458 } else {
459 queries.len() <= parameters.len()
460 };
461 fits && queries
462 .iter()
463 .zip(parameters.iter())
464 .all(|(query, parameter)| query.is_valid(parameter))
465 }
466
467 pub fn queries(&self) -> &[FunctionQueryParameter<'a>] {
469 match self {
470 Self::Any => &[],
471 Self::Prefix(queries) | Self::Exact(queries) => queries,
472 }
473 }
474
475 pub fn to_static(&self) -> Parameters<'static> {
477 let queries = |queries: &Cow<'_, [FunctionQueryParameter<'_>]>| {
478 queries
479 .iter()
480 .map(|query| query.to_static())
481 .collect::<Vec<_>>()
482 .into()
483 };
484 match self {
485 Self::Any => Parameters::Any,
486 Self::Prefix(inner) => Parameters::Prefix(queries(inner)),
487 Self::Exact(inner) => Parameters::Exact(queries(inner)),
488 }
489 }
490}
491
492#[derive(Debug, Default, Clone, PartialEq, Hash)]
513pub struct FunctionQuery<'a> {
514 pub name: Option<Cow<'a, str>>,
516 pub module_name: Filter<Cow<'a, str>>,
518 pub type_query: Filter<TypeQuery<'a>>,
520 pub visibility: Option<Visibility>,
522 pub inputs: Parameters<'a>,
524 pub outputs: Parameters<'a>,
526 pub meta: Filter<FunctionMetaQuery>,
528}
529
530impl FunctionQuery<'_> {
531 pub fn is_valid(&self, signature: &FunctionSignature) -> bool {
533 self.name
534 .as_ref()
535 .map(|name| name.as_ref() == signature.name)
536 .unwrap_or(true)
537 && self
538 .module_name
539 .is_valid(signature.module_name.as_ref(), |name, module_name| {
540 name.as_ref() == module_name
541 })
542 && self
543 .type_query
544 .is_valid(signature.type_handle.as_ref(), |query, handle| {
545 query.is_valid(handle)
546 })
547 && self
548 .visibility
549 .map(|visibility| signature.visibility.is_visible(visibility))
550 .unwrap_or(true)
551 && self.inputs.is_valid(&signature.inputs)
552 && self.outputs.is_valid(&signature.outputs)
553 && self
554 .meta
555 .is_valid(signature.meta.as_ref(), |query, meta| query(meta))
556 }
557
558 pub fn as_hash(&self) -> u64 {
560 let mut hasher = FxHasher::default();
561 self.hash(&mut hasher);
562 hasher.finish()
563 }
564
565 pub fn to_static(&self) -> FunctionQuery<'static> {
567 FunctionQuery {
568 name: self
569 .name
570 .as_ref()
571 .map(|name| name.as_ref().to_owned().into()),
572 module_name: self.module_name.map(|name| name.as_ref().to_owned().into()),
573 type_query: self.type_query.map(|query| query.to_static()),
574 visibility: self.visibility,
575 inputs: self.inputs.to_static(),
576 outputs: self.outputs.to_static(),
577 meta: self.meta,
578 }
579 }
580}
581
582#[macro_export]
594macro_rules! function_signature {
595 (
596 $registry:expr
597 =>
598 $(mod $module_name:ident)?
599 $(type ($type:ty))?
600 fn
601 $name:ident
602 ($( $input_name:ident : $input_type:ty ),*)
603 ->
604 ($( $output_name:ident : $output_type:ty ),*)
605 ) => {{
606 let mut result = $crate::function::FunctionSignature::new(stringify!($name));
607 $(
608 result.module_name = Some(stringify!($module_name).to_owned());
609 )?
610 $(
611 result.type_handle = Some($registry.find_type($crate::types::TypeQuery::of::<$type>()).unwrap());
612 )?
613 $(
614 result.inputs.push(
615 $crate::function::FunctionParameter::new(
616 stringify!($input_name).to_owned(),
617 $registry.find_type($crate::types::TypeQuery::of::<$input_type>()).unwrap()
618 )
619 );
620 )*
621 $(
622 result.outputs.push(
623 $crate::function::FunctionParameter::new(
624 stringify!($output_name).to_owned(),
625 $registry.find_type($crate::types::TypeQuery::of::<$output_type>()).unwrap()
626 )
627 );
628 )*
629 result
630 }};
631}
632
633#[macro_export]
646macro_rules! define_function {
647 (
648 $registry:expr
649 =>
650 $(mod $module_name:ident)?
651 $(type ($type:ty))?
652 fn
653 $name:ident
654 ($( $input_name:ident : $input_type:ty),*)
655 ->
656 ($( $output_name:ident : $output_type:ty),*)
657 $code:block
658 ) => {
659 $crate::function::Function::new(
660 $crate::function_signature! {
661 $registry
662 =>
663 $(mod $module_name)?
664 $(type ($type))?
665 fn
666 $name
667 ($($input_name : $input_type),*)
668 ->
669 ($($output_name : $output_type),*)
670 },
671 $crate::function::FunctionBody::closure(move |context, registry| {
672 use intuicio_data::data_stack::DataStackPack;
673 #[allow(unused_mut)]
674 let ($(mut $input_name,)*) = <($($input_type,)*)>::stack_pop(context.stack());
675 $code.stack_push_reversed(context.stack());
676 }),
677 )
678 };
679}
680
681#[cfg(test)]
682mod tests {
683 use crate as intuicio_core;
684 use crate::{context::*, function::*, registry::*, types::struct_type::*};
685 use intuicio_data;
686 use intuicio_derive::*;
687
688 #[intuicio_function(meta = "foo", args_meta(_bar = "foo"))]
689 fn function_meta(_bar: bool) {}
690
691 #[intuicio_function(name = "+", module_name = "core/ops")]
692 fn function_non_ident_name(a: i32, b: i32) -> i32 {
693 a + b
694 }
695
696 #[test]
699 fn test_query_filters() {
700 let mut registry = Registry::default();
701 registry.add_type(NativeStructBuilder::new::<i32>().build());
702 let i32_type = registry.find_type(TypeQuery::of::<i32>()).unwrap();
703
704 let free = FunctionSignature::new("f")
705 .with_module_name("lib")
706 .with_input(FunctionParameter::new("a", i32_type.clone()));
707 let method = FunctionSignature::new("f")
708 .with_module_name("lib")
709 .with_type_handle(i32_type.clone())
710 .with_input(FunctionParameter::new("a", i32_type.clone()));
711
712 let query = FunctionQuery {
714 type_query: Filter::Absent,
715 ..Default::default()
716 };
717 assert!(query.is_valid(&free));
718 assert!(!query.is_valid(&method));
719
720 let query = FunctionQuery::default();
723 assert!(query.is_valid(&free));
724 assert!(query.is_valid(&method));
725
726 let query = FunctionQuery {
728 module_name: Filter::Matching("lib".into()),
729 ..Default::default()
730 };
731 assert!(query.is_valid(&free));
732 let query = FunctionQuery {
733 module_name: Filter::Matching("other".into()),
734 ..Default::default()
735 };
736 assert!(!query.is_valid(&free));
737
738 let two = FunctionSignature::new("g")
739 .with_input(FunctionParameter::new("a", i32_type.clone()))
740 .with_input(FunctionParameter::new("b", i32_type.clone()));
741
742 let one_filter = vec![FunctionQueryParameter::default()];
744 assert!(
745 FunctionQuery {
746 inputs: Parameters::Prefix(one_filter.to_owned().into()),
747 ..Default::default()
748 }
749 .is_valid(&two)
750 );
751 assert!(
752 !FunctionQuery {
753 inputs: Parameters::Exact(one_filter.into()),
754 ..Default::default()
755 }
756 .is_valid(&two)
757 );
758
759 let three_filters = vec![
762 FunctionQueryParameter::default(),
763 FunctionQueryParameter::default(),
764 FunctionQueryParameter::default(),
765 ];
766 assert!(
767 !FunctionQuery {
768 inputs: Parameters::Prefix(three_filters.into()),
769 ..Default::default()
770 }
771 .is_valid(&two)
772 );
773 }
774
775 #[test]
776 fn test_function_non_ident_name() {
777 let mut registry = Registry::default();
778 registry.add_type(NativeStructBuilder::new::<i32>().build());
779 let signature = function_non_ident_name::define_signature(®istry);
780 assert_eq!(signature.name, "+");
781 assert_eq!(signature.module_name.as_deref(), Some("core/ops"));
782 }
783
784 #[test]
785 fn test_function() {
786 fn add(context: &mut Context, _: &Registry) {
787 let a = context.stack().pop::<i32>().unwrap();
788 let b = context.stack().pop::<i32>().unwrap();
789 context.stack().push(a + b);
790 }
791
792 let i32_handle = NativeStructBuilder::new::<i32>()
793 .build()
794 .into_type()
795 .into_handle();
796 let signature = FunctionSignature::new("add")
797 .with_input(FunctionParameter::new("a", i32_handle.clone()))
798 .with_input(FunctionParameter::new("b", i32_handle.clone()))
799 .with_output(FunctionParameter::new("result", i32_handle));
800 let function = Function::new(signature.to_owned(), FunctionBody::pointer(add));
801
802 assert!(FunctionQuery::default().is_valid(&signature));
803 assert!(
804 FunctionQuery {
805 name: Some("add".into()),
806 ..Default::default()
807 }
808 .is_valid(&signature)
809 );
810 assert!(
811 FunctionQuery {
812 name: Some("add".into()),
813 inputs: [
814 FunctionQueryParameter {
815 name: Some("a".into()),
816 ..Default::default()
817 },
818 FunctionQueryParameter {
819 name: Some("b".into()),
820 ..Default::default()
821 }
822 ]
823 .as_slice()
824 .into(),
825 outputs: [FunctionQueryParameter {
826 name: Some("result".into()),
827 ..Default::default()
828 }]
829 .as_slice()
830 .into(),
831 ..Default::default()
832 }
833 .is_valid(&signature)
834 );
835 assert!(
836 !FunctionQuery {
837 name: Some("add".into()),
838 inputs: [
839 FunctionQueryParameter {
840 name: Some("b".into()),
841 ..Default::default()
842 },
843 FunctionQueryParameter {
844 name: Some("a".into()),
845 ..Default::default()
846 }
847 ]
848 .as_slice()
849 .into(),
850 ..Default::default()
851 }
852 .is_valid(&signature)
853 );
854
855 let mut context = Context::new(10240, 10240);
856 let registry = Registry::default().with_basic_types();
857
858 context.stack().push(2);
859 context.stack().push(40);
860 function.invoke(&mut context, ®istry);
861 assert_eq!(context.stack().pop::<i32>().unwrap(), 42);
862
863 assert_eq!(
864 function_meta::define_signature(®istry).meta,
865 Some(Meta::Identifier("foo".to_owned()))
866 );
867 }
868}