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