rune/module/
module.rs

1use core::marker::PhantomData;
2
3use crate as rune;
4use crate::alloc::prelude::*;
5use crate::alloc::{self, HashMap, HashSet};
6use crate::compile::context::{AttributeMacroHandler, MacroHandler};
7use crate::compile::{self, meta, ContextError, Docs, Named};
8use crate::function::{Function, FunctionKind, InstanceFunction, Plain};
9use crate::function_meta::{
10    Associated, AssociatedFunctionData, AssociatedName, FunctionArgs, FunctionBuilder,
11    FunctionData, FunctionMeta, FunctionMetaKind, MacroMeta, MacroMetaKind, ToFieldFunction,
12    ToInstance,
13};
14use crate::item::IntoComponent;
15use crate::macros::{MacroContext, TokenStream};
16use crate::module::DocFunction;
17use crate::runtime::{
18    Address, AnyTypeInfo, ConstConstructImpl, MaybeTypeOf, Memory, Output, Protocol, ToConstValue,
19    TypeHash, TypeOf, VmError,
20};
21use crate::{Hash, Item, ItemBuf};
22
23use super::{
24    AssociatedKey, InstallWith, ItemFnMut, ItemMut, ModuleAssociated, ModuleAssociatedKind,
25    ModuleAttributeMacro, ModuleConstantBuilder, ModuleFunction, ModuleFunctionBuilder, ModuleItem,
26    ModuleItemCommon, ModuleItemKind, ModuleMacro, ModuleMeta, ModuleRawFunctionBuilder,
27    ModuleReexport, ModuleTrait, ModuleTraitImpl, ModuleType, TraitMut, TypeMut, TypeSpecification,
28    VariantMut,
29};
30
31#[derive(Debug, TryClone, PartialEq, Eq, Hash)]
32enum Name {
33    /// An associated key.
34    Associated(AssociatedKey),
35    /// A regular item.
36    Item(Hash),
37    /// A macro.
38    Macro(Hash),
39    /// An attribute macro.
40    AttributeMacro(Hash),
41    /// A conflicting trait implementation.
42    TraitImpl(Hash, Hash),
43}
44
45/// A [`Module`] that is a collection of native functions and types.
46///
47/// Needs to be installed into a [Context][crate::compile::Context] using
48/// [Context::install][crate::compile::Context::install].
49#[derive(Default)]
50pub struct Module {
51    /// Uniqueness checks.
52    names: HashSet<Name>,
53    /// A special identifier for this module, which will cause it to not conflict if installed multiple times.
54    pub(crate) unique: Option<&'static str>,
55    /// The name of the module.
56    pub(crate) item: ItemBuf,
57    /// Functions.
58    pub(crate) items: Vec<ModuleItem>,
59    /// Associated items.
60    pub(crate) associated: Vec<ModuleAssociated>,
61    /// Registered types.
62    pub(crate) types: Vec<ModuleType>,
63    /// Type hash to types mapping.
64    pub(crate) types_hash: HashMap<Hash, usize>,
65    /// A trait registered in the current module.
66    pub(crate) traits: Vec<ModuleTrait>,
67    /// A trait implementation registered in the current module.
68    pub(crate) trait_impls: Vec<ModuleTraitImpl>,
69    /// A re-export in the current module.
70    pub(crate) reexports: Vec<ModuleReexport>,
71    /// Constant constructors.
72    pub(crate) construct: Vec<(Hash, AnyTypeInfo, ConstConstructImpl)>,
73    /// Defines construct hashes.
74    pub(crate) construct_hash: HashSet<Hash>,
75    /// Module level metadata.
76    pub(crate) common: ModuleItemCommon,
77}
78
79impl Module {
80    /// Create an empty module for the root path.
81    pub fn new() -> Self {
82        Self::default()
83    }
84
85    /// Modify the current module to utilise a special identifier.
86    ///
87    /// TODO: Deprecate after next major release.
88    #[doc(hidden)]
89    pub fn with_unique(self, id: &'static str) -> Self {
90        Self {
91            unique: Some(id),
92            ..self
93        }
94    }
95
96    /// Construct a new module for the given item.
97    pub fn with_item(iter: impl IntoIterator<Item: IntoComponent>) -> Result<Self, ContextError> {
98        Ok(Self::inner_new(ItemBuf::with_item(iter)?))
99    }
100
101    /// Construct a new module for the given crate.
102    pub fn with_crate(name: &str) -> Result<Self, ContextError> {
103        Ok(Self::inner_new(ItemBuf::with_crate(name)?))
104    }
105
106    /// Construct a new module for the given crate.
107    pub fn with_crate_item(
108        name: &str,
109        iter: impl IntoIterator<Item: IntoComponent>,
110    ) -> Result<Self, ContextError> {
111        Ok(Self::inner_new(ItemBuf::with_crate_item(name, iter)?))
112    }
113
114    /// Construct a new module from the given module meta.
115    pub fn from_meta(module_meta: ModuleMeta) -> Result<Self, ContextError> {
116        let meta = module_meta()?;
117        let mut m = Self::inner_new(meta.item.try_to_owned()?);
118        m.item_mut().static_docs(meta.docs)?;
119        Ok(m)
120    }
121
122    fn inner_new(item: ItemBuf) -> Self {
123        Self {
124            names: HashSet::new(),
125            unique: None,
126            item,
127            items: Vec::new(),
128            associated: Vec::new(),
129            types: Vec::new(),
130            traits: Vec::new(),
131            trait_impls: Vec::new(),
132            types_hash: HashMap::new(),
133            reexports: Vec::new(),
134            construct: Vec::new(),
135            construct_hash: HashSet::new(),
136            common: ModuleItemCommon {
137                docs: Docs::EMPTY,
138                deprecated: None,
139            },
140        }
141    }
142
143    /// Mutate item-level properties for this module.
144    pub fn item_mut(&mut self) -> ItemMut<'_> {
145        ItemMut {
146            docs: &mut self.common.docs,
147            #[cfg(feature = "doc")]
148            deprecated: &mut self.common.deprecated,
149        }
150    }
151
152    /// Register a type. Registering a type is mandatory in order to register
153    /// instance functions using that type.
154    ///
155    /// This will allow the type to be used within scripts, using the item named
156    /// here.
157    ///
158    /// # Examples
159    ///
160    /// ```
161    /// use rune::{Any, Context, Module};
162    ///
163    /// #[derive(Any)]
164    /// struct MyBytes {
165    ///     queue: Vec<String>,
166    /// }
167    ///
168    /// impl MyBytes {
169    ///     #[rune::function]
170    ///     fn len(&self) -> usize {
171    ///         self.queue.len()
172    ///     }
173    /// }
174    ///
175    /// // Register `len` without registering a type.
176    /// let mut m = Module::default();
177    /// // Note: cannot do this until we have registered a type.
178    /// m.function_meta(MyBytes::len)?;
179    ///
180    /// let mut context = rune::Context::new();
181    /// assert!(context.install(m).is_err());
182    ///
183    /// // Register `len` properly.
184    /// let mut m = Module::default();
185    ///
186    /// m.ty::<MyBytes>()?;
187    /// m.function_meta(MyBytes::len)?;
188    ///
189    /// let mut context = Context::new();
190    /// assert!(context.install(m).is_ok());
191    /// # Ok::<_, rune::support::Error>(())
192    /// ```
193    pub fn ty<T>(&mut self) -> Result<TypeMut<'_, T>, ContextError>
194    where
195        T: ?Sized + TypeOf + Named + InstallWith,
196    {
197        if !self.names.try_insert(Name::Item(T::HASH))? {
198            return Err(ContextError::ConflictingType {
199                item: T::ITEM.try_to_owned()?,
200                type_info: T::type_info(),
201                hash: T::HASH,
202            });
203        }
204
205        let index = self.types.len();
206        self.types_hash.try_insert(T::HASH, index)?;
207
208        self.types.try_push(ModuleType {
209            item: T::ITEM.try_to_owned()?,
210            hash: T::HASH,
211            common: ModuleItemCommon {
212                docs: Docs::EMPTY,
213                deprecated: None,
214            },
215            type_parameters: T::PARAMETERS,
216            type_info: T::type_info(),
217            spec: None,
218            constructor: None,
219        })?;
220
221        T::install_with(self)?;
222
223        let ty = self.types.last_mut().unwrap();
224
225        Ok(TypeMut {
226            docs: &mut ty.common.docs,
227            #[cfg(feature = "doc")]
228            deprecated: &mut ty.common.deprecated,
229            spec: &mut ty.spec,
230            constructor: &mut ty.constructor,
231            item: &ty.item,
232            _marker: PhantomData,
233        })
234    }
235
236    /// Accessor to modify type metadata such as documentaiton, fields, variants.
237    pub fn type_meta<T>(&mut self) -> Result<TypeMut<'_, T>, ContextError>
238    where
239        T: ?Sized + TypeOf + Named,
240    {
241        let type_hash = T::HASH;
242
243        let Some(ty) = self.types_hash.get(&type_hash).map(|&i| &mut self.types[i]) else {
244            let full_name = T::display().try_to_string()?;
245
246            return Err(ContextError::MissingType {
247                item: ItemBuf::with_item(&[full_name])?,
248                type_info: T::type_info(),
249            });
250        };
251
252        Ok(TypeMut {
253            docs: &mut ty.common.docs,
254            #[cfg(feature = "doc")]
255            deprecated: &mut ty.common.deprecated,
256            spec: &mut ty.spec,
257            constructor: &mut ty.constructor,
258            item: &ty.item,
259            _marker: PhantomData,
260        })
261    }
262
263    /// Access variant metadata for the given type and the index of its variant.
264    pub fn variant_meta<T>(&mut self, index: usize) -> Result<VariantMut<'_, T>, ContextError>
265    where
266        T: ?Sized + TypeOf + Named,
267    {
268        let type_hash = T::HASH;
269
270        let Some(ty) = self.types_hash.get(&type_hash).map(|&i| &mut self.types[i]) else {
271            let full_name = T::display().try_to_string()?;
272
273            return Err(ContextError::MissingType {
274                item: ItemBuf::with_item(&[full_name])?,
275                type_info: T::type_info(),
276            });
277        };
278
279        let Some(TypeSpecification::Enum(en)) = &mut ty.spec else {
280            let full_name = T::display().try_to_string()?;
281
282            return Err(ContextError::MissingEnum {
283                item: ItemBuf::with_item(&[full_name])?,
284                type_info: T::type_info(),
285            });
286        };
287
288        let Some(variant) = en.variants.get_mut(index) else {
289            return Err(ContextError::MissingVariant {
290                type_info: T::type_info(),
291                index,
292            });
293        };
294
295        Ok(VariantMut {
296            name: variant.name,
297            docs: &mut variant.docs,
298            fields: &mut variant.fields,
299            constructor: &mut variant.constructor,
300            _marker: PhantomData,
301        })
302    }
303
304    /// Register a constant value, at a crate, module or associated level.
305    ///
306    /// # Examples
307    ///
308    /// ```
309    /// use rune::{docstring, Any, Module};
310    ///
311    /// let mut module = Module::default();
312    ///
313    /// #[derive(Any)]
314    /// struct MyType;
315    ///
316    /// module.constant("TEN", 10)
317    ///     .build()?
318    ///     .docs(docstring! {
319    ///         /// A global ten value.
320    ///     });
321    ///
322    /// module.constant("VEC", [1, 2, 3].as_slice())
323    ///     .build()?;
324    ///
325    /// module.constant("TEN", 10)
326    ///     .build_associated::<MyType>()?
327    ///     .docs(docstring! {
328    ///         /// Ten which looks like an associated constant.
329    ///     });
330    /// # Ok::<_, rune::support::Error>(())
331    /// ```
332    pub fn constant<N, V>(&mut self, name: N, value: V) -> ModuleConstantBuilder<'_, N, V>
333    where
334        V: TypeHash + TypeOf + ToConstValue,
335    {
336        ModuleConstantBuilder {
337            module: self,
338            name,
339            value,
340        }
341    }
342
343    pub(super) fn insert_constant<N, V>(
344        &mut self,
345        name: N,
346        value: V,
347    ) -> Result<ItemMut<'_>, ContextError>
348    where
349        N: IntoComponent,
350        V: TypeHash + TypeOf + ToConstValue,
351    {
352        let item = self.item.join([name])?;
353        let hash = Hash::type_hash(&item);
354
355        let value = match value.to_const_value() {
356            Ok(value) => value,
357            Err(error) => {
358                return Err(ContextError::InvalidConstValue {
359                    item,
360                    error: Box::try_new(error)?,
361                })
362            }
363        };
364
365        if !self.names.try_insert(Name::Item(hash))? {
366            return Err(ContextError::ConflictingConstantName { item, hash });
367        }
368
369        self.items.try_push(ModuleItem {
370            item,
371            hash,
372            common: ModuleItemCommon {
373                docs: Docs::EMPTY,
374                deprecated: None,
375            },
376            kind: ModuleItemKind::Constant(value),
377        })?;
378
379        self.insert_const_construct::<V>()?;
380
381        let c = self.items.last_mut().unwrap();
382
383        Ok(ItemMut {
384            docs: &mut c.common.docs,
385            #[cfg(feature = "doc")]
386            deprecated: &mut c.common.deprecated,
387        })
388    }
389
390    pub(super) fn insert_associated_constant<V>(
391        &mut self,
392        associated: Associated,
393        value: V,
394    ) -> Result<ItemMut<'_>, ContextError>
395    where
396        V: TypeHash + TypeOf + ToConstValue,
397    {
398        let value = match value.to_const_value() {
399            Ok(value) => value,
400            Err(error) => {
401                return Err(ContextError::InvalidAssociatedConstValue {
402                    container: associated.container_type_info,
403                    kind: Box::try_new(associated.name.kind)?,
404                    error: Box::try_new(error)?,
405                });
406            }
407        };
408
409        self.insert_associated_name(&associated)?;
410
411        self.associated.try_push(ModuleAssociated {
412            container: associated.container,
413            container_type_info: associated.container_type_info,
414            name: associated.name,
415            common: ModuleItemCommon {
416                docs: Docs::EMPTY,
417                deprecated: None,
418            },
419            kind: ModuleAssociatedKind::Constant(value),
420        })?;
421
422        self.insert_const_construct::<V>()?;
423
424        let last = self.associated.last_mut().unwrap();
425
426        Ok(ItemMut {
427            docs: &mut last.common.docs,
428            #[cfg(feature = "doc")]
429            deprecated: &mut last.common.deprecated,
430        })
431    }
432
433    fn insert_const_construct<V>(&mut self) -> alloc::Result<()>
434    where
435        V: TypeHash + TypeOf + ToConstValue,
436    {
437        if self.construct_hash.try_insert(V::HASH)? {
438            if let Some(construct) = V::construct()? {
439                self.construct
440                    .try_push((V::HASH, V::STATIC_TYPE_INFO, construct))?;
441            }
442        }
443
444        Ok(())
445    }
446
447    /// Register a native macro handler through its meta.
448    ///
449    /// The metadata must be provided by annotating the function with
450    /// [`#[rune::macro_]`][crate::macro_].
451    ///
452    /// This has the benefit that it captures documentation comments which can
453    /// be used when generating documentation or referencing the function
454    /// through code sense systems.
455    ///
456    /// # Examples
457    ///
458    /// ```
459    /// use rune::Module;
460    /// use rune::ast;
461    /// use rune::compile;
462    /// use rune::macros::{quote, MacroContext, TokenStream};
463    /// use rune::parse::Parser;
464    /// use rune::alloc::prelude::*;
465    ///
466    /// /// Takes an identifier and converts it into a string.
467    /// ///
468    /// /// # Examples
469    /// ///
470    /// /// ```rune
471    /// /// assert_eq!(ident_to_string!(Hello), "Hello");
472    /// /// ```
473    /// #[rune::macro_]
474    /// fn ident_to_string(cx: &mut MacroContext<'_, '_, '_>, stream: &TokenStream) -> compile::Result<TokenStream> {
475    ///     let mut p = Parser::from_token_stream(stream, cx.input_span());
476    ///     let ident = p.parse_all::<ast::Ident>()?;
477    ///     let ident = cx.resolve(ident)?.try_to_owned()?;
478    ///     let string = cx.lit(&ident)?;
479    ///     Ok(quote!(#string).into_token_stream(cx)?)
480    /// }
481    ///
482    /// let mut m = Module::new();
483    /// m.macro_meta(ident_to_string)?;
484    /// # Ok::<_, rune::support::Error>(())
485    /// ```
486    #[inline]
487    pub fn macro_meta(&mut self, meta: MacroMeta) -> Result<ItemMut<'_>, ContextError> {
488        let meta = meta()?;
489
490        let item = match meta.kind {
491            MacroMetaKind::Function(data) => {
492                let item = self.item.join(&data.item)?;
493                let hash = Hash::type_hash(&item);
494
495                if !self.names.try_insert(Name::Macro(hash))? {
496                    return Err(ContextError::ConflictingMacroName { item, hash });
497                }
498
499                let mut docs = Docs::EMPTY;
500                docs.set_docs(meta.docs)?;
501
502                self.items.try_push(ModuleItem {
503                    item,
504                    hash,
505                    common: ModuleItemCommon {
506                        docs,
507                        deprecated: None,
508                    },
509                    kind: ModuleItemKind::Macro(ModuleMacro {
510                        handler: data.handler,
511                    }),
512                })?;
513
514                self.items.last_mut().unwrap()
515            }
516            MacroMetaKind::Attribute(data) => {
517                let item = self.item.join(&data.item)?;
518                let hash = Hash::type_hash(&item);
519
520                if !self.names.try_insert(Name::AttributeMacro(hash))? {
521                    return Err(ContextError::ConflictingMacroName { item, hash });
522                }
523
524                let mut docs = Docs::EMPTY;
525                docs.set_docs(meta.docs)?;
526
527                self.items.try_push(ModuleItem {
528                    item,
529                    hash,
530                    common: ModuleItemCommon {
531                        docs,
532                        deprecated: None,
533                    },
534                    kind: ModuleItemKind::AttributeMacro(ModuleAttributeMacro {
535                        handler: data.handler,
536                    }),
537                })?;
538
539                self.items.last_mut().unwrap()
540            }
541        };
542
543        Ok(ItemMut {
544            docs: &mut item.common.docs,
545            #[cfg(feature = "doc")]
546            deprecated: &mut item.common.deprecated,
547        })
548    }
549
550    /// Register a native macro handler.
551    ///
552    /// If possible, [`Module::macro_meta`] should be used since it includes more
553    /// useful information about the macro.
554    ///
555    /// # Examples
556    ///
557    /// ```
558    /// use rune::Module;
559    /// use rune::ast;
560    /// use rune::compile;
561    /// use rune::macros::{quote, MacroContext, TokenStream};
562    /// use rune::parse::Parser;
563    /// use rune::alloc::prelude::*;
564    ///
565    /// fn ident_to_string(cx: &mut MacroContext<'_, '_, '_>, stream: &TokenStream) -> compile::Result<TokenStream> {
566    ///     let mut p = Parser::from_token_stream(stream, cx.input_span());
567    ///     let ident = p.parse_all::<ast::Ident>()?;
568    ///     let ident = cx.resolve(ident)?.try_to_owned()?;
569    ///     let string = cx.lit(&ident)?;
570    ///     Ok(quote!(#string).into_token_stream(cx)?)
571    /// }
572    ///
573    /// let mut m = Module::new();
574    /// m.macro_(["ident_to_string"], ident_to_string)?;
575    /// # Ok::<_, rune::support::Error>(())
576    /// ```
577    pub fn macro_<N, M>(&mut self, name: N, f: M) -> Result<ItemMut<'_>, ContextError>
578    where
579        M: 'static
580            + Send
581            + Sync
582            + Fn(&mut MacroContext<'_, '_, '_>, &TokenStream) -> compile::Result<TokenStream>,
583        N: IntoComponent,
584    {
585        let item = self.item.join([name])?;
586        let hash = Hash::type_hash(&item);
587
588        if !self.names.try_insert(Name::Macro(hash))? {
589            return Err(ContextError::ConflictingMacroName { item, hash });
590        }
591
592        let handler = MacroHandler::new(f)?;
593
594        self.items.try_push(ModuleItem {
595            item,
596            hash,
597            common: ModuleItemCommon::default(),
598            kind: ModuleItemKind::Macro(ModuleMacro { handler }),
599        })?;
600
601        let m = self.items.last_mut().unwrap();
602
603        Ok(ItemMut {
604            docs: &mut m.common.docs,
605            #[cfg(feature = "doc")]
606            deprecated: &mut m.common.deprecated,
607        })
608    }
609
610    /// Register a native attribute macro handler.
611    ///
612    /// If possible, [`Module::macro_meta`] should be used since it includes more
613    /// useful information about the function.
614    ///
615    /// # Examples
616    ///
617    /// ```
618    /// use rune::Module;
619    /// use rune::ast;
620    /// use rune::compile;
621    /// use rune::macros::{quote, MacroContext, TokenStream, ToTokens};
622    /// use rune::parse::Parser;
623    ///
624    /// fn rename_fn(cx: &mut MacroContext<'_, '_, '_>, input: &TokenStream, item: &TokenStream) -> compile::Result<TokenStream> {
625    ///     let mut item = Parser::from_token_stream(item, cx.macro_span());
626    ///     let mut fun = item.parse_all::<ast::ItemFn>()?;
627    ///
628    ///     let mut input = Parser::from_token_stream(input, cx.input_span());
629    ///     fun.name = input.parse_all::<ast::EqValue<_>>()?.value;
630    ///     Ok(quote!(#fun).into_token_stream(cx)?)
631    /// }
632    ///
633    /// let mut m = Module::new();
634    /// m.attribute_macro(["rename_fn"], rename_fn)?;
635    /// # Ok::<_, rune::support::Error>(())
636    /// ```
637    pub fn attribute_macro<N, M>(&mut self, name: N, f: M) -> Result<ItemMut<'_>, ContextError>
638    where
639        M: 'static
640            + Send
641            + Sync
642            + Fn(
643                &mut MacroContext<'_, '_, '_>,
644                &TokenStream,
645                &TokenStream,
646            ) -> compile::Result<TokenStream>,
647        N: IntoComponent,
648    {
649        let item = self.item.join([name])?;
650        let hash = Hash::type_hash(&item);
651
652        if !self.names.try_insert(Name::AttributeMacro(hash))? {
653            return Err(ContextError::ConflictingMacroName { item, hash });
654        }
655
656        let handler = AttributeMacroHandler::new(f)?;
657
658        self.items.try_push(ModuleItem {
659            item,
660            hash,
661            common: ModuleItemCommon {
662                docs: Docs::EMPTY,
663                deprecated: None,
664            },
665            kind: ModuleItemKind::AttributeMacro(ModuleAttributeMacro { handler }),
666        })?;
667
668        let m = self.items.last_mut().unwrap();
669
670        Ok(ItemMut {
671            docs: &mut m.common.docs,
672            #[cfg(feature = "doc")]
673            deprecated: &mut m.common.deprecated,
674        })
675    }
676
677    /// Register a function handler through its meta.
678    ///
679    /// The metadata must be provided by annotating the function with
680    /// [`#[rune::function]`][macro@crate::function].
681    ///
682    /// This has the benefit that it captures documentation comments which can
683    /// be used when generating documentation or referencing the function
684    /// through code sense systems.
685    ///
686    /// # Examples
687    ///
688    /// ```
689    /// use rune::{ContextError, Module, Ref};
690    ///
691    /// /// This is a pretty neat function.
692    /// #[rune::function]
693    /// fn to_string(string: &str) -> String {
694    ///     string.to_string()
695    /// }
696    ///
697    /// /// This is a pretty neat download function
698    /// #[rune::function]
699    /// async fn download(url: Ref<str>) -> rune::support::Result<String> {
700    ///     # todo!()
701    /// }
702    ///
703    /// fn module() -> Result<Module, ContextError> {
704    ///     let mut m = Module::new();
705    ///     m.function_meta(to_string)?;
706    ///     m.function_meta(download)?;
707    ///     Ok(m)
708    /// }
709    /// ```
710    ///
711    /// Registering instance functions:
712    ///
713    /// ```
714    /// use rune::{Any, Module, Ref};
715    ///
716    /// #[derive(Any)]
717    /// struct MyBytes {
718    ///     queue: Vec<String>,
719    /// }
720    ///
721    /// impl MyBytes {
722    ///     fn new() -> Self {
723    ///         Self {
724    ///             queue: Vec::new(),
725    ///         }
726    ///     }
727    ///
728    ///     #[rune::function]
729    ///     fn len(&self) -> usize {
730    ///         self.queue.len()
731    ///     }
732    ///
733    ///     #[rune::function(instance, path = Self::download)]
734    ///     async fn download(this: Ref<Self>, url: Ref<str>) -> rune::support::Result<()> {
735    ///         # todo!()
736    ///     }
737    /// }
738    ///
739    /// let mut m = Module::default();
740    ///
741    /// m.ty::<MyBytes>()?;
742    /// m.function_meta(MyBytes::len)?;
743    /// m.function_meta(MyBytes::download)?;
744    /// # Ok::<_, rune::support::Error>(())
745    /// ```
746    #[inline]
747    pub fn function_meta(&mut self, meta: FunctionMeta) -> Result<ItemFnMut<'_>, ContextError> {
748        let meta = meta()?;
749
750        let mut docs = Docs::EMPTY;
751        docs.set_docs(meta.statics.docs)?;
752        docs.set_arguments(meta.statics.arguments)?;
753        let deprecated = meta.statics.deprecated.map(TryInto::try_into).transpose()?;
754
755        match meta.kind {
756            FunctionMetaKind::Function(data) => self.function_inner(data, docs, deprecated),
757            FunctionMetaKind::AssociatedFunction(data) => {
758                self.insert_associated_function(data, docs, deprecated)
759            }
760        }
761    }
762
763    pub(super) fn function_from_meta_kind(
764        &mut self,
765        kind: FunctionMetaKind,
766    ) -> Result<ItemFnMut<'_>, ContextError> {
767        match kind {
768            FunctionMetaKind::Function(data) => self.function_inner(data, Docs::EMPTY, None),
769            FunctionMetaKind::AssociatedFunction(data) => {
770                self.insert_associated_function(data, Docs::EMPTY, None)
771            }
772        }
773    }
774
775    /// Register a function.
776    ///
777    /// If possible, [`Module::function_meta`] should be used since it includes more
778    /// useful information about the function.
779    ///
780    /// # Examples
781    ///
782    /// ```
783    /// use rune::{docstring, Module};
784    ///
785    /// fn add_ten(value: i64) -> i64 {
786    ///     value + 10
787    /// }
788    ///
789    /// let mut module = Module::default();
790    ///
791    /// module.function("add_ten", add_ten)
792    ///     .build()?
793    ///     .docs(docstring! {
794    ///         /// Adds 10 to any integer passed in.
795    ///     });
796    /// # Ok::<_, rune::support::Error>(())
797    /// ```
798    ///
799    /// Asynchronous function:
800    ///
801    /// ```
802    /// use rune::{docstring, Any, Module};
803    /// # async fn download(url: &str) -> Result<String, DownloadError> { Ok(String::new()) }
804    ///
805    /// #[derive(Any)]
806    /// struct DownloadError {
807    ///     /* .. */
808    /// }
809    ///
810    /// async fn download_quote() -> Result<String, DownloadError> {
811    ///     download("https://api.quotable.io/random").await
812    /// }
813    ///
814    /// let mut module = Module::default();
815    ///
816    /// module.function("download_quote", download_quote)
817    ///     .build()?
818    ///     .docs(docstring! {
819    ///         /// Download a random quote from the internet.
820    ///     });
821    /// # Ok::<_, rune::support::Error>(())
822    /// ```
823    pub fn function<F, A, N, K>(&mut self, name: N, f: F) -> ModuleFunctionBuilder<'_, F, A, N, K>
824    where
825        F: Function<A, K, Return: MaybeTypeOf>,
826        A: FunctionArgs,
827        K: FunctionKind,
828    {
829        ModuleFunctionBuilder {
830            module: self,
831            inner: FunctionBuilder::new(name, f),
832        }
833    }
834
835    /// Register an instance function.
836    ///
837    /// If possible, [`Module::function_meta`] should be used since it includes
838    /// more useful information about the function.
839    ///
840    /// This returns a [`ItemMut`], which is a handle that can be used to
841    /// associate more metadata with the inserted item.
842    ///
843    /// # Replacing this with `function_meta` and `#[rune::function]`
844    ///
845    /// This is how you declare an instance function which takes `&self` or
846    /// `&mut self`:
847    ///
848    /// ```rust
849    /// # use rune::Any;
850    /// #[derive(Any)]
851    /// struct Struct {
852    ///     /* .. */
853    /// }
854    ///
855    /// impl Struct {
856    ///     /// Get the length of the `Struct`.
857    ///     #[rune::function]
858    ///     fn len(&self) -> usize {
859    ///         /* .. */
860    ///         # todo!()
861    ///     }
862    /// }
863    /// ```
864    ///
865    /// If a function does not take `&self` or `&mut self`, you must specify that
866    /// it's an instance function using `#[rune::function(instance)]`. The first
867    /// argument is then considered the instance the function gets associated with:
868    ///
869    /// ```rust
870    /// # use rune::Any;
871    /// #[derive(Any)]
872    /// struct Struct {
873    ///     /* .. */
874    /// }
875    ///
876    /// /// Get the length of the `Struct`.
877    /// #[rune::function(instance)]
878    /// fn len(this: &Struct) -> usize {
879    ///     /* .. */
880    ///     # todo!()
881    /// }
882    /// ```
883    ///
884    /// To declare an associated function which does not receive the type we
885    /// must specify the path to the function using `#[rune::function(path =
886    /// Self::<name>)]`:
887    ///
888    /// ```rust
889    /// # use rune::Any;
890    /// #[derive(Any)]
891    /// struct Struct {
892    ///     /* .. */
893    /// }
894    ///
895    /// impl Struct {
896    ///     /// Construct a new [`Struct`].
897    ///     #[rune::function(path = Self::new)]
898    ///     fn new() -> Struct {
899    ///         Struct {
900    ///            /* .. */
901    ///         }
902    ///     }
903    /// }
904    /// ```
905    ///
906    /// Or externally like this:
907    ///
908    /// ```rust
909    /// # use rune::Any;
910    /// #[derive(Any)]
911    /// struct Struct {
912    ///     /* .. */
913    /// }
914    ///
915    /// /// Construct a new [`Struct`].
916    /// #[rune::function(free, path = Struct::new)]
917    /// fn new() -> Struct {
918    ///     Struct {
919    ///        /* .. */
920    ///     }
921    /// }
922    /// ```
923    ///
924    /// The first part `Struct` in `Struct::new` is used to determine the type
925    /// the function is associated with.
926    ///
927    /// Protocol functions can either be defined in an impl block or externally.
928    /// To define a protocol externally, you can simply do this:
929    ///
930    /// ```rust
931    /// # use rune::Any;
932    /// # use rune::runtime::Formatter;
933    /// #[derive(Any)]
934    /// struct Struct {
935    ///     /* .. */
936    /// }
937    ///
938    /// #[rune::function(instance, protocol = DISPLAY_FMT)]
939    /// fn display_fmt(this: &Struct, f: &mut Formatter) -> std::fmt::Result {
940    ///     /* .. */
941    ///     # todo!()
942    /// }
943    /// ```
944    ///
945    /// # Examples
946    ///
947    /// ```
948    /// use rune::{Any, Module};
949    ///
950    /// #[derive(Any)]
951    /// struct MyBytes {
952    ///     queue: Vec<String>,
953    /// }
954    ///
955    /// impl MyBytes {
956    ///     /// Construct a new empty bytes container.
957    ///     #[rune::function(path = Self::new)]
958    ///     fn new() -> Self {
959    ///         Self {
960    ///             queue: Vec::new(),
961    ///         }
962    ///     }
963    ///
964    ///     /// Get the number of bytes.
965    ///     #[rune::function]
966    ///     fn len(&self) -> usize {
967    ///         self.queue.len()
968    ///     }
969    /// }
970    ///
971    /// let mut m = Module::default();
972    ///
973    /// m.ty::<MyBytes>()?;
974    /// m.function_meta(MyBytes::new)?;
975    /// m.function_meta(MyBytes::len)?;
976    /// # Ok::<_, rune::support::Error>(())
977    /// ```
978    ///
979    /// Asynchronous function:
980    ///
981    /// ```
982    /// use std::sync::atomic::AtomicU32;
983    /// use std::sync::Arc;
984    ///
985    /// use rune::{Any, Module, Ref};
986    ///
987    /// #[derive(Clone, Debug, Any)]
988    /// struct Client {
989    ///     value: Arc<AtomicU32>,
990    /// }
991    ///
992    /// #[derive(Any)]
993    /// struct DownloadError {
994    ///     /* .. */
995    /// }
996    ///
997    /// impl Client {
998    ///     /// Download a thing.
999    ///     #[rune::function(instance, path = Self::download)]
1000    ///     async fn download(this: Ref<Self>) -> Result<(), DownloadError> {
1001    ///         /* .. */
1002    ///         # Ok(())
1003    ///     }
1004    /// }
1005    ///
1006    /// let mut module = Module::default();
1007    ///
1008    /// module.ty::<Client>()?;
1009    /// module.function_meta(Client::download)?;
1010    /// # Ok::<_, rune::support::Error>(())
1011    /// ```
1012    pub fn associated_function<N, F, A, K>(
1013        &mut self,
1014        name: N,
1015        f: F,
1016    ) -> Result<ItemFnMut<'_>, ContextError>
1017    where
1018        N: ToInstance,
1019        F: InstanceFunction<A, K, Return: MaybeTypeOf>,
1020        A: FunctionArgs,
1021        K: FunctionKind,
1022    {
1023        self.insert_associated_function(
1024            AssociatedFunctionData::from_instance_function(name.to_instance()?, f)?,
1025            Docs::EMPTY,
1026            None,
1027        )
1028    }
1029
1030    /// Install a protocol function that interacts with the given field.
1031    ///
1032    /// This returns a [`ItemMut`], which is a handle that can be used to
1033    /// associate more metadata with the inserted item.
1034    pub fn field_function<N, F, A>(
1035        &mut self,
1036        protocol: &'static Protocol,
1037        name: N,
1038        f: F,
1039    ) -> Result<ItemFnMut<'_>, ContextError>
1040    where
1041        N: ToFieldFunction,
1042        F: InstanceFunction<A, Plain, Return: MaybeTypeOf>,
1043        A: FunctionArgs,
1044    {
1045        self.insert_associated_function(
1046            AssociatedFunctionData::from_instance_function(name.to_field_function(protocol)?, f)?,
1047            Docs::EMPTY,
1048            None,
1049        )
1050    }
1051
1052    /// Install a protocol function that interacts with the given index.
1053    ///
1054    /// An index can either be a field inside a tuple or the equivalent inside
1055    /// of a variant.
1056    pub fn index_function<F, A>(
1057        &mut self,
1058        protocol: &'static Protocol,
1059        index: usize,
1060        f: F,
1061    ) -> Result<ItemFnMut<'_>, ContextError>
1062    where
1063        F: InstanceFunction<A, Plain, Return: MaybeTypeOf>,
1064        A: FunctionArgs,
1065    {
1066        let name = AssociatedName::index(protocol, index);
1067        self.insert_associated_function(
1068            AssociatedFunctionData::from_instance_function(name, f)?,
1069            Docs::EMPTY,
1070            None,
1071        )
1072    }
1073
1074    /// Register a raw function which interacts directly with the virtual
1075    /// machine.
1076    ///
1077    /// This returns a [`ItemMut`], which is a handle that can be used to
1078    /// associate more metadata with the inserted item.
1079    ///
1080    /// # Examples
1081    ///
1082    /// ```
1083    /// use rune::Module;
1084    /// use rune::runtime::{Output, Memory, ToValue, VmError, Address};
1085    /// use rune::{docstring, vm_try};
1086    ///
1087    /// fn sum(memory: &mut dyn Memory, addr: Address, args: usize, out: Output) -> Result<(), VmError> {
1088    ///     let mut number = 0;
1089    ///
1090    ///     for value in memory.slice_at(addr, args)? {
1091    ///         number += value.as_integer::<i64>()?;
1092    ///     }
1093    ///
1094    ///     memory.store(out, number)?;
1095    ///     Ok(())
1096    /// }
1097    ///
1098    /// let mut module = Module::default();
1099    ///
1100    /// module.raw_function("sum", sum)
1101    ///     .build()?
1102    ///     .docs(docstring! {
1103    ///         /// Sum all numbers provided to the function.
1104    ///     })?;
1105    ///
1106    /// # Ok::<_, rune::support::Error>(())
1107    /// ```
1108    pub fn raw_function<N, F>(&mut self, name: N, handler: F) -> ModuleRawFunctionBuilder<'_, N, F>
1109    where
1110        F: 'static
1111            + Fn(&mut dyn Memory, Address, usize, Output) -> Result<(), VmError>
1112            + Send
1113            + Sync,
1114    {
1115        ModuleRawFunctionBuilder {
1116            module: self,
1117            name,
1118            handler,
1119        }
1120    }
1121
1122    fn function_inner(
1123        &mut self,
1124        data: FunctionData,
1125        docs: Docs,
1126        #[allow(unused)] deprecated: Option<Box<str>>,
1127    ) -> Result<ItemFnMut<'_>, ContextError> {
1128        let item = self.item.join(&data.item)?;
1129        let hash = Hash::type_hash(&item);
1130
1131        if !self.names.try_insert(Name::Item(hash))? {
1132            return Err(ContextError::ConflictingFunctionName { item, hash });
1133        }
1134
1135        self.items.try_push(ModuleItem {
1136            item,
1137            hash,
1138            common: ModuleItemCommon { docs, deprecated },
1139            kind: ModuleItemKind::Function(ModuleFunction {
1140                handler: data.handler,
1141                trait_hash: None,
1142                doc: DocFunction {
1143                    #[cfg(feature = "doc")]
1144                    is_async: data.is_async,
1145                    #[cfg(feature = "doc")]
1146                    args: data.args,
1147                    #[cfg(feature = "doc")]
1148                    return_type: data.return_type,
1149                    #[cfg(feature = "doc")]
1150                    argument_types: data.argument_types,
1151                },
1152            }),
1153        })?;
1154
1155        let last = self.items.last_mut().unwrap();
1156
1157        #[cfg(feature = "doc")]
1158        let last_fn = match &mut last.kind {
1159            ModuleItemKind::Function(f) => f,
1160            _ => unreachable!(),
1161        };
1162
1163        Ok(ItemFnMut {
1164            docs: &mut last.common.docs,
1165            #[cfg(feature = "doc")]
1166            deprecated: &mut last.common.deprecated,
1167            #[cfg(feature = "doc")]
1168            is_async: &mut last_fn.doc.is_async,
1169            #[cfg(feature = "doc")]
1170            args: &mut last_fn.doc.args,
1171            #[cfg(feature = "doc")]
1172            return_type: &mut last_fn.doc.return_type,
1173            #[cfg(feature = "doc")]
1174            argument_types: &mut last_fn.doc.argument_types,
1175        })
1176    }
1177
1178    /// Install an associated function.
1179    fn insert_associated_function(
1180        &mut self,
1181        data: AssociatedFunctionData,
1182        docs: Docs,
1183        #[allow(unused)] deprecated: Option<Box<str>>,
1184    ) -> Result<ItemFnMut<'_>, ContextError> {
1185        self.insert_associated_name(&data.associated)?;
1186
1187        self.associated.try_push(ModuleAssociated {
1188            container: data.associated.container,
1189            container_type_info: data.associated.container_type_info,
1190            name: data.associated.name,
1191            common: ModuleItemCommon { docs, deprecated },
1192            kind: ModuleAssociatedKind::Function(ModuleFunction {
1193                handler: data.handler,
1194                trait_hash: None,
1195                doc: DocFunction {
1196                    #[cfg(feature = "doc")]
1197                    is_async: data.is_async,
1198                    #[cfg(feature = "doc")]
1199                    args: data.args,
1200                    #[cfg(feature = "doc")]
1201                    return_type: data.return_type,
1202                    #[cfg(feature = "doc")]
1203                    argument_types: data.argument_types,
1204                },
1205            }),
1206        })?;
1207
1208        let last = self.associated.last_mut().unwrap();
1209
1210        #[cfg(feature = "doc")]
1211        let last_fn = match &mut last.kind {
1212            ModuleAssociatedKind::Function(f) => f,
1213            _ => unreachable!(),
1214        };
1215
1216        Ok(ItemFnMut {
1217            docs: &mut last.common.docs,
1218            #[cfg(feature = "doc")]
1219            deprecated: &mut last.common.deprecated,
1220            #[cfg(feature = "doc")]
1221            is_async: &mut last_fn.doc.is_async,
1222            #[cfg(feature = "doc")]
1223            args: &mut last_fn.doc.args,
1224            #[cfg(feature = "doc")]
1225            return_type: &mut last_fn.doc.return_type,
1226            #[cfg(feature = "doc")]
1227            argument_types: &mut last_fn.doc.argument_types,
1228        })
1229    }
1230
1231    fn insert_associated_name(&mut self, associated: &Associated) -> Result<(), ContextError> {
1232        if !self
1233            .names
1234            .try_insert(Name::Associated(associated.as_key()?))?
1235        {
1236            return Err(match &associated.name.kind {
1237                meta::AssociatedKind::Protocol(protocol) => {
1238                    ContextError::ConflictingProtocolFunction {
1239                        type_info: associated.container_type_info.try_clone()?,
1240                        name: protocol.name.try_into()?,
1241                    }
1242                }
1243                meta::AssociatedKind::FieldFn(protocol, field) => {
1244                    ContextError::ConflictingFieldFunction {
1245                        type_info: associated.container_type_info.try_clone()?,
1246                        name: protocol.name.try_into()?,
1247                        field: field.as_ref().try_into()?,
1248                    }
1249                }
1250                meta::AssociatedKind::IndexFn(protocol, index) => {
1251                    ContextError::ConflictingIndexFunction {
1252                        type_info: associated.container_type_info.try_clone()?,
1253                        name: protocol.name.try_into()?,
1254                        index: *index,
1255                    }
1256                }
1257                meta::AssociatedKind::Instance(name) => ContextError::ConflictingInstanceFunction {
1258                    type_info: associated.container_type_info.try_clone()?,
1259                    name: name.as_ref().try_into()?,
1260                },
1261            });
1262        }
1263
1264        Ok(())
1265    }
1266
1267    /// Define a new trait.
1268    pub fn define_trait(
1269        &mut self,
1270        item: impl IntoIterator<Item: IntoComponent>,
1271    ) -> Result<TraitMut<'_>, ContextError> {
1272        let item = self.item.join(item)?;
1273        let hash = Hash::type_hash(&item);
1274
1275        if !self.names.try_insert(Name::Item(hash))? {
1276            return Err(ContextError::ConflictingTrait { item, hash });
1277        }
1278
1279        self.traits.try_push(ModuleTrait {
1280            item,
1281            hash,
1282            common: ModuleItemCommon::default(),
1283            handler: None,
1284            functions: Vec::new(),
1285        })?;
1286
1287        let t = self.traits.last_mut().unwrap();
1288
1289        Ok(TraitMut {
1290            docs: &mut t.common.docs,
1291            #[cfg(feature = "doc")]
1292            deprecated: &mut t.common.deprecated,
1293            handler: &mut t.handler,
1294            functions: &mut t.functions,
1295        })
1296    }
1297
1298    /// Implement the trait `trait_item` for the type `T`.
1299    pub fn implement_trait<T>(&mut self, trait_item: &Item) -> Result<(), ContextError>
1300    where
1301        T: ?Sized + TypeOf + Named,
1302    {
1303        let hash = T::HASH;
1304        let type_info = T::type_info();
1305        let trait_hash = Hash::type_hash(trait_item);
1306
1307        if !self.names.try_insert(Name::TraitImpl(hash, trait_hash))? {
1308            return Err(ContextError::ConflictingTraitImpl {
1309                trait_item: trait_item.try_to_owned()?,
1310                trait_hash,
1311                item: T::ITEM.try_to_owned()?,
1312                hash,
1313            });
1314        }
1315
1316        self.trait_impls.try_push(ModuleTraitImpl {
1317            item: T::ITEM.try_to_owned()?,
1318            hash,
1319            type_info,
1320            trait_item: trait_item.try_to_owned()?,
1321            trait_hash,
1322        })?;
1323
1324        Ok(())
1325    }
1326
1327    /// Define a re-export.
1328    pub fn reexport(
1329        &mut self,
1330        item: impl IntoIterator<Item: IntoComponent>,
1331        to: &Item,
1332    ) -> Result<(), ContextError> {
1333        let item = self.item.join(item)?;
1334        let hash = Hash::type_hash(&item);
1335
1336        if !self.names.try_insert(Name::Item(hash))? {
1337            return Err(ContextError::ConflictingReexport {
1338                item,
1339                hash,
1340                to: to.try_to_owned()?,
1341            });
1342        }
1343
1344        self.reexports.try_push(ModuleReexport {
1345            item,
1346            hash,
1347            to: to.try_to_owned()?,
1348        })?;
1349
1350        Ok(())
1351    }
1352}
1353
1354impl AsRef<Module> for Module {
1355    #[inline]
1356    fn as_ref(&self) -> &Module {
1357        self
1358    }
1359}