bean_script/modules/
registry.rs

1use std::{any::Any, cell::RefCell, collections::HashMap, path::PathBuf, rc::Rc};
2
3use crate::{
4	logger::Logger,
5	util::{make_ref, MutRc},
6};
7
8use super::{bean_std, BuiltinModule, CustomModule, Module, ModuleBuilder};
9
10pub(super) enum RegistryEntry {
11	Uninitialized(Box<dyn FnOnce() -> MutRc<dyn Module>>),
12	Available(MutRc<dyn Module>),
13}
14
15impl RegistryEntry {
16	pub fn get_or_init(self) -> MutRc<dyn Module> {
17		match self {
18			Self::Uninitialized(init) => init(),
19			Self::Available(v) => v,
20		}
21	}
22}
23
24#[derive(Clone, Copy)]
25pub struct RegistryFeatures {
26	pub custom_modules: bool,
27	pub import: bool,
28	pub lang_debug: bool,
29}
30
31impl Default for RegistryFeatures {
32	fn default() -> Self {
33		Self {
34			custom_modules: true,
35			import: true,
36			lang_debug: false,
37		}
38	}
39}
40
41pub struct ModuleRegistry {
42	pub(super) registered: HashMap<String, RegistryEntry>,
43	pub(super) local: HashMap<PathBuf, MutRc<CustomModule>>,
44	pub(super) loading: Vec<PathBuf>,
45	runtime: MutRc<BuiltinModule>,
46	pub features: RegistryFeatures,
47	pub logger: Logger,
48	pub metadata: HashMap<String, Box<dyn Any>>,
49}
50
51impl std::fmt::Debug for ModuleRegistry {
52	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53		f.debug_struct("ModuleRegistry").finish()
54	}
55}
56
57impl ModuleRegistry {
58	pub fn new(features: RegistryFeatures) -> Self {
59		let standard_lib = BuiltinModule::new(bean_std::construct, features);
60		let mut s = Self {
61			registered: HashMap::new(),
62			local: HashMap::new(),
63			loading: Vec::new(),
64			runtime: match RefCell::borrow(
65				&standard_lib.get_submodule("runtime").unwrap(),
66			)
67			.as_any()
68			.downcast_ref::<BuiltinModule>()
69			{
70				Some(r) => Rc::new(RefCell::new(r.clone())),
71				None => panic!("Runtime module is custom?"),
72			},
73			features: RegistryFeatures::default(),
74			logger: Logger::Stdout,
75			metadata: HashMap::new(),
76		};
77		s.registered.insert(
78			String::from("std"),
79			RegistryEntry::Available(make_ref(standard_lib)),
80		);
81		s
82	}
83
84	pub fn register_builtin(
85		&mut self,
86		name: String,
87		constructor: fn(&mut ModuleBuilder),
88	) {
89		if !self.registered.contains_key(&name) {
90			let features = self.features.clone();
91			self.registered.insert(
92				name,
93				RegistryEntry::Uninitialized(Box::new(move || {
94					make_ref(BuiltinModule::new(constructor, features))
95				})),
96			);
97		} else {
98			panic!("Trying to register a builtin module under a used name.")
99		}
100	}
101
102	pub fn register_initialized_builtin(&mut self, name: String, module: BuiltinModule) {
103		if !self.registered.contains_key(&name) {
104			self.registered
105				.insert(name, RegistryEntry::Available(make_ref(module)));
106		} else {
107			panic!("Trying to register a builtin module under a used name.")
108		}
109	}
110
111	pub fn set_logger(&mut self, logger: Logger) {
112		self.logger = logger;
113	}
114
115	pub fn runtime(&self) -> MutRc<BuiltinModule> {
116		Rc::clone(&self.runtime)
117	}
118}