Skip to main content

hara_native/kernel/
namespace.rs

1use std::cell::RefCell;
2use std::collections::{HashMap, HashSet};
3use std::rc::Rc;
4
5use crate::kernel::{Var, VarMetadata, VarOrigin};
6use crate::lang::data::Symbol;
7use crate::lang::protocol::INamespaced;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum NamespaceLoadState {
11    Unloaded,
12    Loading,
13    Loaded,
14    Failed,
15}
16
17impl NamespaceLoadState {
18    pub fn as_str(self) -> &'static str {
19        match self {
20            Self::Unloaded => "unloaded",
21            Self::Loading => "loading",
22            Self::Loaded => "loaded",
23            Self::Failed => "failed",
24        }
25    }
26}
27
28#[derive(Debug, Clone)]
29pub struct Namespace<V> {
30    name: Symbol,
31    mappings: Rc<RefCell<HashMap<Symbol, Var<V>>>>,
32    aliases: Rc<RefCell<HashMap<Symbol, Namespace<V>>>>,
33    lazy_aliases: Rc<RefCell<HashMap<Symbol, Symbol>>>,
34    imports: Rc<RefCell<HashMap<Symbol, String>>>,
35    native_flavor: Rc<RefCell<Option<String>>>,
36    role: Rc<RefCell<String>>,
37    foundation_exposed: Rc<RefCell<Option<HashSet<String>>>>,
38    foundation_excluded: Rc<RefCell<HashSet<String>>>,
39}
40impl<V> Namespace<V> {
41    pub fn new(name: impl AsRef<str>) -> Self {
42        Self {
43            name: Symbol::parse(name.as_ref()),
44            mappings: Rc::new(RefCell::new(HashMap::new())),
45            aliases: Rc::new(RefCell::new(HashMap::new())),
46            lazy_aliases: Rc::new(RefCell::new(HashMap::new())),
47            imports: Rc::new(RefCell::new(HashMap::new())),
48            native_flavor: Rc::new(RefCell::new(None)),
49            role: Rc::new(RefCell::new("standard".into())),
50            foundation_exposed: Rc::new(RefCell::new(None)),
51            foundation_excluded: Rc::new(RefCell::new(HashSet::new())),
52        }
53    }
54    pub fn name(&self) -> &Symbol {
55        &self.name
56    }
57    pub fn same_identity(&self, other: &Self) -> bool {
58        Rc::ptr_eq(&self.mappings, &other.mappings)
59    }
60    pub fn identity_address(&self) -> usize {
61        Rc::as_ptr(&self.mappings) as usize
62    }
63    pub fn intern(&self, name: impl AsRef<str>, value: V) -> Var<V>
64    where
65        V: Clone + 'static,
66    {
67        let local = Symbol::create(None, name.as_ref());
68        if let Some(existing) = self.mappings.borrow().get(&local).cloned() {
69            existing.reset_value(value);
70            return existing;
71        }
72        let path = format!("{}/{}", self.name.as_str(), local.as_str());
73        let var = Var::new(path, value);
74        self.mappings.borrow_mut().insert(local, var.clone());
75        var
76    }
77    pub fn intern_with_metadata(
78        &self,
79        name: impl AsRef<str>,
80        value: V,
81        metadata: VarMetadata,
82    ) -> Var<V>
83    where
84        V: Clone + 'static,
85    {
86        let local = Symbol::create(None, name.as_ref());
87        if let Some(existing) = self.mappings.borrow().get(&local).cloned() {
88            existing.reset_value(value);
89            existing.set_metadata(metadata);
90            return existing;
91        }
92        let path = format!("{}/{}", self.name.as_str(), local.as_str());
93        let var = Var::with_metadata(path, value, metadata);
94        self.mappings.borrow_mut().insert(local, var.clone());
95        var
96    }
97    pub fn intern_with_origin(&self, name: impl AsRef<str>, value: V, origin: VarOrigin) -> Var<V>
98    where
99        V: Clone + 'static,
100    {
101        self.intern_with_metadata(
102            name,
103            value,
104            VarMetadata {
105                origin,
106                ..VarMetadata::default()
107            },
108        )
109    }
110    pub fn map_var(&self, symbol: Symbol, var: Var<V>) {
111        self.mappings.borrow_mut().insert(symbol, var);
112    }
113    pub fn unmap(&self, symbol: &Symbol) -> Option<Var<V>> {
114        self.mappings.borrow_mut().remove(symbol)
115    }
116    pub fn resolve(&self, symbol: &Symbol) -> Option<Var<V>>
117    where
118        V: Clone,
119    {
120        if let Some(namespace) = symbol.get_namespace() {
121            if namespace == "-" {
122                return self
123                    .mappings
124                    .borrow()
125                    .get(&Symbol::create(None, symbol.get_name()))
126                    .cloned();
127            }
128            let alias = Symbol::parse(namespace);
129            return self.aliases.borrow().get(&alias).and_then(|ns| {
130                ns.mappings
131                    .borrow()
132                    .get(&Symbol::create(None, symbol.get_name()))
133                    .cloned()
134            });
135        }
136        self.mappings.borrow().get(symbol).cloned()
137    }
138    pub fn unalias(&self, alias: impl AsRef<str>) -> Option<Namespace<V>> {
139        let alias = Symbol::parse(alias.as_ref());
140        self.lazy_aliases.borrow_mut().remove(&alias);
141        self.aliases.borrow_mut().remove(&alias)
142    }
143    pub fn alias(&self, alias: impl AsRef<str>, namespace: Namespace<V>) {
144        let alias = Symbol::parse(alias.as_ref());
145        self.lazy_aliases.borrow_mut().remove(&alias);
146        self.aliases.borrow_mut().insert(alias, namespace);
147    }
148    pub fn lazy_alias(&self, alias: impl AsRef<str>, target: impl AsRef<str>) {
149        let alias = Symbol::parse(alias.as_ref());
150        self.aliases.borrow_mut().remove(&alias);
151        self.lazy_aliases
152            .borrow_mut()
153            .insert(alias, Symbol::parse(target.as_ref()));
154    }
155    pub fn lazy_target(&self, alias: impl AsRef<str>) -> Option<Symbol> {
156        self.lazy_aliases
157            .borrow()
158            .get(&Symbol::parse(alias.as_ref()))
159            .cloned()
160    }
161    pub fn lazy_aliases(&self) -> Vec<(Symbol, Symbol)> {
162        self.lazy_aliases
163            .borrow()
164            .iter()
165            .map(|(alias, target)| (alias.clone(), target.clone()))
166            .collect()
167    }
168    pub fn import(&self, name: impl AsRef<str>, host_type: impl Into<String>) {
169        self.imports
170            .borrow_mut()
171            .insert(Symbol::parse(name.as_ref()), host_type.into());
172    }
173    pub fn imported(&self, name: &Symbol) -> Option<String> {
174        self.imports.borrow().get(name).cloned()
175    }
176    pub fn set_native_flavor(&self, flavor: Option<String>) {
177        *self.native_flavor.borrow_mut() = flavor;
178    }
179    pub fn native_flavor(&self) -> Option<String> {
180        self.native_flavor.borrow().clone()
181    }
182    pub fn set_role(&self, role: impl Into<String>) {
183        *self.role.borrow_mut() = role.into();
184    }
185    pub fn set_foundation_visibility(
186        &self,
187        exposed: Option<&HashSet<String>>,
188        excluded: &HashSet<String>,
189        blank: bool,
190    ) {
191        *self.foundation_exposed.borrow_mut() = if blank {
192            Some(HashSet::new())
193        } else {
194            exposed.cloned()
195        };
196        *self.foundation_excluded.borrow_mut() = excluded.clone();
197    }
198    pub(crate) fn foundation_visible(&self, name: &Symbol) -> bool {
199        if self.foundation_excluded.borrow().contains(name.as_str()) {
200            return false;
201        }
202        self.foundation_exposed
203            .borrow()
204            .as_ref()
205            .is_none_or(|exposed| exposed.contains(name.as_str()))
206    }
207    pub fn role(&self) -> String {
208        self.role.borrow().clone()
209    }
210    pub fn mappings(&self) -> Vec<(Symbol, Var<V>)>
211    where
212        V: Clone,
213    {
214        self.mappings
215            .borrow()
216            .iter()
217            .map(|(k, v)| (k.clone(), v.clone()))
218            .collect()
219    }
220    pub fn aliases(&self) -> Vec<(Symbol, Namespace<V>)>
221    where
222        V: Clone,
223    {
224        self.aliases
225            .borrow()
226            .iter()
227            .map(|(k, v)| (k.clone(), v.clone()))
228            .collect()
229    }
230    pub fn imports(&self) -> Vec<(Symbol, String)> {
231        self.imports
232            .borrow()
233            .iter()
234            .map(|(k, v)| (k.clone(), v.clone()))
235            .collect()
236    }
237}
238
239#[derive(Debug, Clone)]
240pub struct NamespaceRegistry<V> {
241    namespaces: Rc<RefCell<HashMap<Symbol, Namespace<V>>>>,
242    current: Rc<RefCell<Symbol>>,
243    loading_states: Rc<RefCell<HashMap<Symbol, NamespaceLoadState>>>,
244    load_failures: Rc<RefCell<HashMap<Symbol, String>>>,
245    global_aliases: Rc<RefCell<HashMap<Symbol, Symbol>>>,
246    global_imports: Rc<RefCell<HashMap<Symbol, Symbol>>>,
247    module_revisions: Rc<RefCell<HashMap<Symbol, u64>>>,
248    module_dependencies: Rc<RefCell<HashMap<Symbol, Vec<Symbol>>>>,
249}
250
251pub struct NamespaceRegistrySnapshot<V> {
252    namespaces: HashMap<Symbol, NamespaceSnapshot<V>>,
253    current: Symbol,
254    loading_states: HashMap<Symbol, NamespaceLoadState>,
255    load_failures: HashMap<Symbol, String>,
256    global_aliases: HashMap<Symbol, Symbol>,
257    global_imports: HashMap<Symbol, Symbol>,
258    module_revisions: HashMap<Symbol, u64>,
259    module_dependencies: HashMap<Symbol, Vec<Symbol>>,
260}
261
262pub struct NamespaceTransactionSnapshot<V> {
263    namespace_names: HashSet<Symbol>,
264    namespaces: HashMap<Symbol, NamespaceSnapshot<V>>,
265    current: Symbol,
266    loading_states: HashMap<Symbol, NamespaceLoadState>,
267    load_failures: HashMap<Symbol, String>,
268    global_aliases: HashMap<Symbol, Symbol>,
269    global_imports: HashMap<Symbol, Symbol>,
270    module_revisions: HashMap<Symbol, u64>,
271    module_dependencies: HashMap<Symbol, Vec<Symbol>>,
272}
273
274struct NamespaceSnapshot<V> {
275    namespace: Namespace<V>,
276    mappings: HashMap<Symbol, (Var<V>, V, VarMetadata)>,
277    aliases: HashMap<Symbol, Namespace<V>>,
278    lazy_aliases: HashMap<Symbol, Symbol>,
279    imports: HashMap<Symbol, String>,
280    native_flavor: Option<String>,
281    role: String,
282    foundation_exposed: Option<HashSet<String>>,
283    foundation_excluded: HashSet<String>,
284}
285impl<V: Clone> Default for NamespaceRegistry<V> {
286    fn default() -> Self {
287        Self::new("user")
288    }
289}
290impl<V: Clone> NamespaceRegistry<V> {
291    fn namespace_snapshot(namespace: &Namespace<V>) -> NamespaceSnapshot<V>
292    where
293        V: 'static,
294    {
295        let mappings = namespace
296            .mappings
297            .borrow()
298            .iter()
299            .map(|(name, var)| {
300                (
301                    name.clone(),
302                    (var.clone(), var.deref_value(), var.metadata()),
303                )
304            })
305            .collect();
306        NamespaceSnapshot {
307            namespace: namespace.clone(),
308            mappings,
309            aliases: namespace.aliases.borrow().clone(),
310            lazy_aliases: namespace.lazy_aliases.borrow().clone(),
311            imports: namespace.imports.borrow().clone(),
312            native_flavor: namespace.native_flavor.borrow().clone(),
313            role: namespace.role.borrow().clone(),
314            foundation_exposed: namespace.foundation_exposed.borrow().clone(),
315            foundation_excluded: namespace.foundation_excluded.borrow().clone(),
316        }
317    }
318
319    pub fn new(initial: impl AsRef<str>) -> Self {
320        let name = Symbol::parse(initial.as_ref());
321        let namespace = Namespace::new(name.as_str());
322        let mut namespaces = HashMap::new();
323        namespaces.insert(name.clone(), namespace);
324        let mut loading_states = HashMap::new();
325        loading_states.insert(name.clone(), NamespaceLoadState::Loaded);
326        Self {
327            namespaces: Rc::new(RefCell::new(namespaces)),
328            current: Rc::new(RefCell::new(name)),
329            loading_states: Rc::new(RefCell::new(loading_states)),
330            load_failures: Rc::new(RefCell::new(HashMap::new())),
331            global_aliases: Rc::new(RefCell::new(HashMap::new())),
332            global_imports: Rc::new(RefCell::new(HashMap::new())),
333            module_revisions: Rc::new(RefCell::new(HashMap::new())),
334            module_dependencies: Rc::new(RefCell::new(HashMap::new())),
335        }
336    }
337    pub fn current(&self) -> Namespace<V> {
338        self.namespaces
339            .borrow()
340            .get(&*self.current.borrow())
341            .cloned()
342            .expect("current namespace exists")
343    }
344    pub fn find(&self, name: impl AsRef<str>) -> Option<Namespace<V>> {
345        self.namespaces
346            .borrow()
347            .get(&Symbol::parse(name.as_ref()))
348            .cloned()
349    }
350    pub fn find_or_create(&self, name: impl AsRef<str>) -> Namespace<V> {
351        let symbol = Symbol::parse(name.as_ref());
352        if let Some(namespace) = self.namespaces.borrow().get(&symbol).cloned() {
353            return namespace;
354        }
355        let namespace = Namespace::new(symbol.as_str());
356        self.namespaces
357            .borrow_mut()
358            .insert(symbol.clone(), namespace.clone());
359        self.loading_states
360            .borrow_mut()
361            .entry(symbol)
362            .or_insert(NamespaceLoadState::Loaded);
363        namespace
364    }
365    pub fn set_current(&self, name: impl AsRef<str>) -> Namespace<V> {
366        let namespace = self.find_or_create(name);
367        *self.current.borrow_mut() = namespace.name().clone();
368        namespace
369    }
370    pub fn all(&self) -> Vec<Namespace<V>> {
371        self.namespaces.borrow().values().cloned().collect()
372    }
373    /// Returns every namespace known either as a materialized namespace or as
374    /// a discoverable module with load state.  Catalog-backed modules can
375    /// therefore be inspected before a Namespace value exists.
376    pub fn known_names(&self) -> Vec<Symbol> {
377        let mut names = self
378            .namespaces
379            .borrow()
380            .keys()
381            .chain(self.loading_states.borrow().keys())
382            .cloned()
383            .collect::<HashSet<_>>()
384            .into_iter()
385            .collect::<Vec<_>>();
386        names.sort_by(|left, right| left.as_str().cmp(right.as_str()));
387        names
388    }
389    pub fn load_state(&self, name: impl AsRef<str>) -> Option<NamespaceLoadState> {
390        self.loading_states
391            .borrow()
392            .get(&Symbol::parse(name.as_ref()))
393            .copied()
394    }
395    pub fn set_load_state(&self, name: impl AsRef<str>, state: NamespaceLoadState) {
396        self.loading_states
397            .borrow_mut()
398            .insert(Symbol::parse(name.as_ref()), state);
399    }
400    pub fn clear_load_state(&self, name: impl AsRef<str>) {
401        self.loading_states
402            .borrow_mut()
403            .remove(&Symbol::parse(name.as_ref()));
404    }
405    pub fn load_failure(&self, name: impl AsRef<str>) -> Option<String> {
406        self.load_failures
407            .borrow()
408            .get(&Symbol::parse(name.as_ref()))
409            .cloned()
410    }
411    pub fn set_load_failure(&self, name: impl AsRef<str>, detail: impl Into<String>) {
412        self.load_failures
413            .borrow_mut()
414            .insert(Symbol::parse(name.as_ref()), detail.into());
415    }
416    pub fn clear_load_failure(&self, name: impl AsRef<str>) {
417        self.load_failures
418            .borrow_mut()
419            .remove(&Symbol::parse(name.as_ref()));
420    }
421    pub fn register_global_alias(
422        &self,
423        alias: impl AsRef<str>,
424        namespace: impl AsRef<str>,
425    ) -> Result<(), String> {
426        let alias = Symbol::parse(alias.as_ref());
427        let namespace = Symbol::parse(namespace.as_ref());
428        if alias.get_namespace().is_some() || alias.as_str() == "-" {
429            return Err(format!("Invalid global namespace alias: {alias}"));
430        }
431        if let Some(previous) = self.global_aliases.borrow().get(&alias) {
432            if previous != &namespace {
433                return Err(format!(
434                    "Global namespace alias already refers to {previous}: {alias}"
435                ));
436            }
437            return Ok(());
438        }
439        self.global_aliases.borrow_mut().insert(alias, namespace);
440        Ok(())
441    }
442    pub fn global_aliases(&self) -> Vec<(Symbol, Symbol)> {
443        self.global_aliases
444            .borrow()
445            .iter()
446            .map(|(alias, namespace)| (alias.clone(), namespace.clone()))
447            .collect()
448    }
449    pub fn register_global_import(
450        &self,
451        shorthand: impl AsRef<str>,
452        canonical: impl AsRef<str>,
453    ) -> Result<(), String> {
454        let shorthand = Symbol::parse(shorthand.as_ref());
455        let canonical = Symbol::parse(canonical.as_ref());
456        if shorthand.get_namespace().is_none() {
457            return Err(format!("Invalid global import Var: {shorthand}"));
458        }
459        let local = Symbol::create(None, shorthand.get_name());
460        if let Some(previous) = self.global_imports.borrow().get(&local) {
461            if previous != &canonical {
462                return Err(format!(
463                    "Global import already refers to {previous}: {}",
464                    local
465                ));
466            }
467            return Ok(());
468        }
469        self.global_imports
470            .borrow_mut()
471            .insert(local, canonical);
472        Ok(())
473    }
474    pub fn global_imports(&self) -> Vec<(Symbol, Symbol)> {
475        self.global_imports
476            .borrow()
477            .iter()
478            .map(|(shorthand, canonical)| (shorthand.clone(), canonical.clone()))
479            .collect()
480    }
481    pub fn module_revision(&self, name: impl AsRef<str>) -> u64 {
482        self.module_revisions
483            .borrow()
484            .get(&Symbol::parse(name.as_ref()))
485            .copied()
486            .unwrap_or(0)
487    }
488    pub fn commit_module_revision(&self, name: impl AsRef<str>) -> u64 {
489        let name = Symbol::parse(name.as_ref());
490        let next = self.module_revision(name.as_str()) + 1;
491        self.module_revisions.borrow_mut().insert(name, next);
492        next
493    }
494    pub fn module_dependencies(&self, name: impl AsRef<str>) -> Vec<Symbol> {
495        self.module_dependencies
496            .borrow()
497            .get(&Symbol::parse(name.as_ref()))
498            .cloned()
499            .unwrap_or_default()
500    }
501    pub fn clear_module_dependencies(&self, name: impl AsRef<str>) {
502        self.module_dependencies
503            .borrow_mut()
504            .insert(Symbol::parse(name.as_ref()), Vec::new());
505    }
506    pub fn record_module_dependency(&self, module: impl AsRef<str>, dependency: impl AsRef<str>) {
507        let module = Symbol::parse(module.as_ref());
508        let dependency = Symbol::parse(dependency.as_ref());
509        let mut dependencies = self.module_dependencies.borrow_mut();
510        let values = dependencies.entry(module).or_default();
511        if !values.contains(&dependency) {
512            values.push(dependency);
513        }
514    }
515    pub fn snapshot(&self) -> NamespaceRegistrySnapshot<V>
516    where
517        V: 'static,
518    {
519        let namespaces = self
520            .namespaces
521            .borrow()
522            .iter()
523            .map(|(name, namespace)| (name.clone(), Self::namespace_snapshot(namespace)))
524            .collect();
525        NamespaceRegistrySnapshot {
526            namespaces,
527            current: self.current.borrow().clone(),
528            loading_states: self.loading_states.borrow().clone(),
529            load_failures: self.load_failures.borrow().clone(),
530            global_aliases: self.global_aliases.borrow().clone(),
531            global_imports: self.global_imports.borrow().clone(),
532            module_revisions: self.module_revisions.borrow().clone(),
533            module_dependencies: self.module_dependencies.borrow().clone(),
534        }
535    }
536
537    pub fn transaction_snapshot<'a>(
538        &self,
539        names: impl IntoIterator<Item = &'a str>,
540    ) -> NamespaceTransactionSnapshot<V>
541    where
542        V: 'static,
543    {
544        let selected = names.into_iter().map(Symbol::parse).collect::<HashSet<_>>();
545        let namespaces = self.namespaces.borrow();
546        NamespaceTransactionSnapshot {
547            namespace_names: namespaces.keys().cloned().collect(),
548            namespaces: namespaces
549                .iter()
550                .filter(|(name, _)| selected.contains(*name))
551                .map(|(name, namespace)| (name.clone(), Self::namespace_snapshot(namespace)))
552                .collect(),
553            current: self.current.borrow().clone(),
554            loading_states: self.loading_states.borrow().clone(),
555            load_failures: self.load_failures.borrow().clone(),
556            global_aliases: self.global_aliases.borrow().clone(),
557            global_imports: self.global_imports.borrow().clone(),
558            module_revisions: self.module_revisions.borrow().clone(),
559            module_dependencies: self.module_dependencies.borrow().clone(),
560        }
561    }
562    pub fn restore(&self, snapshot: NamespaceRegistrySnapshot<V>)
563    where
564        V: 'static,
565    {
566        let mut namespaces = HashMap::new();
567        for (name, saved) in snapshot.namespaces {
568            let namespace = saved.namespace;
569            let mut mappings = HashMap::new();
570            for (local, (var, value, metadata)) in saved.mappings {
571                var.reset_value(value);
572                var.set_metadata(metadata);
573                mappings.insert(local, var);
574            }
575            *namespace.mappings.borrow_mut() = mappings;
576            *namespace.aliases.borrow_mut() = saved.aliases;
577            *namespace.lazy_aliases.borrow_mut() = saved.lazy_aliases;
578            *namespace.imports.borrow_mut() = saved.imports;
579            *namespace.native_flavor.borrow_mut() = saved.native_flavor;
580            *namespace.role.borrow_mut() = saved.role;
581            *namespace.foundation_exposed.borrow_mut() = saved.foundation_exposed;
582            *namespace.foundation_excluded.borrow_mut() = saved.foundation_excluded;
583            namespaces.insert(name, namespace);
584        }
585        *self.namespaces.borrow_mut() = namespaces;
586        *self.current.borrow_mut() = snapshot.current;
587        *self.loading_states.borrow_mut() = snapshot.loading_states;
588        *self.load_failures.borrow_mut() = snapshot.load_failures;
589        *self.global_aliases.borrow_mut() = snapshot.global_aliases;
590        *self.global_imports.borrow_mut() = snapshot.global_imports;
591        *self.module_revisions.borrow_mut() = snapshot.module_revisions;
592        *self.module_dependencies.borrow_mut() = snapshot.module_dependencies;
593    }
594
595    pub fn restore_transaction(&self, snapshot: NamespaceTransactionSnapshot<V>)
596    where
597        V: 'static,
598    {
599        let mut namespaces = self.namespaces.borrow_mut();
600        namespaces.retain(|name, _| snapshot.namespace_names.contains(name));
601        for (name, saved) in snapshot.namespaces {
602            let namespace = saved.namespace;
603            let mut mappings = HashMap::new();
604            for (local, (var, value, metadata)) in saved.mappings {
605                var.reset_value(value);
606                var.set_metadata(metadata);
607                mappings.insert(local, var);
608            }
609            *namespace.mappings.borrow_mut() = mappings;
610            *namespace.aliases.borrow_mut() = saved.aliases;
611            *namespace.lazy_aliases.borrow_mut() = saved.lazy_aliases;
612            *namespace.imports.borrow_mut() = saved.imports;
613            *namespace.native_flavor.borrow_mut() = saved.native_flavor;
614            *namespace.role.borrow_mut() = saved.role;
615            *namespace.foundation_exposed.borrow_mut() = saved.foundation_exposed;
616            *namespace.foundation_excluded.borrow_mut() = saved.foundation_excluded;
617            namespaces.insert(name, namespace);
618        }
619        drop(namespaces);
620        *self.current.borrow_mut() = snapshot.current;
621        *self.loading_states.borrow_mut() = snapshot.loading_states;
622        *self.load_failures.borrow_mut() = snapshot.load_failures;
623        *self.global_aliases.borrow_mut() = snapshot.global_aliases;
624        *self.global_imports.borrow_mut() = snapshot.global_imports;
625        *self.module_revisions.borrow_mut() = snapshot.module_revisions;
626        *self.module_dependencies.borrow_mut() = snapshot.module_dependencies;
627    }
628    pub fn remove(&self, name: impl AsRef<str>) -> Option<Namespace<V>> {
629        let symbol = Symbol::parse(name.as_ref());
630        if symbol == *self.current.borrow() {
631            return None;
632        }
633        self.loading_states.borrow_mut().remove(&symbol);
634        self.load_failures.borrow_mut().remove(&symbol);
635        self.module_revisions.borrow_mut().remove(&symbol);
636        self.module_dependencies.borrow_mut().remove(&symbol);
637        self.global_aliases
638            .borrow_mut()
639            .retain(|_, namespace| namespace != &symbol);
640        self.namespaces.borrow_mut().remove(&symbol)
641    }
642    pub fn resolve(&self, symbol: &Symbol) -> Option<Var<V>>
643    where
644        V: Clone,
645    {
646        if let Some(namespace_name) = symbol.get_namespace() {
647            let local = Symbol::create(None, symbol.get_name());
648            if namespace_name == "-" {
649                return self.current().mappings.borrow().get(&local).cloned();
650            }
651            if let Some(namespace) = self.find(namespace_name) {
652                return namespace.mappings.borrow().get(&local).cloned();
653            }
654            if let Some(namespace_name) = self
655                .global_aliases
656                .borrow()
657                .get(&Symbol::parse(namespace_name))
658            {
659                if let Some(namespace) = self.find(namespace_name.as_str()) {
660                    return namespace.mappings.borrow().get(&local).cloned();
661                }
662            }
663            return self
664                .current()
665                .aliases
666                .borrow()
667                .get(&Symbol::parse(namespace_name))
668                .and_then(|namespace| namespace.mappings.borrow().get(&local).cloned());
669        }
670        let current = self.current();
671        current
672            .resolve(symbol)
673            .or_else(|| {
674                self.global_imports
675                    .borrow()
676                    .get(symbol)
677                    .cloned()
678                    .and_then(|canonical| self.resolve(&canonical))
679            })
680            .or_else(|| {
681                self.find("std.foundation")
682                    .filter(|_| current.foundation_visible(symbol))
683                    .and_then(|foundation| foundation.resolve(symbol))
684            })
685            .or_else(|| {
686                let name = symbol.as_str();
687                (name.starts_with("std.native.") || name.starts_with("std.protocol.")).then(
688                    || {
689                        self.namespaces.borrow().values().find_map(|namespace| {
690                            namespace
691                                .mappings
692                                .borrow()
693                                .values()
694                                .find(|var| var.symbol().as_str() == name)
695                                .cloned()
696                        })
697                    },
698                )?
699            })
700    }
701    pub fn set_var(&self, symbol: Symbol, var: Var<V>) -> Result<Var<V>, String>
702    where
703        V: Clone,
704    {
705        let namespace = match symbol.get_namespace() {
706            Some(name) => self
707                .find(name)
708                .ok_or_else(|| format!("Namespace not found: {name}"))?,
709            None => self.current(),
710        };
711        namespace.map_var(Symbol::create(None, symbol.get_name()), var.clone());
712        Ok(var)
713    }
714    pub fn visible_symbol_names(&self) -> Vec<String> {
715        let current = self.current();
716        let mut names = current
717            .mappings
718            .borrow()
719            .iter()
720            .map(|(name, var)| {
721                (
722                    name.as_str().to_owned(),
723                    var.hara_metadata()
724                        .is_some_and(|metadata| metadata.flag("public")),
725                )
726            })
727            .collect::<Vec<_>>();
728        if current.name().as_str() != "std.foundation" {
729            if let Some(foundation) = self.find("std.foundation") {
730                names.extend(
731                    foundation
732                        .mappings()
733                        .into_iter()
734                        .filter(|(name, _)| {
735                            current.foundation_visible(name) && current.resolve(name).is_none()
736                        })
737                        .map(|(name, var)| {
738                            (
739                                name.as_str().to_owned(),
740                                var.hara_metadata()
741                                    .is_some_and(|metadata| metadata.flag("public")),
742                            )
743                        }),
744                );
745            }
746        }
747        for (alias, namespace) in current.aliases.borrow().iter() {
748            names.extend(namespace.mappings.borrow().iter().map(|(name, var)| {
749                (
750                    format!("{}/{}", alias.as_str(), name.as_str()),
751                    var.hara_metadata()
752                        .is_some_and(|metadata| metadata.flag("public")),
753                )
754            }));
755        }
756        names.sort_by(|left, right| right.1.cmp(&left.1).then(left.0.cmp(&right.0)));
757        names.dedup_by(|left, right| left.0 == right.0);
758        names.into_iter().map(|(name, _)| name).collect()
759    }
760}
761
762#[cfg(test)]
763mod tests {
764    use super::{Namespace, NamespaceLoadState, VarMetadata};
765    use crate::lang::data::Symbol;
766    use crate::lang::protocol::IDeref;
767    #[test]
768    fn resolves_local_and_aliased_vars() {
769        let source = Namespace::new("source");
770        source.intern("answer", 42);
771        let original = source.resolve(&Symbol::parse("answer")).unwrap();
772        let reinterned = source.intern("answer", 43);
773        assert!(original.same_identity(&reinterned));
774        assert_eq!(original.deref(), 43);
775        let target = Namespace::new("target");
776        target.alias("s", source.clone());
777        assert_eq!(
778            source.resolve(&Symbol::parse("answer")).unwrap().deref(),
779            43
780        );
781        assert_eq!(
782            target.resolve(&Symbol::parse("s/answer")).unwrap().deref(),
783            43
784        );
785        assert_eq!(
786            source.resolve(&Symbol::parse("-/answer")).unwrap().deref(),
787            43
788        );
789    }
790    #[test]
791    fn registry_manages_lifecycle_resolution_and_visibility() {
792        let registry = super::NamespaceRegistry::new("user");
793        registry.current().intern("local", 1);
794        let library = registry.find_or_create("example.lib");
795        library.intern("answer", 42);
796        library.intern("IExample/method", 43);
797        registry.current().alias("lib", library);
798        assert_eq!(
799            registry
800                .resolve(&Symbol::parse("example.lib/answer"))
801                .unwrap()
802                .deref(),
803            42
804        );
805        assert_eq!(
806            registry
807                .resolve(&Symbol::parse("lib/answer"))
808                .unwrap()
809                .deref(),
810            42
811        );
812        assert_eq!(
813            registry.resolve(&Symbol::parse("-/local")).unwrap().deref(),
814            1
815        );
816        assert_eq!(
817            registry
818                .resolve(&Symbol::parse("example.lib/IExample/method"))
819                .unwrap()
820                .deref(),
821            43
822        );
823        assert_eq!(
824            registry.visible_symbol_names(),
825            vec!["lib/IExample/method", "lib/answer", "local"]
826        );
827        assert!(registry.remove("user").is_none());
828        assert!(registry.remove("example.lib").is_some());
829    }
830
831    #[test]
832    fn registry_tracks_session_local_namespace_loading_state() {
833        let first = super::NamespaceRegistry::<i32>::new("user");
834        let second = super::NamespaceRegistry::<i32>::new("user");
835
836        assert_eq!(first.load_state("user"), Some(NamespaceLoadState::Loaded));
837        assert_eq!(first.load_state("example.lazy"), None);
838
839        first.set_load_state("example.lazy", NamespaceLoadState::Unloaded);
840        first.set_load_state("example.lazy", NamespaceLoadState::Loading);
841        first.set_load_state("example.lazy", NamespaceLoadState::Failed);
842
843        assert_eq!(
844            first.load_state("example.lazy"),
845            Some(NamespaceLoadState::Failed)
846        );
847        assert_eq!(second.load_state("example.lazy"), None);
848    }
849
850    #[test]
851    fn visible_symbols_rank_public_vars_before_helpers() {
852        let registry = super::NamespaceRegistry::new("user");
853        registry.current().intern("zebra-helper", 1);
854        registry.current().intern("alpha-helper", 2);
855        registry.current().intern_with_metadata(
856            "recommended-api",
857            3,
858            VarMetadata {
859                hara: Some(crate::lang::data::Metadata::new(vec![(
860                    crate::lang::data::MetadataValue::Keyword(crate::lang::data::Keyword::from(
861                        "public",
862                    )),
863                    crate::lang::data::MetadataValue::Boolean(true),
864                )])),
865                ..VarMetadata::default()
866            },
867        );
868        registry.current().intern_with_metadata(
869            "advertised-api",
870            4,
871            VarMetadata {
872                hara: Some(crate::lang::data::Metadata::new(vec![(
873                    crate::lang::data::MetadataValue::Keyword(crate::lang::data::Keyword::from(
874                        "public",
875                    )),
876                    crate::lang::data::MetadataValue::Boolean(true),
877                )])),
878                ..VarMetadata::default()
879            },
880        );
881        assert_eq!(
882            registry.visible_symbol_names(),
883            vec![
884                "advertised-api",
885                "recommended-api",
886                "alpha-helper",
887                "zebra-helper"
888            ]
889        );
890    }
891}