1use core::fmt;
2
3use crate as rune;
4use crate::alloc::prelude::*;
5use crate::alloc::{self, BTreeSet, Box, HashMap, HashSet, String, Vec};
6#[cfg(feature = "emit")]
7use crate::compile::MetaInfo;
8use crate::compile::{self, ContextError, Names};
9use crate::compile::{meta, Docs};
10use crate::function::{Function, Plain};
11use crate::function_meta::{AssociatedName, ToInstance};
12use crate::hash;
13use crate::item::{ComponentRef, IntoComponent};
14use crate::macros::{MacroContext, TokenStream};
15use crate::module::{
16 DocFunction, Fields, Module, ModuleAssociated, ModuleAssociatedKind, ModuleFunction,
17 ModuleItem, ModuleItemCommon, ModuleReexport, ModuleTrait, ModuleTraitImpl, ModuleType,
18 TypeSpecification,
19};
20use crate::runtime::{
21 Address, AnyTypeInfo, ConstConstructImpl, ConstContext, ConstValue, FunctionHandler, Memory,
22 Output, Protocol, Rtti, RttiKind, RuntimeContext, TypeInfo, VmError,
23};
24use crate::sync::Arc;
25use crate::{Hash, Item, ItemBuf};
26
27crate::declare_dyn_fn! {
28 struct MacroHandlerVtable;
29
30 pub struct MacroHandler {
32 fn call(cx: &mut MacroContext<'_, '_, '_>, input: &TokenStream) -> compile::Result<TokenStream>;
33 }
34}
35
36crate::declare_dyn_fn! {
37 struct TraitHandlerVtable;
38
39 pub struct TraitHandler {
41 fn call(cx: &mut TraitContext<'_>) -> Result<(), ContextError>;
42 }
43}
44
45crate::declare_dyn_fn! {
46 struct AttributeMacroHandlerVtable;
47
48 pub struct AttributeMacroHandler {
50 fn call(cx: &mut MacroContext<'_, '_, '_>, input: &TokenStream, attributes: &TokenStream) -> compile::Result<TokenStream>;
51 }
52}
53
54pub struct TraitContext<'a> {
56 cx: &'a mut Context,
58 item: &'a Item,
60 hash: Hash,
62 type_info: &'a TypeInfo,
64 trait_item: &'a Item,
66 trait_hash: Hash,
68}
69
70impl TraitContext<'_> {
71 pub fn item(&self) -> &Item {
73 self.item
74 }
75
76 pub fn hash(&self) -> Hash {
78 self.hash
79 }
80
81 pub fn find(&mut self, protocol: &'static Protocol) -> Result<FunctionHandler, ContextError> {
85 let name = protocol.to_instance()?;
86
87 let hash = name
88 .kind
89 .hash(self.hash)
90 .with_function_parameters(name.function_parameters);
91
92 let Some(handler) = self.cx.functions.get(&hash) else {
93 return Err(ContextError::MissingTraitFunction {
94 name: name.kind.try_to_string()?,
95 item: self.item.try_to_owned()?,
96 hash,
97 trait_item: self.trait_item.try_to_owned()?,
98 trait_hash: self.trait_hash,
99 });
100 };
101
102 let handler = handler.clone();
103
104 if let Some(method) = protocol.method {
105 self.function_handler(method, &handler)?;
106 }
107
108 Ok(handler)
109 }
110
111 pub fn try_find(&self, name: impl ToInstance) -> Result<Option<FunctionHandler>, ContextError> {
115 let name = name.to_instance()?;
116
117 let hash = name
118 .kind
119 .hash(self.hash)
120 .with_function_parameters(name.function_parameters);
121
122 Ok(self.cx.functions.get(&hash).cloned())
123 }
124
125 pub fn find_or_define<A, F>(
127 &mut self,
128 protocol: &'static Protocol,
129 function: F,
130 ) -> Result<FunctionHandler, ContextError>
131 where
132 F: Function<A, Plain>,
133 {
134 let function = if let Some(function) = self.try_find(protocol)? {
135 function
136 } else {
137 self.function(protocol, function)?
138 };
139
140 if let Some(method) = protocol.method {
141 self.function_handler(method, &function)?;
142 }
143
144 Ok(function)
145 }
146
147 pub fn function<F, A>(
149 &mut self,
150 name: impl ToInstance,
151 handler: F,
152 ) -> Result<FunctionHandler, ContextError>
153 where
154 F: Function<A, Plain>,
155 {
156 let handler = FunctionHandler::new(move |memory, addr, len, out| {
157 handler.call(memory, addr, len, out)
158 })?;
159 self.function_handler(name, &handler)?;
160 Ok(handler)
161 }
162
163 pub fn raw_function<F>(
165 &mut self,
166 name: impl ToInstance,
167 handler: F,
168 ) -> Result<FunctionHandler, ContextError>
169 where
170 F: 'static
171 + Fn(&mut dyn Memory, Address, usize, Output) -> Result<(), VmError>
172 + Send
173 + Sync,
174 {
175 let handler = FunctionHandler::new(handler)?;
176 self.function_handler(name, &handler)?;
177 Ok(handler)
178 }
179
180 fn function_handler(
183 &mut self,
184 name: impl ToInstance,
185 handler: &FunctionHandler,
186 ) -> Result<(), ContextError> {
187 let name = name.to_instance()?;
188 self.function_inner(name, handler)
189 }
190
191 fn function_inner(
192 &mut self,
193 name: AssociatedName,
194 handler: &FunctionHandler,
195 ) -> Result<(), ContextError> {
196 let function = ModuleFunction {
197 handler: handler.clone(),
198 trait_hash: Some(self.trait_hash),
199 doc: DocFunction {
200 #[cfg(feature = "doc")]
201 is_async: false,
202 #[cfg(feature = "doc")]
203 args: None,
204 #[cfg(feature = "doc")]
205 argument_types: Box::default(),
206 #[cfg(feature = "doc")]
207 return_type: meta::DocType::empty(),
208 },
209 };
210
211 let assoc = ModuleAssociated {
212 container: self.hash,
213 container_type_info: self.type_info.try_clone()?,
214 name,
215 common: ModuleItemCommon {
216 docs: Docs::EMPTY,
217 deprecated: None,
218 },
219 kind: ModuleAssociatedKind::Function(function),
220 };
221
222 self.cx.install_associated(&assoc)?;
223 Ok(())
224 }
225}
226
227#[derive(Debug)]
229#[non_exhaustive]
230pub(crate) struct ContextMeta {
231 pub(crate) hash: Hash,
233 pub(crate) item: Option<ItemBuf>,
235 pub(crate) kind: meta::Kind,
237 #[cfg(feature = "doc")]
239 pub(crate) deprecated: Option<Box<str>>,
240 #[cfg(feature = "doc")]
242 pub(crate) docs: Docs,
243}
244
245impl ContextMeta {
246 #[cfg(feature = "emit")]
247 pub(crate) fn info(&self) -> alloc::Result<MetaInfo> {
248 MetaInfo::new(&self.kind, self.hash, self.item.as_deref())
249 }
250}
251
252#[derive(Debug, TryClone)]
254#[non_exhaustive]
255pub(crate) struct ContextType {
256 item: ItemBuf,
258 hash: Hash,
260 type_info: TypeInfo,
262 type_parameters: Hash,
264}
265
266impl fmt::Display for ContextType {
267 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
268 write!(fmt, "{} => {}", self.item, self.type_info)?;
269 Ok(())
270 }
271}
272
273#[derive(Default)]
285pub struct Context {
286 unique: HashSet<&'static str>,
288 has_default_modules: bool,
290 meta: Vec<ContextMeta>,
292 hash_to_meta: hash::Map<Vec<usize>>,
294 item_to_hash: HashMap<ItemBuf, BTreeSet<Hash>>,
296 functions: hash::Map<FunctionHandler>,
298 deprecations: hash::Map<String>,
300 #[cfg(feature = "doc")]
302 associated: hash::Map<Vec<Hash>>,
303 #[cfg(feature = "doc")]
305 implemented_traits: hash::Map<Vec<Hash>>,
306 macros: hash::Map<MacroHandler>,
308 traits: hash::Map<Option<TraitHandler>>,
310 attribute_macros: hash::Map<AttributeMacroHandler>,
312 types: hash::Map<ContextType>,
314 names: Names,
316 crates: HashSet<Box<str>>,
318 constants: hash::Map<ConstValue>,
320 construct: hash::Map<ConstConstructImpl>,
322}
323
324impl Context {
325 #[inline]
327 pub fn new() -> Self {
328 Self::default()
329 }
330
331 pub fn with_config(#[allow(unused)] stdio: bool) -> Result<Self, ContextError> {
345 let mut this = Self::new();
346
347 this.install(crate::modules::iter::module()?)?;
351 this.install(crate::modules::core::module()?)?;
352 this.install(crate::modules::cmp::module()?)?;
353 this.install(crate::modules::any::module()?)?;
354 this.install(crate::modules::clone::module()?)?;
355 this.install(crate::modules::num::module()?)?;
356 this.install(crate::modules::hash::module()?)?;
357
358 this.install(crate::modules::string::module()?)?;
359 this.install(crate::modules::bytes::module()?)?;
360
361 this.install(crate::modules::collections::module()?)?;
362 this.install(crate::modules::collections::hash_map::module()?)?;
363 this.install(crate::modules::collections::hash_set::module()?)?;
364 this.install(crate::modules::collections::vec_deque::module()?)?;
365
366 this.install(crate::modules::char::module()?)?;
367 this.install(crate::modules::f64::module()?)?;
368 this.install(crate::modules::f64::consts::module()?)?;
369 this.install(crate::modules::tuple::module()?)?;
370 this.install(crate::modules::fmt::module()?)?;
371 this.install(crate::modules::future::module()?)?;
372 this.install(crate::modules::i64::module()?)?;
373 this.install(crate::modules::u64::module()?)?;
374 this.install(crate::modules::io::module(stdio)?)?;
375 this.install(crate::modules::macros::module()?)?;
376 this.install(crate::modules::macros::builtin::module()?)?;
377 this.install(crate::modules::mem::module()?)?;
378 this.install(crate::modules::object::module()?)?;
379 this.install(crate::modules::ops::module()?)?;
380 this.install(crate::modules::ops::generator::module()?)?;
381 this.install(crate::modules::option::module()?)?;
382 this.install(crate::modules::result::module()?)?;
383 this.install(crate::modules::stream::module()?)?;
384 this.install(crate::modules::test::module()?)?;
385 this.install(crate::modules::vec::module()?)?;
386 this.install(crate::modules::slice::module()?)?;
387 this.has_default_modules = true;
388 Ok(this)
389 }
390
391 pub fn with_default_modules() -> Result<Self, ContextError> {
393 Self::with_config(true)
394 }
395
396 pub fn runtime(&self) -> alloc::Result<RuntimeContext> {
414 Ok(RuntimeContext::new(
415 self.functions.try_clone()?,
416 self.constants.try_clone()?,
417 self.construct.try_clone()?,
418 self.deprecations.try_clone()?,
419 ))
420 }
421
422 #[tracing::instrument(skip_all, fields(item = ?module.as_ref().item))]
428 pub fn install<M>(&mut self, module: M) -> Result<(), ContextError>
429 where
430 M: AsRef<Module>,
431 {
432 let module = module.as_ref();
433 tracing::trace!("installing");
434
435 if let Some(id) = module.unique {
436 if !self.unique.try_insert(id)? {
437 return Ok(());
438 }
439 }
440
441 if let Some(ComponentRef::Crate(name)) = module.item.first() {
442 self.crates.try_insert(name.try_into()?)?;
443 }
444
445 tracing::trace!("module");
446 self.install_module(module)?;
447
448 tracing::trace!(types = module.types.len(), "types");
449 for ty in &module.types {
450 self.install_type(ty)?;
451 }
452
453 tracing::trace!(traits = module.traits.len(), "traits");
454 for t in &module.traits {
455 self.install_trait(t)?;
456 }
457
458 tracing::trace!(items = module.items.len(), "items");
459 for item in &module.items {
460 self.install_item(item)?;
461 }
462
463 tracing::trace!(associated = module.associated.len(), "associated");
464 for assoc in &module.associated {
465 self.install_associated(assoc)?;
466 }
467
468 tracing::trace!(trait_impls = module.trait_impls.len(), "trait impls");
469 for t in &module.trait_impls {
470 self.install_trait_impl(t)?;
471 }
472
473 tracing::trace!(reexports = module.reexports.len(), "reexports");
474 for r in &module.reexports {
475 self.install_reexport(r)?;
476 }
477
478 tracing::trace!(construct = module.construct.len(), "construct");
479 for (hash, type_info, construct) in &module.construct {
480 self.install_construct(*hash, type_info, construct)?;
481 }
482
483 Ok(())
484 }
485
486 #[cfg(any(feature = "cli", feature = "languageserver"))]
488 pub(crate) fn iter_functions(&self) -> impl Iterator<Item = (&ContextMeta, &meta::Signature)> {
489 self.meta.iter().flat_map(|meta| {
490 let signature = meta.kind.as_signature()?;
491 Some((meta, signature))
492 })
493 }
494
495 #[cfg(feature = "cli")]
497 pub(crate) fn iter_types(&self) -> impl Iterator<Item = (Hash, &Item)> {
498 use core::iter;
499
500 let mut it = self.types.iter();
501
502 iter::from_fn(move || {
503 let (hash, ty) = it.next()?;
504 Some((*hash, ty.item.as_ref()))
505 })
506 }
507
508 pub(crate) fn iter_components<'a, I>(
510 &'a self,
511 iter: I,
512 ) -> alloc::Result<impl Iterator<Item = ComponentRef<'a>> + 'a>
513 where
514 I: 'a + IntoIterator<Item: IntoComponent>,
515 {
516 self.names.iter_components(iter)
517 }
518
519 pub(crate) fn lookup_meta(
524 &self,
525 item: &Item,
526 ) -> Option<impl Iterator<Item = &ContextMeta> + Clone> {
527 let hashes = self.item_to_hash.get(item)?;
528
529 Some(hashes.iter().flat_map(|hash| {
530 let indexes = self
531 .hash_to_meta
532 .get(hash)
533 .map(Vec::as_slice)
534 .unwrap_or_default();
535 indexes.iter().map(|&i| &self.meta[i])
536 }))
537 }
538
539 #[cfg(any(feature = "cli", feature = "languageserver", feature = "emit"))]
541 pub(crate) fn lookup_meta_by_hash(
542 &self,
543 hash: Hash,
544 ) -> impl ExactSizeIterator<Item = &ContextMeta> + Clone {
545 let indexes = self
546 .hash_to_meta
547 .get(&hash)
548 .map(Vec::as_slice)
549 .unwrap_or_default();
550
551 indexes.iter().map(|&i| &self.meta[i])
552 }
553
554 pub fn lookup_deprecation(&self, hash: Hash) -> Option<&str> {
556 self.deprecations.get(&hash).map(|s| s.as_str())
557 }
558
559 pub(crate) fn contains_prefix(&self, item: &Item) -> alloc::Result<bool> {
561 self.names.contains_prefix(item)
562 }
563
564 pub(crate) fn lookup_function(&self, hash: Hash) -> Option<&FunctionHandler> {
566 self.functions.get(&hash)
567 }
568
569 #[cfg(all(feature = "doc", feature = "cli"))]
571 pub(crate) fn associated(&self, hash: Hash) -> impl Iterator<Item = Hash> + '_ {
572 self.associated
573 .get(&hash)
574 .map(Vec::as_slice)
575 .unwrap_or_default()
576 .iter()
577 .copied()
578 }
579
580 #[cfg(all(feature = "doc", feature = "cli"))]
582 pub(crate) fn traits(&self, hash: Hash) -> impl Iterator<Item = Hash> + '_ {
583 self.implemented_traits
584 .get(&hash)
585 .map(Vec::as_slice)
586 .unwrap_or_default()
587 .iter()
588 .copied()
589 }
590
591 pub(crate) fn lookup_macro(&self, hash: Hash) -> Option<&MacroHandler> {
593 self.macros.get(&hash)
594 }
595
596 pub(crate) fn lookup_attribute_macro(&self, hash: Hash) -> Option<&AttributeMacroHandler> {
598 self.attribute_macros.get(&hash)
599 }
600
601 #[cfg(feature = "cli")]
603 pub(crate) fn iter_crates(&self) -> impl Iterator<Item = &str> {
604 self.crates.iter().map(|s| s.as_ref())
605 }
606
607 pub(crate) fn contains_crate(&self, name: &str) -> bool {
609 self.crates.contains(name)
610 }
611
612 pub(crate) fn has_default_modules(&self) -> bool {
617 self.has_default_modules
618 }
619
620 fn find_existing_module(&self, hash: Hash) -> Option<usize> {
622 let indexes = self.hash_to_meta.get(&hash)?;
623
624 for &index in indexes {
625 let Some(m) = self.meta.get(index) else {
626 continue;
627 };
628
629 if matches!(m.kind, meta::Kind::Module) {
630 return Some(index);
631 }
632 }
633
634 None
635 }
636
637 #[tracing::instrument(skip_all)]
639 fn install_meta(&mut self, meta: ContextMeta) -> Result<(), ContextError> {
640 if let Some(item) = &meta.item {
641 tracing::trace!(?item);
642
643 self.names.insert(item)?;
644
645 self.item_to_hash
646 .entry(item.try_clone()?)
647 .or_try_default()?
648 .try_insert(meta.hash)?;
649 }
650
651 #[cfg(feature = "doc")]
652 if let Some(h) = meta.kind.associated_container() {
653 let assoc = self.associated.entry(h).or_try_default()?;
654 assoc.try_push(meta.hash)?;
655 }
656
657 let hash = meta.hash;
658
659 let index = self.meta.len();
660
661 self.meta.try_push(meta)?;
662
663 self.hash_to_meta
664 .entry(hash)
665 .or_try_default()?
666 .try_push(index)?;
667
668 Ok(())
669 }
670
671 fn install_module(&mut self, m: &Module) -> Result<(), ContextError> {
673 self.names.insert(&m.item)?;
674
675 let mut current = Some((m.item.as_ref(), Some(&m.common)));
676
677 #[allow(unused)]
678 while let Some((item, common)) = current.take() {
679 let hash = Hash::type_hash(item);
680
681 if let Some(index) = self.find_existing_module(hash) {
682 #[cfg(feature = "doc")]
683 if let Some(common) = common {
684 let meta = &mut self.meta[index];
685 meta.deprecated = common.deprecated.try_clone()?;
686 meta.docs = common.docs.try_clone()?;
687 }
688 } else {
689 self.install_meta(ContextMeta {
690 hash,
691 item: Some(item.try_to_owned()?),
692 kind: meta::Kind::Module,
693 #[cfg(feature = "doc")]
694 deprecated: common
695 .map(|c| c.deprecated.as_ref().try_cloned())
696 .transpose()?
697 .flatten(),
698 #[cfg(feature = "doc")]
699 docs: common
700 .map(|c| c.docs.try_clone())
701 .transpose()?
702 .unwrap_or_default(),
703 })?;
704 }
705
706 current = item.parent().map(|item| (item, None));
707 }
708
709 Ok(())
710 }
711
712 fn install_type(&mut self, ty: &ModuleType) -> Result<(), ContextError> {
714 self.install_type_info(ContextType {
715 item: ty.item.try_to_owned()?,
716 hash: ty.hash,
717 type_info: ty.type_info.try_clone()?,
718 type_parameters: ty.type_parameters,
719 })?;
720
721 let parameters = Hash::EMPTY.with_type_parameters(ty.type_parameters);
722
723 let kind = if let Some(spec) = &ty.spec {
724 match spec {
725 TypeSpecification::Struct(fields) => {
726 let constructor = match &ty.constructor {
727 Some(c) => {
728 let signature = meta::Signature {
729 #[cfg(feature = "doc")]
730 is_async: false,
731 #[cfg(feature = "doc")]
732 arguments: Some(fields_to_arguments(fields)?),
733 #[cfg(feature = "doc")]
734 return_type: meta::DocType::new(ty.hash),
735 };
736
737 if c.args != fields.len() {
738 return Err(ContextError::ConstructorArgumentsMismatch {
739 type_info: ty.type_info.try_clone()?,
740 expected: fields.len(),
741 actual: c.args,
742 });
743 }
744
745 self.insert_native_fn(&ty.type_info, ty.hash, &c.handler, None)?;
746 Some(signature)
747 }
748 None => None,
749 };
750
751 meta::Kind::Struct {
752 fields: match fields {
753 Fields::Named(fields) => meta::Fields::Named(meta::FieldsNamed {
754 fields: fields
755 .iter()
756 .copied()
757 .enumerate()
758 .map(|(position, name)| {
759 Ok(meta::FieldMeta {
760 name: name.try_into()?,
761 position,
762 })
763 })
764 .try_collect::<alloc::Result<_>>()??,
765 }),
766 Fields::Unnamed(args) => meta::Fields::Unnamed(*args),
767 Fields::Empty => meta::Fields::Empty,
768 },
769 constructor,
770 parameters,
771 enum_hash: Hash::EMPTY,
772 }
773 }
774 TypeSpecification::Enum(en) => {
775 for variant in &en.variants {
776 let Some(fields) = &variant.fields else {
777 continue;
778 };
779
780 let kind = match fields {
781 Fields::Empty => RttiKind::Empty,
782 Fields::Unnamed(..) => RttiKind::Tuple,
783 Fields::Named(..) => RttiKind::Struct,
784 };
785
786 let item = ty.item.extended(variant.name)?;
787 let hash = Hash::type_hash(&item);
788
789 self.install_type_info(ContextType {
790 item: item.try_clone()?,
791 hash,
792 type_info: TypeInfo::rtti(Arc::try_new(Rtti {
793 kind,
794 hash: ty.hash,
795 variant_hash: hash,
796 item: item.try_clone()?,
797 fields: fields.to_fields()?,
798 })?),
799 type_parameters: Hash::EMPTY,
800 })?;
801
802 let constructor = if let Some(c) = &variant.constructor {
803 let signature = meta::Signature {
804 #[cfg(feature = "doc")]
805 is_async: false,
806 #[cfg(feature = "doc")]
807 arguments: Some(fields_to_arguments(fields)?),
808 #[cfg(feature = "doc")]
809 return_type: meta::DocType::new(ty.hash),
810 };
811
812 if c.args != fields.len() {
813 return Err(ContextError::VariantConstructorArgumentsMismatch {
814 type_info: ty.type_info.try_clone()?,
815 name: variant.name,
816 expected: fields.len(),
817 actual: c.args,
818 });
819 }
820
821 self.insert_native_fn(
822 &item,
823 hash,
824 &c.handler,
825 variant.deprecated.as_deref(),
826 )?;
827 Some(signature)
828 } else {
829 None
830 };
831
832 self.install_meta(ContextMeta {
833 hash,
834 item: Some(item),
835 kind: meta::Kind::Struct {
836 fields: match fields {
837 Fields::Named(names) => {
838 meta::Fields::Named(meta::FieldsNamed {
839 fields: names
840 .iter()
841 .copied()
842 .enumerate()
843 .map(|(position, name)| {
844 Ok(meta::FieldMeta {
845 name: name.try_into()?,
846 position,
847 })
848 })
849 .try_collect::<alloc::Result<_>>()??,
850 })
851 }
852 Fields::Unnamed(args) => meta::Fields::Unnamed(*args),
853 Fields::Empty => meta::Fields::Empty,
854 },
855 constructor,
856 parameters: Hash::EMPTY,
857 enum_hash: ty.hash,
858 },
859 #[cfg(feature = "doc")]
860 deprecated: variant.deprecated.try_clone()?,
861 #[cfg(feature = "doc")]
862 docs: variant.docs.try_clone()?,
863 })?;
864 }
865
866 meta::Kind::Enum { parameters }
867 }
868 }
869 } else {
870 meta::Kind::Type { parameters }
871 };
872
873 self.install_meta(ContextMeta {
874 hash: ty.hash,
875 item: Some(ty.item.try_to_owned()?),
876 kind,
877 #[cfg(feature = "doc")]
878 deprecated: ty.common.deprecated.try_clone()?,
879 #[cfg(feature = "doc")]
880 docs: ty.common.docs.try_clone()?,
881 })?;
882
883 Ok(())
884 }
885
886 fn install_trait(&mut self, t: &ModuleTrait) -> Result<(), ContextError> {
887 if self.traits.try_insert(t.hash, t.handler.clone())?.is_some() {
888 return Err(ContextError::ConflictingTrait {
889 item: t.item.try_clone()?,
890 hash: t.hash,
891 });
892 }
893
894 self.install_meta(ContextMeta {
895 hash: t.hash,
896 item: Some(t.item.try_clone()?),
897 kind: meta::Kind::Trait,
898 #[cfg(feature = "doc")]
899 deprecated: t.common.deprecated.try_clone()?,
900 #[cfg(feature = "doc")]
901 docs: t.common.docs.try_clone()?,
902 })?;
903
904 for f in &t.functions {
905 let signature = meta::Signature::from_context(&f.doc, &f.common)?;
906
907 let kind = meta::Kind::Function {
908 associated: Some(f.name.kind.try_clone()?),
909 trait_hash: None,
910 signature,
911 is_test: false,
912 is_bench: false,
913 parameters: Hash::EMPTY.with_function_parameters(f.name.function_parameters),
914 #[cfg(feature = "doc")]
915 container: Some(t.hash),
916 #[cfg(feature = "doc")]
917 parameter_types: f.name.parameter_types.try_clone()?,
918 };
919
920 let hash = f
921 .name
922 .kind
923 .hash(t.hash)
924 .with_function_parameters(f.name.function_parameters);
925
926 let item = if let meta::AssociatedKind::Instance(name) = &f.name.kind {
927 let item = t.item.extended(name.as_ref())?;
928 let hash = Hash::type_hash(&item);
929 Some((hash, item))
930 } else {
931 None
932 };
933
934 self.install_meta(ContextMeta {
935 hash,
936 item: item.map(|(_, item)| item),
937 kind,
938 #[cfg(feature = "doc")]
939 deprecated: f.common.deprecated.try_clone()?,
940 #[cfg(feature = "doc")]
941 docs: f.common.docs.try_clone()?,
942 })?;
943 }
944
945 Ok(())
946 }
947
948 fn install_trait_impl(&mut self, i: &ModuleTraitImpl) -> Result<(), ContextError> {
949 if !self.types.contains_key(&i.hash) {
950 return Err(ContextError::MissingType {
951 item: i.item.try_to_owned()?,
952 type_info: i.type_info.try_clone()?,
953 });
954 };
955
956 let Some(handler) = self.traits.get(&i.trait_hash).cloned() else {
957 return Err(ContextError::MissingTrait {
958 item: i.trait_item.try_clone()?,
959 hash: i.hash,
960 impl_item: i.item.try_to_owned()?,
961 impl_hash: i.hash,
962 });
963 };
964
965 if let Some(handler) = handler {
966 handler.call(&mut TraitContext {
967 cx: self,
968 item: &i.item,
969 hash: i.hash,
970 type_info: &i.type_info,
971 trait_item: &i.trait_item,
972 trait_hash: i.trait_hash,
973 })?;
974 }
975
976 #[cfg(feature = "doc")]
977 self.implemented_traits
978 .entry(i.hash)
979 .or_try_default()?
980 .try_push(i.trait_hash)?;
981
982 Ok(())
983 }
984
985 fn install_reexport(&mut self, r: &ModuleReexport) -> Result<(), ContextError> {
986 self.install_meta(ContextMeta {
987 hash: r.hash,
988 item: Some(r.item.try_clone()?),
989 kind: meta::Kind::Alias(meta::Alias {
990 to: r.to.try_clone()?,
991 }),
992 #[cfg(feature = "doc")]
993 deprecated: None,
994 #[cfg(feature = "doc")]
995 docs: Docs::EMPTY,
996 })?;
997
998 Ok(())
999 }
1000
1001 fn install_construct(
1003 &mut self,
1004 hash: Hash,
1005 type_info: &AnyTypeInfo,
1006 construct: &ConstConstructImpl,
1007 ) -> Result<(), ContextError> {
1008 let old = self.construct.try_insert(hash, construct.clone())?;
1009
1010 if old.is_some() {
1011 return Err(ContextError::ConflictingConstConstruct {
1012 type_info: TypeInfo::from(*type_info),
1013 hash,
1014 });
1015 }
1016
1017 Ok(())
1018 }
1019
1020 fn install_type_info(&mut self, ty: ContextType) -> Result<(), ContextError> {
1021 let item_hash = Hash::type_hash(&ty.item).with_type_parameters(ty.type_parameters);
1022
1023 if ty.hash != item_hash {
1024 return Err(ContextError::TypeHashMismatch {
1025 type_info: ty.type_info,
1026 item: ty.item,
1027 hash: ty.hash,
1028 item_hash,
1029 });
1030 }
1031
1032 self.constants.try_insert(
1033 Hash::associated_function(ty.hash, &Protocol::INTO_TYPE_NAME),
1034 ConstValue::try_from(ty.item.try_to_string()?)?,
1035 )?;
1036
1037 if let Some(old) = self.types.try_insert(ty.hash, ty)? {
1038 return Err(ContextError::ConflictingType {
1039 item: old.item,
1040 type_info: old.type_info,
1041 hash: old.hash,
1042 });
1043 }
1044
1045 Ok(())
1046 }
1047
1048 fn install_item(&mut self, m: &ModuleItem) -> Result<(), ContextError> {
1050 self.names.insert(&m.item)?;
1051
1052 let kind = match &m.kind {
1053 rune::module::ModuleItemKind::Constant(value) => {
1054 self.constants.try_insert(m.hash, value.try_clone()?)?;
1055 meta::Kind::Const
1056 }
1057 rune::module::ModuleItemKind::Function(f) => {
1058 self.constants.try_insert(
1059 Hash::associated_function(m.hash, &Protocol::INTO_TYPE_NAME),
1060 ConstValue::try_from(m.item.try_to_string()?)?,
1061 )?;
1062
1063 let signature = meta::Signature::from_context(&f.doc, &m.common)?;
1064
1065 self.insert_native_fn(&m.item, m.hash, &f.handler, m.common.deprecated.as_deref())?;
1066
1067 meta::Kind::Function {
1068 associated: None,
1069 trait_hash: f.trait_hash,
1070 signature,
1071 is_test: false,
1072 is_bench: false,
1073 parameters: Hash::EMPTY,
1074 #[cfg(feature = "doc")]
1075 container: None,
1076 #[cfg(feature = "doc")]
1077 parameter_types: Vec::new(),
1078 }
1079 }
1080 rune::module::ModuleItemKind::Macro(macro_) => {
1081 self.macros.try_insert(m.hash, macro_.handler.clone())?;
1082 meta::Kind::Macro
1083 }
1084 rune::module::ModuleItemKind::AttributeMacro(macro_) => {
1085 self.attribute_macros
1086 .try_insert(m.hash, macro_.handler.clone())?;
1087 meta::Kind::AttributeMacro
1088 }
1089 };
1090
1091 self.install_meta(ContextMeta {
1092 hash: m.hash,
1093 item: Some(m.item.try_to_owned()?),
1094 kind,
1095 #[cfg(feature = "doc")]
1096 deprecated: m.common.deprecated.try_clone()?,
1097 #[cfg(feature = "doc")]
1098 docs: m.common.docs.try_clone()?,
1099 })?;
1100
1101 Ok(())
1102 }
1103
1104 fn install_associated(&mut self, assoc: &ModuleAssociated) -> Result<(), ContextError> {
1105 let Some(info) = self.types.get(&assoc.container).try_cloned()? else {
1106 return Err(ContextError::MissingContainer {
1107 container: assoc.container_type_info.try_clone()?,
1108 });
1109 };
1110
1111 let hash = assoc
1112 .name
1113 .kind
1114 .hash(assoc.container)
1115 .with_function_parameters(assoc.name.function_parameters);
1116
1117 let item = if let meta::AssociatedKind::Instance(name) = &assoc.name.kind {
1124 let item = info.item.extended(name.as_ref())?;
1125
1126 let hash = Hash::type_hash(&item)
1127 .with_type_parameters(info.type_parameters)
1128 .with_function_parameters(assoc.name.function_parameters);
1129
1130 Some((hash, item))
1131 } else {
1132 None
1133 };
1134
1135 let kind = match &assoc.kind {
1136 ModuleAssociatedKind::Constant(value) => {
1137 if let Some((hash, ..)) = item {
1138 self.constants.try_insert(hash, value.try_clone()?)?;
1139 }
1140
1141 self.constants.try_insert(hash, value.try_clone()?)?;
1142 meta::Kind::Const
1143 }
1144 ModuleAssociatedKind::Function(f) => {
1145 let signature = meta::Signature::from_context(&f.doc, &assoc.common)?;
1146
1147 if let Some((hash, item)) = &item {
1148 self.constants.try_insert(
1149 Hash::associated_function(*hash, &Protocol::INTO_TYPE_NAME),
1150 ConstValue::try_from(item.try_to_string()?)?,
1151 )?;
1152
1153 self.insert_native_fn(
1154 &assoc.container_type_info,
1155 *hash,
1156 &f.handler,
1157 assoc.common.deprecated.as_deref(),
1158 )?;
1159 }
1160
1161 self.insert_native_fn(
1162 &assoc.container_type_info,
1163 hash,
1164 &f.handler,
1165 assoc.common.deprecated.as_deref(),
1166 )?;
1167
1168 meta::Kind::Function {
1169 associated: Some(assoc.name.kind.try_clone()?),
1170 trait_hash: f.trait_hash,
1171 signature,
1172 is_test: false,
1173 is_bench: false,
1174 parameters: Hash::EMPTY
1175 .with_type_parameters(info.type_parameters)
1176 .with_function_parameters(assoc.name.function_parameters),
1177 #[cfg(feature = "doc")]
1178 container: Some(assoc.container),
1179 #[cfg(feature = "doc")]
1180 parameter_types: assoc.name.parameter_types.try_clone()?,
1181 }
1182 }
1183 };
1184
1185 self.install_meta(ContextMeta {
1186 hash,
1187 item: item.map(|(_, item)| item),
1188 kind,
1189 #[cfg(feature = "doc")]
1190 deprecated: assoc.common.deprecated.try_clone()?,
1191 #[cfg(feature = "doc")]
1192 docs: assoc.common.docs.try_clone()?,
1193 })?;
1194
1195 Ok(())
1196 }
1197
1198 fn insert_native_fn(
1199 &mut self,
1200 display: &dyn fmt::Display,
1201 hash: Hash,
1202 handler: &FunctionHandler,
1203 deprecation: Option<&str>,
1204 ) -> Result<(), ContextError> {
1205 if self.functions.contains_key(&hash) {
1206 return Err(ContextError::ConflictingFunction {
1207 part: display.try_to_string()?.try_into()?,
1208 hash,
1209 });
1210 }
1211
1212 self.functions.try_insert(hash, handler.clone())?;
1213
1214 if let Some(msg) = deprecation {
1215 self.deprecations.try_insert(hash, msg.try_to_owned()?)?;
1216 }
1217
1218 Ok(())
1219 }
1220
1221 pub(crate) fn get_const_value(&self, hash: Hash) -> Option<&ConstValue> {
1223 self.constants.get(&hash)
1224 }
1225}
1226
1227impl fmt::Debug for Context {
1228 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1229 write!(f, "Context")
1230 }
1231}
1232
1233impl ConstContext for Context {
1234 #[inline]
1235 fn get(&self, hash: Hash) -> Option<&ConstConstructImpl> {
1236 self.construct.get(&hash)
1237 }
1238}
1239
1240#[cfg(feature = "doc")]
1241fn fields_to_arguments(fields: &Fields) -> alloc::Result<Box<[meta::DocArgument]>> {
1242 match *fields {
1243 Fields::Named(fields) => {
1244 let mut out = Vec::try_with_capacity(fields.len())?;
1245
1246 for &name in fields {
1247 out.try_push(meta::DocArgument {
1248 name: meta::DocName::Name(Box::try_from(name)?),
1249 base: Hash::EMPTY,
1250 generics: Box::default(),
1251 })?;
1252 }
1253
1254 Box::try_from(out)
1255 }
1256 Fields::Unnamed(args) => {
1257 let mut out = Vec::try_with_capacity(args)?;
1258
1259 for n in 0..args {
1260 out.try_push(meta::DocArgument {
1261 name: meta::DocName::Index(n),
1262 base: Hash::EMPTY,
1263 generics: Box::default(),
1264 })?;
1265 }
1266
1267 Box::try_from(out)
1268 }
1269 Fields::Empty => Ok(Box::default()),
1270 }
1271}
1272
1273#[cfg(test)]
1274static_assertions::assert_impl_all!(Context: Send, Sync);