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 ))
419 }
420
421 #[tracing::instrument(skip_all, fields(item = ?module.as_ref().item))]
427 pub fn install<M>(&mut self, module: M) -> Result<(), ContextError>
428 where
429 M: AsRef<Module>,
430 {
431 let module = module.as_ref();
432 tracing::trace!("installing");
433
434 if let Some(id) = module.unique {
435 if !self.unique.try_insert(id)? {
436 return Ok(());
437 }
438 }
439
440 if let Some(ComponentRef::Crate(name)) = module.item.first() {
441 self.crates.try_insert(name.try_into()?)?;
442 }
443
444 tracing::trace!("module");
445 self.install_module(module)?;
446
447 tracing::trace!(types = module.types.len(), "types");
448 for ty in &module.types {
449 self.install_type(ty)?;
450 }
451
452 tracing::trace!(traits = module.traits.len(), "traits");
453 for t in &module.traits {
454 self.install_trait(t)?;
455 }
456
457 tracing::trace!(items = module.items.len(), "items");
458 for item in &module.items {
459 self.install_item(item)?;
460 }
461
462 tracing::trace!(associated = module.associated.len(), "associated");
463 for assoc in &module.associated {
464 self.install_associated(assoc)?;
465 }
466
467 tracing::trace!(trait_impls = module.trait_impls.len(), "trait impls");
468 for t in &module.trait_impls {
469 self.install_trait_impl(t)?;
470 }
471
472 tracing::trace!(reexports = module.reexports.len(), "reexports");
473 for r in &module.reexports {
474 self.install_reexport(r)?;
475 }
476
477 tracing::trace!(construct = module.construct.len(), "construct");
478 for (hash, type_info, construct) in &module.construct {
479 self.install_construct(*hash, type_info, construct)?;
480 }
481
482 Ok(())
483 }
484
485 #[cfg(any(feature = "cli", feature = "languageserver"))]
487 pub(crate) fn iter_functions(&self) -> impl Iterator<Item = (&ContextMeta, &meta::Signature)> {
488 self.meta.iter().flat_map(|meta| {
489 let signature = meta.kind.as_signature()?;
490 Some((meta, signature))
491 })
492 }
493
494 #[cfg(feature = "cli")]
496 pub(crate) fn iter_types(&self) -> impl Iterator<Item = (Hash, &Item)> {
497 use core::iter;
498
499 let mut it = self.types.iter();
500
501 iter::from_fn(move || {
502 let (hash, ty) = it.next()?;
503 Some((*hash, ty.item.as_ref()))
504 })
505 }
506
507 pub(crate) fn iter_components<'a, I>(
509 &'a self,
510 iter: I,
511 ) -> alloc::Result<impl Iterator<Item = ComponentRef<'a>> + 'a>
512 where
513 I: 'a + IntoIterator<Item: IntoComponent>,
514 {
515 self.names.iter_components(iter)
516 }
517
518 pub(crate) fn lookup_meta(
523 &self,
524 item: &Item,
525 ) -> Option<impl Iterator<Item = &ContextMeta> + Clone> {
526 let hashes = self.item_to_hash.get(item)?;
527
528 Some(hashes.iter().flat_map(|hash| {
529 let indexes = self
530 .hash_to_meta
531 .get(hash)
532 .map(Vec::as_slice)
533 .unwrap_or_default();
534 indexes.iter().map(|&i| &self.meta[i])
535 }))
536 }
537
538 #[cfg(any(feature = "cli", feature = "languageserver", feature = "emit"))]
540 pub(crate) fn lookup_meta_by_hash(
541 &self,
542 hash: Hash,
543 ) -> impl ExactSizeIterator<Item = &ContextMeta> + Clone {
544 let indexes = self
545 .hash_to_meta
546 .get(&hash)
547 .map(Vec::as_slice)
548 .unwrap_or_default();
549
550 indexes.iter().map(|&i| &self.meta[i])
551 }
552
553 pub fn lookup_deprecation(&self, hash: Hash) -> Option<&str> {
555 self.deprecations.get(&hash).map(|s| s.as_str())
556 }
557
558 pub(crate) fn contains_prefix(&self, item: &Item) -> alloc::Result<bool> {
560 self.names.contains_prefix(item)
561 }
562
563 pub(crate) fn lookup_function(&self, hash: Hash) -> Option<&FunctionHandler> {
565 self.functions.get(&hash)
566 }
567
568 #[cfg(all(feature = "doc", feature = "cli"))]
570 pub(crate) fn associated(&self, hash: Hash) -> impl Iterator<Item = Hash> + '_ {
571 self.associated
572 .get(&hash)
573 .map(Vec::as_slice)
574 .unwrap_or_default()
575 .iter()
576 .copied()
577 }
578
579 #[cfg(all(feature = "doc", feature = "cli"))]
581 pub(crate) fn traits(&self, hash: Hash) -> impl Iterator<Item = Hash> + '_ {
582 self.implemented_traits
583 .get(&hash)
584 .map(Vec::as_slice)
585 .unwrap_or_default()
586 .iter()
587 .copied()
588 }
589
590 pub(crate) fn lookup_macro(&self, hash: Hash) -> Option<&MacroHandler> {
592 self.macros.get(&hash)
593 }
594
595 pub(crate) fn lookup_attribute_macro(&self, hash: Hash) -> Option<&AttributeMacroHandler> {
597 self.attribute_macros.get(&hash)
598 }
599
600 #[cfg(feature = "cli")]
602 pub(crate) fn iter_crates(&self) -> impl Iterator<Item = &str> {
603 self.crates.iter().map(|s| s.as_ref())
604 }
605
606 pub(crate) fn contains_crate(&self, name: &str) -> bool {
608 self.crates.contains(name)
609 }
610
611 pub(crate) fn has_default_modules(&self) -> bool {
616 self.has_default_modules
617 }
618
619 fn find_existing_module(&self, hash: Hash) -> Option<usize> {
621 let indexes = self.hash_to_meta.get(&hash)?;
622
623 for &index in indexes {
624 let Some(m) = self.meta.get(index) else {
625 continue;
626 };
627
628 if matches!(m.kind, meta::Kind::Module) {
629 return Some(index);
630 }
631 }
632
633 None
634 }
635
636 #[tracing::instrument(skip_all)]
638 fn install_meta(&mut self, meta: ContextMeta) -> Result<(), ContextError> {
639 if let Some(item) = &meta.item {
640 tracing::trace!(?item);
641
642 self.names.insert(item)?;
643
644 self.item_to_hash
645 .entry(item.try_clone()?)
646 .or_try_default()?
647 .try_insert(meta.hash)?;
648 }
649
650 #[cfg(feature = "doc")]
651 if let Some(h) = meta.kind.associated_container() {
652 let assoc = self.associated.entry(h).or_try_default()?;
653 assoc.try_push(meta.hash)?;
654 }
655
656 let hash = meta.hash;
657
658 let index = self.meta.len();
659
660 self.meta.try_push(meta)?;
661
662 self.hash_to_meta
663 .entry(hash)
664 .or_try_default()?
665 .try_push(index)?;
666
667 Ok(())
668 }
669
670 fn install_module(&mut self, m: &Module) -> Result<(), ContextError> {
672 self.names.insert(&m.item)?;
673
674 let mut current = Some((m.item.as_ref(), Some(&m.common)));
675
676 #[allow(unused)]
677 while let Some((item, common)) = current.take() {
678 let hash = Hash::type_hash(item);
679
680 if let Some(index) = self.find_existing_module(hash) {
681 #[cfg(feature = "doc")]
682 if let Some(common) = common {
683 let meta = &mut self.meta[index];
684 meta.deprecated = common.deprecated.try_clone()?;
685 meta.docs = common.docs.try_clone()?;
686 }
687 } else {
688 self.install_meta(ContextMeta {
689 hash,
690 item: Some(item.try_to_owned()?),
691 kind: meta::Kind::Module,
692 #[cfg(feature = "doc")]
693 deprecated: common
694 .map(|c| c.deprecated.as_ref().try_cloned())
695 .transpose()?
696 .flatten(),
697 #[cfg(feature = "doc")]
698 docs: common
699 .map(|c| c.docs.try_clone())
700 .transpose()?
701 .unwrap_or_default(),
702 })?;
703 }
704
705 current = item.parent().map(|item| (item, None));
706 }
707
708 Ok(())
709 }
710
711 fn install_type(&mut self, ty: &ModuleType) -> Result<(), ContextError> {
713 self.install_type_info(ContextType {
714 item: ty.item.try_to_owned()?,
715 hash: ty.hash,
716 type_info: ty.type_info.try_clone()?,
717 type_parameters: ty.type_parameters,
718 })?;
719
720 let parameters = Hash::EMPTY.with_type_parameters(ty.type_parameters);
721
722 let kind = if let Some(spec) = &ty.spec {
723 match spec {
724 TypeSpecification::Struct(fields) => {
725 let constructor = match &ty.constructor {
726 Some(c) => {
727 let signature = meta::Signature {
728 #[cfg(feature = "doc")]
729 is_async: false,
730 #[cfg(feature = "doc")]
731 arguments: Some(fields_to_arguments(fields)?),
732 #[cfg(feature = "doc")]
733 return_type: meta::DocType::new(ty.hash),
734 };
735
736 if c.args != fields.len() {
737 return Err(ContextError::ConstructorArgumentsMismatch {
738 type_info: ty.type_info.try_clone()?,
739 expected: fields.len(),
740 actual: c.args,
741 });
742 }
743
744 self.insert_native_fn(&ty.type_info, ty.hash, &c.handler, None)?;
745 Some(signature)
746 }
747 None => None,
748 };
749
750 meta::Kind::Struct {
751 fields: match fields {
752 Fields::Named(fields) => meta::Fields::Named(meta::FieldsNamed {
753 fields: fields
754 .iter()
755 .copied()
756 .enumerate()
757 .map(|(position, name)| {
758 Ok(meta::FieldMeta {
759 name: name.try_into()?,
760 position,
761 })
762 })
763 .try_collect::<alloc::Result<_>>()??,
764 }),
765 Fields::Unnamed(args) => meta::Fields::Unnamed(*args),
766 Fields::Empty => meta::Fields::Empty,
767 },
768 constructor,
769 parameters,
770 enum_hash: Hash::EMPTY,
771 }
772 }
773 TypeSpecification::Enum(en) => {
774 for variant in &en.variants {
775 let Some(fields) = &variant.fields else {
776 continue;
777 };
778
779 let kind = match fields {
780 Fields::Empty => RttiKind::Empty,
781 Fields::Unnamed(..) => RttiKind::Tuple,
782 Fields::Named(..) => RttiKind::Struct,
783 };
784
785 let item = ty.item.extended(variant.name)?;
786 let hash = Hash::type_hash(&item);
787
788 self.install_type_info(ContextType {
789 item: item.try_clone()?,
790 hash,
791 type_info: TypeInfo::rtti(Arc::try_new(Rtti {
792 kind,
793 hash: ty.hash,
794 variant_hash: hash,
795 item: item.try_clone()?,
796 fields: fields.to_fields()?,
797 })?),
798 type_parameters: Hash::EMPTY,
799 })?;
800
801 let constructor = if let Some(c) = &variant.constructor {
802 let signature = meta::Signature {
803 #[cfg(feature = "doc")]
804 is_async: false,
805 #[cfg(feature = "doc")]
806 arguments: Some(fields_to_arguments(fields)?),
807 #[cfg(feature = "doc")]
808 return_type: meta::DocType::new(ty.hash),
809 };
810
811 if c.args != fields.len() {
812 return Err(ContextError::VariantConstructorArgumentsMismatch {
813 type_info: ty.type_info.try_clone()?,
814 name: variant.name,
815 expected: fields.len(),
816 actual: c.args,
817 });
818 }
819
820 self.insert_native_fn(
821 &item,
822 hash,
823 &c.handler,
824 variant.deprecated.as_deref(),
825 )?;
826 Some(signature)
827 } else {
828 None
829 };
830
831 self.install_meta(ContextMeta {
832 hash,
833 item: Some(item),
834 kind: meta::Kind::Struct {
835 fields: match fields {
836 Fields::Named(names) => {
837 meta::Fields::Named(meta::FieldsNamed {
838 fields: names
839 .iter()
840 .copied()
841 .enumerate()
842 .map(|(position, name)| {
843 Ok(meta::FieldMeta {
844 name: name.try_into()?,
845 position,
846 })
847 })
848 .try_collect::<alloc::Result<_>>()??,
849 })
850 }
851 Fields::Unnamed(args) => meta::Fields::Unnamed(*args),
852 Fields::Empty => meta::Fields::Empty,
853 },
854 constructor,
855 parameters: Hash::EMPTY,
856 enum_hash: ty.hash,
857 },
858 #[cfg(feature = "doc")]
859 deprecated: variant.deprecated.try_clone()?,
860 #[cfg(feature = "doc")]
861 docs: variant.docs.try_clone()?,
862 })?;
863 }
864
865 meta::Kind::Enum { parameters }
866 }
867 }
868 } else {
869 meta::Kind::Type { parameters }
870 };
871
872 self.install_meta(ContextMeta {
873 hash: ty.hash,
874 item: Some(ty.item.try_to_owned()?),
875 kind,
876 #[cfg(feature = "doc")]
877 deprecated: ty.common.deprecated.try_clone()?,
878 #[cfg(feature = "doc")]
879 docs: ty.common.docs.try_clone()?,
880 })?;
881
882 Ok(())
883 }
884
885 fn install_trait(&mut self, t: &ModuleTrait) -> Result<(), ContextError> {
886 if self.traits.try_insert(t.hash, t.handler.clone())?.is_some() {
887 return Err(ContextError::ConflictingTrait {
888 item: t.item.try_clone()?,
889 hash: t.hash,
890 });
891 }
892
893 self.install_meta(ContextMeta {
894 hash: t.hash,
895 item: Some(t.item.try_clone()?),
896 kind: meta::Kind::Trait,
897 #[cfg(feature = "doc")]
898 deprecated: t.common.deprecated.try_clone()?,
899 #[cfg(feature = "doc")]
900 docs: t.common.docs.try_clone()?,
901 })?;
902
903 for f in &t.functions {
904 let signature = meta::Signature::from_context(&f.doc, &f.common)?;
905
906 let kind = meta::Kind::Function {
907 associated: Some(f.name.kind.try_clone()?),
908 trait_hash: None,
909 signature,
910 is_test: false,
911 is_bench: false,
912 parameters: Hash::EMPTY.with_function_parameters(f.name.function_parameters),
913 #[cfg(feature = "doc")]
914 container: Some(t.hash),
915 #[cfg(feature = "doc")]
916 parameter_types: f.name.parameter_types.try_clone()?,
917 };
918
919 let hash = f
920 .name
921 .kind
922 .hash(t.hash)
923 .with_function_parameters(f.name.function_parameters);
924
925 let item = if let meta::AssociatedKind::Instance(name) = &f.name.kind {
926 let item = t.item.extended(name.as_ref())?;
927 let hash = Hash::type_hash(&item);
928 Some((hash, item))
929 } else {
930 None
931 };
932
933 self.install_meta(ContextMeta {
934 hash,
935 item: item.map(|(_, item)| item),
936 kind,
937 #[cfg(feature = "doc")]
938 deprecated: f.common.deprecated.try_clone()?,
939 #[cfg(feature = "doc")]
940 docs: f.common.docs.try_clone()?,
941 })?;
942 }
943
944 Ok(())
945 }
946
947 fn install_trait_impl(&mut self, i: &ModuleTraitImpl) -> Result<(), ContextError> {
948 if !self.types.contains_key(&i.hash) {
949 return Err(ContextError::MissingType {
950 item: i.item.try_to_owned()?,
951 type_info: i.type_info.try_clone()?,
952 });
953 };
954
955 let Some(handler) = self.traits.get(&i.trait_hash).cloned() else {
956 return Err(ContextError::MissingTrait {
957 item: i.trait_item.try_clone()?,
958 hash: i.hash,
959 impl_item: i.item.try_to_owned()?,
960 impl_hash: i.hash,
961 });
962 };
963
964 if let Some(handler) = handler {
965 handler.call(&mut TraitContext {
966 cx: self,
967 item: &i.item,
968 hash: i.hash,
969 type_info: &i.type_info,
970 trait_item: &i.trait_item,
971 trait_hash: i.trait_hash,
972 })?;
973 }
974
975 #[cfg(feature = "doc")]
976 self.implemented_traits
977 .entry(i.hash)
978 .or_try_default()?
979 .try_push(i.trait_hash)?;
980
981 Ok(())
982 }
983
984 fn install_reexport(&mut self, r: &ModuleReexport) -> Result<(), ContextError> {
985 self.install_meta(ContextMeta {
986 hash: r.hash,
987 item: Some(r.item.try_clone()?),
988 kind: meta::Kind::Alias(meta::Alias {
989 to: r.to.try_clone()?,
990 }),
991 #[cfg(feature = "doc")]
992 deprecated: None,
993 #[cfg(feature = "doc")]
994 docs: Docs::EMPTY,
995 })?;
996
997 Ok(())
998 }
999
1000 fn install_construct(
1002 &mut self,
1003 hash: Hash,
1004 type_info: &AnyTypeInfo,
1005 construct: &ConstConstructImpl,
1006 ) -> Result<(), ContextError> {
1007 let old = self.construct.try_insert(hash, construct.clone())?;
1008
1009 if old.is_some() {
1010 return Err(ContextError::ConflictingConstConstruct {
1011 type_info: TypeInfo::from(*type_info),
1012 hash,
1013 });
1014 }
1015
1016 Ok(())
1017 }
1018
1019 fn install_type_info(&mut self, ty: ContextType) -> Result<(), ContextError> {
1020 let item_hash = Hash::type_hash(&ty.item).with_type_parameters(ty.type_parameters);
1021
1022 if ty.hash != item_hash {
1023 return Err(ContextError::TypeHashMismatch {
1024 type_info: ty.type_info,
1025 item: ty.item,
1026 hash: ty.hash,
1027 item_hash,
1028 });
1029 }
1030
1031 self.constants.try_insert(
1032 Hash::associated_function(ty.hash, &Protocol::INTO_TYPE_NAME),
1033 ConstValue::try_from(ty.item.try_to_string()?)?,
1034 )?;
1035
1036 if let Some(old) = self.types.try_insert(ty.hash, ty)? {
1037 return Err(ContextError::ConflictingType {
1038 item: old.item,
1039 type_info: old.type_info,
1040 hash: old.hash,
1041 });
1042 }
1043
1044 Ok(())
1045 }
1046
1047 fn install_item(&mut self, m: &ModuleItem) -> Result<(), ContextError> {
1049 self.names.insert(&m.item)?;
1050
1051 let kind = match &m.kind {
1052 rune::module::ModuleItemKind::Constant(value) => {
1053 self.constants.try_insert(m.hash, value.try_clone()?)?;
1054 meta::Kind::Const
1055 }
1056 rune::module::ModuleItemKind::Function(f) => {
1057 self.constants.try_insert(
1058 Hash::associated_function(m.hash, &Protocol::INTO_TYPE_NAME),
1059 ConstValue::try_from(m.item.try_to_string()?)?,
1060 )?;
1061
1062 let signature = meta::Signature::from_context(&f.doc, &m.common)?;
1063
1064 self.insert_native_fn(&m.item, m.hash, &f.handler, m.common.deprecated.as_deref())?;
1065
1066 meta::Kind::Function {
1067 associated: None,
1068 trait_hash: f.trait_hash,
1069 signature,
1070 is_test: false,
1071 is_bench: false,
1072 parameters: Hash::EMPTY,
1073 #[cfg(feature = "doc")]
1074 container: None,
1075 #[cfg(feature = "doc")]
1076 parameter_types: Vec::new(),
1077 }
1078 }
1079 rune::module::ModuleItemKind::Macro(macro_) => {
1080 self.macros.try_insert(m.hash, macro_.handler.clone())?;
1081 meta::Kind::Macro
1082 }
1083 rune::module::ModuleItemKind::AttributeMacro(macro_) => {
1084 self.attribute_macros
1085 .try_insert(m.hash, macro_.handler.clone())?;
1086 meta::Kind::AttributeMacro
1087 }
1088 };
1089
1090 self.install_meta(ContextMeta {
1091 hash: m.hash,
1092 item: Some(m.item.try_to_owned()?),
1093 kind,
1094 #[cfg(feature = "doc")]
1095 deprecated: m.common.deprecated.try_clone()?,
1096 #[cfg(feature = "doc")]
1097 docs: m.common.docs.try_clone()?,
1098 })?;
1099
1100 Ok(())
1101 }
1102
1103 fn install_associated(&mut self, assoc: &ModuleAssociated) -> Result<(), ContextError> {
1104 let Some(info) = self.types.get(&assoc.container).try_cloned()? else {
1105 return Err(ContextError::MissingContainer {
1106 container: assoc.container_type_info.try_clone()?,
1107 });
1108 };
1109
1110 let hash = assoc
1111 .name
1112 .kind
1113 .hash(assoc.container)
1114 .with_function_parameters(assoc.name.function_parameters);
1115
1116 let item = if let meta::AssociatedKind::Instance(name) = &assoc.name.kind {
1123 let item = info.item.extended(name.as_ref())?;
1124
1125 let hash = Hash::type_hash(&item)
1126 .with_type_parameters(info.type_parameters)
1127 .with_function_parameters(assoc.name.function_parameters);
1128
1129 Some((hash, item))
1130 } else {
1131 None
1132 };
1133
1134 let kind = match &assoc.kind {
1135 ModuleAssociatedKind::Constant(value) => {
1136 if let Some((hash, ..)) = item {
1137 self.constants.try_insert(hash, value.try_clone()?)?;
1138 }
1139
1140 self.constants.try_insert(hash, value.try_clone()?)?;
1141 meta::Kind::Const
1142 }
1143 ModuleAssociatedKind::Function(f) => {
1144 let signature = meta::Signature::from_context(&f.doc, &assoc.common)?;
1145
1146 if let Some((hash, item)) = &item {
1147 self.constants.try_insert(
1148 Hash::associated_function(*hash, &Protocol::INTO_TYPE_NAME),
1149 ConstValue::try_from(item.try_to_string()?)?,
1150 )?;
1151
1152 self.insert_native_fn(
1153 &assoc.container_type_info,
1154 *hash,
1155 &f.handler,
1156 assoc.common.deprecated.as_deref(),
1157 )?;
1158 }
1159
1160 self.insert_native_fn(
1161 &assoc.container_type_info,
1162 hash,
1163 &f.handler,
1164 assoc.common.deprecated.as_deref(),
1165 )?;
1166
1167 meta::Kind::Function {
1168 associated: Some(assoc.name.kind.try_clone()?),
1169 trait_hash: f.trait_hash,
1170 signature,
1171 is_test: false,
1172 is_bench: false,
1173 parameters: Hash::EMPTY
1174 .with_type_parameters(info.type_parameters)
1175 .with_function_parameters(assoc.name.function_parameters),
1176 #[cfg(feature = "doc")]
1177 container: Some(assoc.container),
1178 #[cfg(feature = "doc")]
1179 parameter_types: assoc.name.parameter_types.try_clone()?,
1180 }
1181 }
1182 };
1183
1184 self.install_meta(ContextMeta {
1185 hash,
1186 item: item.map(|(_, item)| item),
1187 kind,
1188 #[cfg(feature = "doc")]
1189 deprecated: assoc.common.deprecated.try_clone()?,
1190 #[cfg(feature = "doc")]
1191 docs: assoc.common.docs.try_clone()?,
1192 })?;
1193
1194 Ok(())
1195 }
1196
1197 fn insert_native_fn(
1198 &mut self,
1199 display: &dyn fmt::Display,
1200 hash: Hash,
1201 handler: &FunctionHandler,
1202 deprecation: Option<&str>,
1203 ) -> Result<(), ContextError> {
1204 if self.functions.contains_key(&hash) {
1205 return Err(ContextError::ConflictingFunction {
1206 part: display.try_to_string()?.try_into()?,
1207 hash,
1208 });
1209 }
1210
1211 self.functions.try_insert(hash, handler.clone())?;
1212
1213 if let Some(msg) = deprecation {
1214 self.deprecations.try_insert(hash, msg.try_to_owned()?)?;
1215 }
1216
1217 Ok(())
1218 }
1219
1220 pub(crate) fn get_const_value(&self, hash: Hash) -> Option<&ConstValue> {
1222 self.constants.get(&hash)
1223 }
1224}
1225
1226impl fmt::Debug for Context {
1227 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1228 write!(f, "Context")
1229 }
1230}
1231
1232impl ConstContext for Context {
1233 #[inline]
1234 fn get(&self, hash: Hash) -> Option<&ConstConstructImpl> {
1235 self.construct.get(&hash)
1236 }
1237}
1238
1239#[cfg(feature = "doc")]
1240fn fields_to_arguments(fields: &Fields) -> alloc::Result<Box<[meta::DocArgument]>> {
1241 match *fields {
1242 Fields::Named(fields) => {
1243 let mut out = Vec::try_with_capacity(fields.len())?;
1244
1245 for &name in fields {
1246 out.try_push(meta::DocArgument {
1247 name: meta::DocName::Name(Box::try_from(name)?),
1248 base: Hash::EMPTY,
1249 generics: Box::default(),
1250 })?;
1251 }
1252
1253 Box::try_from(out)
1254 }
1255 Fields::Unnamed(args) => {
1256 let mut out = Vec::try_with_capacity(args)?;
1257
1258 for n in 0..args {
1259 out.try_push(meta::DocArgument {
1260 name: meta::DocName::Index(n),
1261 base: Hash::EMPTY,
1262 generics: Box::default(),
1263 })?;
1264 }
1265
1266 Box::try_from(out)
1267 }
1268 Fields::Empty => Ok(Box::default()),
1269 }
1270}
1271
1272#[cfg(test)]
1273static_assertions::assert_impl_all!(Context: Send, Sync);