intuicio_core/
registry.rs1use crate::{
2 function::{Function, FunctionHandle, FunctionQuery},
3 object::Object,
4 types::{Type, TypeHandle, TypeQuery, struct_type::NativeStructBuilder},
5};
6use intuicio_data::{
7 managed::{DynamicManaged, DynamicManagedLazy, DynamicManagedRef, DynamicManagedRefMut},
8 managed_box::DynamicManagedBox,
9};
10use std::{
11 collections::BTreeMap,
12 sync::{Arc, RwLock},
13};
14
15pub type RegistryHandle = Arc<Registry>;
16
17#[derive(Debug, Default)]
18pub struct Registry {
19 functions: Vec<FunctionHandle>,
20 types: Vec<TypeHandle>,
21 pub index_capacity: usize,
22 pub use_indexing_threshold: usize,
23 functions_index: RwLock<BTreeMap<u64, FunctionHandle>>,
24 types_index: RwLock<BTreeMap<u64, TypeHandle>>,
25}
26
27impl Clone for Registry {
28 fn clone(&self) -> Self {
29 Self {
30 functions: self.functions.clone(),
31 types: self.types.clone(),
32 index_capacity: self.index_capacity,
33 use_indexing_threshold: self.use_indexing_threshold,
34 functions_index: RwLock::new(
35 self.functions_index
36 .read()
37 .ok()
38 .map(|items| items.clone())
39 .unwrap_or_default(),
40 ),
41 types_index: RwLock::new(
42 self.types_index
43 .read()
44 .ok()
45 .map(|items| items.clone())
46 .unwrap_or_default(),
47 ),
48 }
49 }
50}
51
52impl Registry {
53 pub fn with_basic_types(self) -> Self {
54 self.with_type(NativeStructBuilder::new::<()>().build())
55 .with_type(NativeStructBuilder::new::<bool>().build())
56 .with_type(NativeStructBuilder::new::<i8>().build())
57 .with_type(NativeStructBuilder::new::<i16>().build())
58 .with_type(NativeStructBuilder::new::<i32>().build())
59 .with_type(NativeStructBuilder::new::<i64>().build())
60 .with_type(NativeStructBuilder::new::<i128>().build())
61 .with_type(NativeStructBuilder::new::<isize>().build())
62 .with_type(NativeStructBuilder::new::<u8>().build())
63 .with_type(NativeStructBuilder::new::<u16>().build())
64 .with_type(NativeStructBuilder::new::<u32>().build())
65 .with_type(NativeStructBuilder::new::<u64>().build())
66 .with_type(NativeStructBuilder::new::<u128>().build())
67 .with_type(NativeStructBuilder::new::<usize>().build())
68 .with_type(NativeStructBuilder::new::<f32>().build())
69 .with_type(NativeStructBuilder::new::<f64>().build())
70 .with_type(NativeStructBuilder::new::<char>().build())
71 .with_type(NativeStructBuilder::new_named::<String>("String").build())
72 }
73
74 pub fn with_erased_types(self) -> Self {
75 self.with_type(
76 NativeStructBuilder::new_named_uninitialized::<DynamicManaged>("DynamicManaged")
77 .build(),
78 )
79 .with_type(
80 NativeStructBuilder::new_named_uninitialized::<DynamicManagedLazy>(
81 "DynamicManagedLazy",
82 )
83 .build(),
84 )
85 .with_type(
86 NativeStructBuilder::new_named_uninitialized::<DynamicManagedRef>("DynamicManagedRef")
87 .build(),
88 )
89 .with_type(
90 NativeStructBuilder::new_named_uninitialized::<DynamicManagedRefMut>(
91 "DynamicManagedRefMut",
92 )
93 .build(),
94 )
95 .with_type(
96 NativeStructBuilder::new_named_uninitialized::<DynamicManagedBox>("DynamicManagedBox")
97 .build(),
98 )
99 .with_type(NativeStructBuilder::new_named_uninitialized::<Object>("Object").build())
100 }
101
102 pub fn with_index_capacity(mut self, capacity: usize) -> Self {
103 self.index_capacity = capacity;
104 self
105 }
106
107 pub fn with_max_index_capacity(mut self) -> Self {
108 self.index_capacity = usize::MAX;
109 self
110 }
111
112 pub fn with_use_indexing_threshold(mut self, threshold: usize) -> Self {
113 self.use_indexing_threshold = threshold;
114 self
115 }
116
117 pub fn with_install(mut self, f: impl FnOnce(&mut Self)) -> Self {
118 self.install(f);
119 self
120 }
121
122 pub fn with_function(mut self, function: Function) -> Self {
123 self.add_function(function);
124 self
125 }
126
127 pub fn with_type(mut self, type_: impl Into<Type>) -> Self {
128 self.add_type(type_);
129 self
130 }
131
132 pub fn install(&mut self, f: impl FnOnce(&mut Self)) {
133 f(self);
134 }
135
136 pub fn add_function_handle(&mut self, function_handle: FunctionHandle) {
137 if !self
138 .functions
139 .iter()
140 .any(|handle| handle.signature() == function_handle.signature())
141 {
142 self.functions.push(function_handle);
143 }
144 }
145
146 pub fn add_function(&mut self, function: Function) -> FunctionHandle {
147 if let Some(handle) = self
148 .functions
149 .iter()
150 .find(|handle| handle.signature() == function.signature())
151 {
152 handle.clone()
153 } else {
154 let handle = FunctionHandle::new(function);
155 self.functions.push(handle.clone());
156 handle
157 }
158 }
159
160 pub fn remove_function(&mut self, function_handle: FunctionHandle) {
161 if let Some(position) = self
162 .functions
163 .iter()
164 .position(|handle| handle.signature() == function_handle.signature())
165 {
166 self.functions.swap_remove(position);
167 }
168 }
169
170 pub fn remove_functions(&mut self, query: FunctionQuery) {
171 while let Some(position) = self
172 .functions
173 .iter()
174 .position(|handle| query.is_valid(handle.signature()))
175 {
176 self.functions.swap_remove(position);
177 }
178 }
179
180 pub fn functions(&self) -> impl Iterator<Item = &FunctionHandle> {
181 self.functions.iter()
182 }
183
184 pub fn find_functions<'a>(
185 &'a self,
186 query: FunctionQuery<'a>,
187 ) -> impl Iterator<Item = FunctionHandle> + 'a {
188 self.functions
189 .iter()
190 .filter(move |handle| query.is_valid(handle.signature()))
191 .cloned()
192 }
193
194 pub fn find_function<'a>(&'a self, query: FunctionQuery<'a>) -> Option<FunctionHandle> {
195 if self.index_capacity == 0 || self.functions.len() < self.use_indexing_threshold {
196 self.find_functions(query).next()
197 } else if let Ok(mut index) = self.functions_index.try_write() {
198 let hash = query.as_hash();
199 if let Some(found) = index.get(&hash) {
200 Some(found.clone())
201 } else if let Some(found) = self.find_functions(query).next() {
202 for _ in 0..(index.len().saturating_sub(self.index_capacity)) {
203 if let Some(hash) = index.keys().next().copied() {
204 index.remove(&hash);
205 }
206 }
207 index.insert(hash, found.clone());
208 Some(found)
209 } else {
210 None
211 }
212 } else {
213 self.find_functions(query).next()
214 }
215 }
216
217 pub fn add_type_handle(&mut self, type_handle: TypeHandle) {
218 if !self
219 .types
220 .iter()
221 .any(|handle| handle.as_ref() == type_handle.as_ref())
222 {
223 self.types.push(type_handle);
224 }
225 }
226
227 pub fn add_type(&mut self, type_: impl Into<Type>) -> TypeHandle {
228 let type_ = type_.into();
229 if let Some(handle) = self.types.iter().find(|handle| handle.as_ref() == &type_) {
230 handle.clone()
231 } else {
232 let handle = TypeHandle::new(type_);
233 self.types.push(handle.clone());
234 handle
235 }
236 }
237
238 pub fn remove_type(&mut self, type_handle: TypeHandle) {
239 if let Some(position) = self.types.iter().position(|handle| handle == &type_handle) {
240 self.types.swap_remove(position);
241 }
242 }
243
244 pub fn remove_types(&mut self, query: TypeQuery) {
245 while let Some(position) = self.types.iter().position(|handle| query.is_valid(handle)) {
246 self.types.swap_remove(position);
247 }
248 }
249
250 pub fn types(&self) -> impl Iterator<Item = &TypeHandle> {
251 self.types.iter()
252 }
253
254 pub fn find_types<'a>(&'a self, query: TypeQuery<'a>) -> impl Iterator<Item = TypeHandle> + 'a {
255 self.types
256 .iter()
257 .filter(move |handle| query.is_valid(handle))
258 .cloned()
259 }
260
261 pub fn find_type<'a>(&'a self, query: TypeQuery<'a>) -> Option<TypeHandle> {
262 if self.index_capacity == 0 || self.types.len() < self.use_indexing_threshold {
263 self.find_types(query).next()
264 } else if let Ok(mut index) = self.types_index.try_write() {
265 let hash = query.as_hash();
266 if let Some(found) = index.get(&hash) {
267 Some(found.clone())
268 } else if let Some(found) = self.find_types(query).next() {
269 for _ in 0..(index.len().saturating_sub(self.index_capacity)) {
270 if let Some(hash) = index.keys().next().copied() {
271 index.remove(&hash);
272 }
273 }
274 index.insert(hash, found.clone());
275 Some(found)
276 } else {
277 None
278 }
279 } else {
280 self.find_types(query).next()
281 }
282 }
283}
284
285#[cfg(test)]
286mod tests {
287 use super::*;
288
289 #[test]
290 fn test_async() {
291 fn is_async<T: Send + Sync>() {}
292
293 is_async::<Registry>();
294 }
295}