rune/module/module_raw_function_builder.rs
1use crate::compile::ContextError;
2use crate::function_meta::{
3 Associated, AssociatedFunctionData, FunctionData, FunctionMetaKind, ToInstance,
4};
5use crate::item::IntoComponent;
6use crate::module::ItemFnMut;
7use crate::runtime::{Address, FunctionHandler, Memory, Output, TypeInfo, TypeOf};
8use crate::{Hash, ItemBuf, VmError};
9
10use super::Module;
11
12/// Raw function builder as returned by [`Module::raw_function`].
13///
14/// This allows for building a function regularly with
15/// [`ModuleRawFunctionBuilder::build`] or statically associate the function
16/// with a type through [`ModuleRawFunctionBuilder::build_associated::<T>`].
17#[must_use = "Must call one of the build functions, like `build` or `build_associated`"]
18pub struct ModuleRawFunctionBuilder<'a, N, F> {
19 pub(super) module: &'a mut Module,
20 pub(super) name: N,
21 pub(super) handler: F,
22}
23
24impl<'a, N, F> ModuleRawFunctionBuilder<'a, N, F>
25where
26 F: 'static + Fn(&mut dyn Memory, Address, usize, Output) -> Result<(), VmError> + Send + Sync,
27{
28 /// Construct a regular function.
29 ///
30 /// This register the function as a free function in the module it's
31 /// associated with, who's full name is the name of the module extended by
32 /// the name of the function.
33 ///
34 /// # Examples
35 ///
36 /// ```
37 /// use rune::{Any, Module};
38 ///
39 /// let mut m = Module::with_item(["module"])?;
40 /// m.raw_function("floob", |_, _, _, _| Ok(())).build()?;
41 /// # Ok::<_, rune::support::Error>(())
42 /// ```
43 #[inline]
44 pub fn build(self) -> Result<ItemFnMut<'a>, ContextError>
45 where
46 N: IntoComponent,
47 {
48 let item = ItemBuf::with_item([self.name])?;
49 let handler = FunctionHandler::new(self.handler)?;
50
51 self.module
52 .function_from_meta_kind(FunctionMetaKind::Function(FunctionData::from_raw(
53 item, handler,
54 )))
55 }
56
57 /// Construct a function that is associated with `T`.
58 ///
59 /// This registers the function as an assocaited function, which can only be
60 /// used through the type `T`.
61 ///
62 /// # Errors
63 ///
64 /// This function call will cause an error in [`Context::install`] if the
65 /// type we're associating it with has not been registered.
66 ///
67 /// [`Context::install`]: crate::Context::install
68 ///
69 /// ```
70 /// use rune::{Any, Module, Context};
71 ///
72 /// #[derive(Any)]
73 /// struct Thing;
74 ///
75 /// let mut m = Module::default();
76 /// m.function("floob", || ()).build_associated::<Thing>()?;
77 ///
78 /// let mut c = Context::default();
79 /// assert!(c.install(m).is_err());
80 /// # Ok::<_, rune::support::Error>(())
81 /// ```
82 ///
83 /// # Examples
84 ///
85 /// ```
86 /// use rune::{Any, Module};
87 ///
88 /// #[derive(Any)]
89 /// struct Thing;
90 ///
91 /// let mut m = Module::default();
92 /// m.ty::<Thing>()?;
93 /// m.raw_function("floob", |_, _, _, _| Ok(())).build_associated::<Thing>()?;
94 /// # Ok::<_, rune::support::Error>(())
95 /// ```
96 #[inline]
97 pub fn build_associated<T>(self) -> Result<ItemFnMut<'a>, ContextError>
98 where
99 N: ToInstance,
100 T: TypeOf,
101 {
102 let associated = Associated::from_type::<T>(self.name.to_instance()?)?;
103 let handler = FunctionHandler::new(self.handler)?;
104
105 self.module
106 .function_from_meta_kind(FunctionMetaKind::AssociatedFunction(
107 AssociatedFunctionData::from_raw(associated, handler),
108 ))
109 }
110
111 /// Construct a function that is associated with a custom dynamically
112 /// specified container.
113 ///
114 /// This registers the function as an assocaited function, which can only be
115 /// used through the specified type.
116 ///
117 /// [`Hash`] and [`TypeInfo`] are usually constructed through the [`TypeOf`]
118 /// trait. But that requires access to a static type, for which you should
119 /// use [`build_associated`] instead.
120 ///
121 /// # Errors
122 ///
123 /// The function call will error if the specified type is not already
124 /// registered in the module.
125 ///
126 /// [`Hash`]: crate::Hash
127 /// [`build_associated`]: super::ModuleFunctionBuilder::build_associated
128 #[inline]
129 pub fn build_associated_with(
130 self,
131 container: Hash,
132 container_type_info: TypeInfo,
133 ) -> Result<ItemFnMut<'a>, ContextError>
134 where
135 N: ToInstance,
136 {
137 let associated = Associated::new(self.name.to_instance()?, container, container_type_info);
138 let handler = FunctionHandler::new(self.handler)?;
139
140 self.module
141 .function_from_meta_kind(FunctionMetaKind::AssociatedFunction(
142 AssociatedFunctionData::from_raw(associated, handler),
143 ))
144 }
145}