rune/module/
module_raw_function_builder.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use ::rust_alloc::sync::Arc;

use crate::compile::ContextError;
use crate::function_meta::{
    Associated, AssociatedFunctionData, FunctionData, FunctionMetaKind, ToInstance,
};
use crate::item::IntoComponent;
use crate::module::ItemFnMut;
use crate::runtime::{FunctionHandler, TypeInfo, TypeOf};
use crate::{Hash, ItemBuf};

use super::Module;

/// Raw function builder as returned by [`Module::raw_function`].
///
/// This allows for building a function regularly with
/// [`ModuleRawFunctionBuilder::build`] or statically associate the function
/// with a type through [`ModuleRawFunctionBuilder::build_associated::<T>`].
#[must_use = "Must call one of the build functions, like `build` or `build_associated`"]
pub struct ModuleRawFunctionBuilder<'a, N> {
    pub(super) module: &'a mut Module,
    pub(super) name: N,
    pub(super) handler: Arc<FunctionHandler>,
}

impl<'a, N> ModuleRawFunctionBuilder<'a, N> {
    /// Construct a regular function.
    ///
    /// This register the function as a free function in the module it's
    /// associated with, who's full name is the name of the module extended by
    /// the name of the function.
    ///
    /// # Examples
    ///
    /// ```
    /// use rune::{Any, Module};
    /// use rune::runtime::VmResult;
    ///
    /// let mut m = Module::with_item(["module"])?;
    /// m.raw_function("floob", |_, _, _, _| VmResult::Ok(())).build()?;
    /// # Ok::<_, rune::support::Error>(())
    /// ```
    #[inline]
    pub fn build(self) -> Result<ItemFnMut<'a>, ContextError>
    where
        N: IntoComponent,
    {
        let item = ItemBuf::with_item([self.name])?;
        self.module
            .function_from_meta_kind(FunctionMetaKind::Function(FunctionData::from_raw(
                item,
                self.handler,
            )))
    }

    /// Construct a function that is associated with `T`.
    ///
    /// This registers the function as an assocaited function, which can only be
    /// used through the type `T`.
    ///
    /// # Errors
    ///
    /// This function call will cause an error in [`Context::install`] if the
    /// type we're associating it with has not been registered.
    ///
    /// [`Context::install`]: crate::Context::install
    ///
    /// ```
    /// use rune::{Any, Module, Context};
    ///
    /// #[derive(Any)]
    /// struct Thing;
    ///
    /// let mut m = Module::default();
    /// m.function("floob", || ()).build_associated::<Thing>()?;
    ///
    /// let mut c = Context::default();
    /// assert!(c.install(m).is_err());
    /// # Ok::<_, rune::support::Error>(())
    /// ```
    ///
    /// # Examples
    ///
    /// ```
    /// use rune::{Any, Module};
    /// use rune::runtime::VmResult;
    ///
    /// #[derive(Any)]
    /// struct Thing;
    ///
    /// let mut m = Module::default();
    /// m.ty::<Thing>()?;
    /// m.raw_function("floob", |_, _, _, _| VmResult::Ok(())).build_associated::<Thing>()?;
    /// # Ok::<_, rune::support::Error>(())
    /// ```
    #[inline]
    pub fn build_associated<T>(self) -> Result<ItemFnMut<'a>, ContextError>
    where
        N: ToInstance,
        T: TypeOf,
    {
        let associated = Associated::from_type::<T>(self.name.to_instance()?)?;

        self.module
            .function_from_meta_kind(FunctionMetaKind::AssociatedFunction(
                AssociatedFunctionData::from_raw(associated, self.handler),
            ))
    }

    /// Construct a function that is associated with a custom dynamically
    /// specified container.
    ///
    /// This registers the function as an assocaited function, which can only be
    /// used through the specified type.
    ///
    /// [`Hash`] and [`TypeInfo`] are usually constructed through the [`TypeOf`]
    /// trait. But that requires access to a static type, for which you should
    /// use [`build_associated`] instead.
    ///
    /// # Errors
    ///
    /// The function call will error if the specified type is not already
    /// registered in the module.
    ///
    /// [`Hash`]: crate::Hash
    /// [`build_associated`]: super::ModuleFunctionBuilder::build_associated
    #[inline]
    pub fn build_associated_with(
        self,
        container: Hash,
        container_type_info: TypeInfo,
    ) -> Result<ItemFnMut<'a>, ContextError>
    where
        N: ToInstance,
    {
        let associated = Associated::new(self.name.to_instance()?, container, container_type_info);
        self.module
            .function_from_meta_kind(FunctionMetaKind::AssociatedFunction(
                AssociatedFunctionData::from_raw(associated, self.handler),
            ))
    }
}