Skip to main content

oxdock_core/exec/
typing.rs

1//! Type-system integration for the executor.
2//!
3//! Name directories (which descriptor answers for `"TAG"`) live per
4//! execution state: one `HashMap` seeded with the startup descriptors,
5//! extended by the run's host descriptors. Words carry their own vtable,
6//! so lifecycle never consults any table; only name resolution (declaration
7//! checking, `TYPES()`, `TYPE_DESCRIBE`) reads the state map.
8
9pub use oxdock_parser::{
10    OxDockType, TypeDescriptor, Value, ValuePayload, clone_boxed, clone_copy, clone_shared,
11    drop_boxed, drop_noop, drop_shared, eq_boxed, eq_inline, eq_shared, fmt_boxed, fmt_inline,
12    fmt_shared, load_inline, startup_descriptors, store_inline, type_anchor, unshare_boxed,
13    unshare_inline, unshare_shared,
14};
15
16use std::collections::HashMap;
17
18use oxdock_process::ProcessManager;
19
20use super::state::ExecState;
21
22/// Fresh name directory seeded with the startup descriptors.
23pub(super) fn startup_type_map() -> HashMap<String, &'static TypeDescriptor> {
24    startup_descriptors()
25        .into_iter()
26        .map(|(name, descriptor)| (name.to_string(), descriptor))
27        .collect()
28}
29
30impl<P: ProcessManager> ExecState<P> {
31    /// Register a host-defined type descriptor (usually `T::descriptor()`
32    /// for a `#[oxdock_type]` payload). Makes the name visible to `TYPES()`
33    /// and valid for `LET $x: NAME` declarations carrying same-named
34    /// payloads. Re-registering a name returns silently when the descriptor
35    /// is identical; a different descriptor under a live name panics
36    /// instead of aliasing two layouts.
37    pub fn register_type(&mut self, descriptor: &'static TypeDescriptor) {
38        if let Some(live) = self.types.get(descriptor.name) {
39            if !std::ptr::eq(*live, descriptor) {
40                panic!(
41                    "type name `{}` already registered for a different descriptor",
42                    descriptor.name
43                );
44            }
45            return;
46        }
47        self.types.insert(descriptor.name.to_string(), descriptor);
48    }
49
50    /// True when `name` names a registered type (startup or host).
51    pub fn is_known_type(&self, name: &str) -> bool {
52        self.types.contains_key(name)
53    }
54
55    /// Resolve a descriptor by name, or `None` when unregistered.
56    pub fn describe_type(&self, name: &str) -> Option<&'static TypeDescriptor> {
57        self.types.get(name).copied()
58    }
59
60    /// Every registered type name: startup descriptors first, then hosts in
61    /// registration order.
62    pub fn type_names(&self) -> Vec<String> {
63        let mut names: Vec<String> = startup_descriptors()
64            .into_iter()
65            .map(|(name, _)| name.to_string())
66            .collect();
67        for name in self.types.keys() {
68            if !names.contains(&name.to_string()) {
69                names.push(name.clone());
70            }
71        }
72        names
73    }
74}