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 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}