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}