rune/compile/
context.rs

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
28/// A (type erased) macro handler.
29pub(crate) type MacroHandler =
30    dyn Fn(&mut MacroContext, &TokenStream) -> compile::Result<TokenStream> + Send + Sync;
31
32/// Invoked when types implement a trait.
33pub(crate) type TraitHandler =
34    dyn Fn(&mut TraitContext<'_>) -> Result<(), ContextError> + Send + Sync;
35
36/// A (type erased) attribute macro handler.
37pub(crate) type AttributeMacroHandler = dyn Fn(&mut MacroContext, &TokenStream, &TokenStream) -> compile::Result<TokenStream>
38    + Send
39    + Sync;
40
41/// Type used to install traits.
42pub struct TraitContext<'a> {
43    /// The context the trait function are being installed into.
44    cx: &'a mut Context,
45    /// The item being installed.
46    item: &'a Item,
47    /// The hash of the item being installed.
48    hash: Hash,
49    /// Type info of the type being installed.
50    type_info: &'a TypeInfo,
51    /// The trait being implemented for.
52    trait_item: &'a Item,
53    /// Hash of the trait being impleemnted.
54    trait_hash: Hash,
55}
56
57impl TraitContext<'_> {
58    /// Return the item the trait is being installed for.
59    pub fn item(&self) -> &Item {
60        self.item
61    }
62
63    /// Return the hash the trait is being installed for.
64    pub fn hash(&self) -> Hash {
65        self.hash
66    }
67
68    /// Find the given protocol function for the current type.
69    ///
70    /// This requires that the function is defined.
71    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    /// Try to find the given associated function.
102    ///
103    /// This does not require that the function is defined.
104    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    /// Find or define a protocol function.
119    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    /// Define a new associated function for the current type.
141    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    /// Define a new associated raw function for the current type.
155    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    /// Define a new associated function for the current type using a raw
169    /// handler.
170    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/// Context metadata.
216#[derive(Debug)]
217#[non_exhaustive]
218pub(crate) struct ContextMeta {
219    /// Type hash for the given meta item.
220    pub(crate) hash: Hash,
221    /// The item of the returned compile meta.
222    pub(crate) item: Option<ItemBuf>,
223    /// The kind of the compile meta.
224    pub(crate) kind: meta::Kind,
225    /// Deprecation notice.
226    #[cfg(feature = "doc")]
227    pub(crate) deprecated: Option<Box<str>>,
228    /// Documentation associated with a context meta.
229    #[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/// Information on a specific type.
241#[derive(Debug, TryClone)]
242#[non_exhaustive]
243pub(crate) struct ContextType {
244    /// Item of the type.
245    item: ItemBuf,
246    /// Type hash.
247    hash: Hash,
248    /// The type check used for the current type.
249    type_check: Option<TypeCheck>,
250    /// Complete detailed information on the hash.
251    type_info: TypeInfo,
252    /// Type parameters.
253    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/// [Context] used for the Rune language.
264///
265/// See [Build::with_context][crate::Build::with_context].
266///
267/// At runtime this needs to be converted into a [RuntimeContext] when used with
268/// a [Vm][crate::runtime::Vm]. This is done through [Context::runtime].
269///
270/// A [Context] contains:
271/// * Native functions.
272/// * Native instance functions.
273/// * And native type definitions.
274#[derive(Default)]
275pub struct Context {
276    /// Unique modules installed in the context.
277    unique: HashSet<&'static str>,
278    /// Whether or not to include the prelude when constructing a new unit.
279    has_default_modules: bool,
280    /// Registered metadata, in the order that it was registered.
281    meta: Vec<ContextMeta>,
282    /// Item metadata in the context.
283    hash_to_meta: hash::Map<Vec<usize>>,
284    /// Store item to hash mapping.
285    item_to_hash: HashMap<ItemBuf, BTreeSet<Hash>>,
286    /// Registered native function handlers.
287    functions: hash::Map<Arc<FunctionHandler>>,
288    /// Registered deprecation mesages for native functions.
289    deprecations: hash::Map<String>,
290    /// Information on associated types.
291    #[cfg(feature = "doc")]
292    associated: hash::Map<Vec<Hash>>,
293    /// Traits implemented by the given hash.
294    #[cfg(feature = "doc")]
295    implemented_traits: hash::Map<Vec<Hash>>,
296    /// Registered native macro handlers.
297    macros: hash::Map<Arc<MacroHandler>>,
298    /// Handlers for realising traits.
299    traits: hash::Map<Option<Arc<TraitHandler>>>,
300    /// Registered native attribute macro handlers.
301    attribute_macros: hash::Map<Arc<AttributeMacroHandler>>,
302    /// Registered types.
303    types: hash::Map<ContextType>,
304    /// All available names in the context.
305    names: Names,
306    /// Registered crates.
307    crates: HashSet<Box<str>>,
308    /// Constants visible in this context
309    constants: hash::Map<ConstValue>,
310    /// Constant constructor.
311    construct: hash::Map<Arc<dyn ConstConstruct>>,
312}
313
314impl Context {
315    /// Construct a new empty [Context].
316    #[inline]
317    pub fn new() -> Self {
318        Self::default()
319    }
320
321    /// Construct a [Context] containing the default set of modules with the
322    /// given configuration.
323    ///
324    /// `stdio` determines if we include I/O functions that interact with stdout
325    /// and stderr by default, like `dbg`, `print`, and `println`. If this is
326    /// `false` all the corresponding low-level I/O functions have to be
327    /// provided through a different module.
328    ///
329    /// These are:
330    ///
331    /// * `::std::io::dbg`
332    /// * `::std::io::print`
333    /// * `::std::io::println`
334    pub fn with_config(#[allow(unused)] stdio: bool) -> Result<Self, ContextError> {
335        let mut this = Self::new();
336
337        // NB: Order is important, since later modules might use types defined
338        // in previous modules.
339
340        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    /// Construct a new collection of functions with default packages installed.
384    pub fn with_default_modules() -> Result<Self, ContextError> {
385        Self::with_config(true)
386    }
387
388    /// Construct a runtime context used when executing the virtual machine.
389    ///
390    /// This is not a cheap operation, since it requires cloning things out of
391    /// the build-time [Context] which are necessary at runtime.
392    ///
393    /// ```no_run
394    /// use rune::{Context, Vm, Unit};
395    /// use std::sync::Arc;
396    ///
397    /// let context = Context::with_default_modules()?;
398    ///
399    /// let runtime = Arc::new(context.runtime()?);
400    /// let unit = Arc::new(Unit::default());
401    ///
402    /// let vm = Vm::new(runtime, unit);
403    /// # Ok::<_, rune::support::Error>(())
404    /// ```
405    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    /// Install the specified module.
414    ///
415    /// This installs everything that has been declared in the given [Module]
416    /// and ensures that they are compatible with the overall context, like
417    /// ensuring that a given type is only declared once.
418    #[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    /// Iterate over all available functions in the [Context].
478    #[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    /// Iterate over all available types in the [Context].
487    #[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    /// Iterate over known child components of the given name.
500    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    /// Access the context meta for the given item.
512    ///
513    /// If this returns `Some`, at least one context meta is guaranteed to be
514    /// available.
515    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    /// Lookup meta by its hash.
532    #[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    /// Lookup deprecation by function hash.
547    pub fn lookup_deprecation(&self, hash: Hash) -> Option<&str> {
548        self.deprecations.get(&hash).map(|s| s.as_str())
549    }
550
551    /// Check if unit contains the given name by prefix.
552    pub(crate) fn contains_prefix(&self, item: &Item) -> alloc::Result<bool> {
553        self.names.contains_prefix(item)
554    }
555
556    /// Lookup the given native function handler in the context.
557    pub(crate) fn lookup_function(&self, hash: Hash) -> Option<&Arc<FunctionHandler>> {
558        self.functions.get(&hash)
559    }
560
561    /// Get all associated types for the given hash.
562    #[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    /// Get all traits implemented for the given hash.
573    #[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    /// Lookup the given macro handler.
584    pub(crate) fn lookup_macro(&self, hash: Hash) -> Option<&Arc<MacroHandler>> {
585        self.macros.get(&hash)
586    }
587
588    /// Lookup the given attribute macro handler.
589    pub(crate) fn lookup_attribute_macro(&self, hash: Hash) -> Option<&Arc<AttributeMacroHandler>> {
590        self.attribute_macros.get(&hash)
591    }
592
593    /// Look up the type check implementation for the specified type hash.
594    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    /// Iterate over available crates.
600    #[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    /// Check if context contains the given crate.
606    pub(crate) fn contains_crate(&self, name: &str) -> bool {
607        self.crates.contains(name)
608    }
609
610    /// Test if the context has the default modules installed.
611    ///
612    /// This determines among other things whether a prelude should be used or
613    /// not.
614    pub(crate) fn has_default_modules(&self) -> bool {
615        self.has_default_modules
616    }
617
618    /// Try to find an existing module.
619    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    /// Install the given meta.
636    #[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    /// Install a module, ensuring that its meta is defined.
670    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    /// Install a single type.
711    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    /// Install a constant constructor.
980    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    /// Install a function and check for duplicates.
1027    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        // If the associated function is a named instance function - register it
1096        // under the name of the item it corresponds to unless it's a field
1097        // function.
1098        //
1099        // The other alternatives are protocol functions (which are not free)
1100        // and plain hashes.
1101        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    /// Get a constant value.
1200    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);