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}