rune/module/module_function_builder.rs
1use crate::compile::ContextError;
2use crate::function::{Function, FunctionKind};
3use crate::function_meta::{FunctionArgs, FunctionBuilder, ToInstance};
4use crate::item::IntoComponent;
5use crate::module::ItemFnMut;
6use crate::runtime::{MaybeTypeOf, TypeInfo, TypeOf};
7use crate::Hash;
8
9use super::Module;
10
11/// Function builder as returned by [`Module::function`].
12///
13/// This allows for building a function regularly with
14/// [`ModuleFunctionBuilder::build`] or statically associate the function with a
15/// type through [`ModuleFunctionBuilder::build_associated::<T>`].
16#[must_use = "Must call one of the build functions, like `build` or `build_associated`"]
17pub struct ModuleFunctionBuilder<'a, F, A, N, K> {
18 pub(super) module: &'a mut Module,
19 pub(super) inner: FunctionBuilder<N, F, A, K>,
20}
21
22impl<'a, F, A, N, K> ModuleFunctionBuilder<'a, F, A, N, K>
23where
24 F: Function<A, K, Return: MaybeTypeOf>,
25 A: FunctionArgs,
26 K: FunctionKind,
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.function("floob", || ()).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 meta = self.inner.build()?;
49 self.module.function_from_meta_kind(meta)
50 }
51
52 /// Construct a function that is associated with `T`.
53 ///
54 /// This registers the function as an assocaited function, which can only be
55 /// used through the type `T`.
56 ///
57 /// # Errors
58 ///
59 /// This function call will cause an error in [`Context::install`] if the
60 /// type we're associating it with has not been registered.
61 ///
62 /// [`Context::install`]: crate::Context::install
63 ///
64 /// ```
65 /// use rune::{Any, Context, Module};
66 ///
67 /// #[derive(Any)]
68 /// struct Thing;
69 ///
70 /// let mut m = Module::default();
71 /// m.function("floob", || ()).build_associated::<Thing>()?;
72 ///
73 /// let mut c = Context::default();
74 /// assert!(c.install(m).is_err());
75 /// # Ok::<_, rune::support::Error>(())
76 /// ```
77 ///
78 /// # Examples
79 ///
80 /// ```
81 /// use rune::{Any, Module};
82 ///
83 /// #[derive(Any)]
84 /// struct Thing;
85 ///
86 /// let mut m = Module::default();
87 /// m.ty::<Thing>()?;
88 /// m.function("floob", || ()).build_associated::<Thing>()?;
89 /// # Ok::<_, rune::support::Error>(())
90 /// ```
91 #[inline]
92 pub fn build_associated<T>(self) -> Result<ItemFnMut<'a>, ContextError>
93 where
94 N: ToInstance,
95 T: TypeOf,
96 {
97 let meta = self.inner.build_associated::<T>()?;
98 self.module.function_from_meta_kind(meta)
99 }
100
101 /// Construct a function that is associated with a custom dynamically
102 /// specified container.
103 ///
104 /// This registers the function as an assocaited function, which can only be
105 /// used through the specified type.
106 ///
107 /// [`Hash`] and [`TypeInfo`] are usually constructed through the
108 /// [`TypeOf`] trait. But that requires access to a static type, for which
109 /// you should use [`build_associated`] instead.
110 ///
111 /// # Errors
112 ///
113 /// The function call will error if the specified type is not already
114 /// registered in the module.
115 ///
116 /// [`build_associated`]: ModuleFunctionBuilder::build_associated
117 /// [`Hash`]: crate::Hash
118 #[inline]
119 pub fn build_associated_with(
120 self,
121 container: Hash,
122 container_type_info: TypeInfo,
123 ) -> Result<ItemFnMut<'a>, ContextError>
124 where
125 N: ToInstance,
126 {
127 let meta = self
128 .inner
129 .build_associated_with(container, container_type_info)?;
130 self.module.function_from_meta_kind(meta)
131 }
132}