intuicio_core/
registry.rs

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