1use crate::func::SendSync;
3use crate::module::FuncMetadata;
4use crate::packages::string_basic::{FUNC_TO_DEBUG, FUNC_TO_STRING};
5use crate::types::dynamic::Variant;
6use crate::{Engine, FuncRegistration, Identifier, RhaiNativeFunc, StaticVec};
7use std::marker::PhantomData;
8
9#[cfg(feature = "no_std")]
10use std::prelude::v1::*;
11
12#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
13use crate::func::register::Mut;
14
15pub trait CustomType: Variant + Clone {
77 fn build(builder: TypeBuilder<Self>);
81}
82
83impl Engine {
84 #[inline]
88 pub fn build_type<T: CustomType>(&mut self) -> &mut Self {
89 T::build(TypeBuilder::new(self));
90 self
91 }
92}
93
94pub struct TypeBuilder<'a, T: Variant + Clone> {
105 engine: &'a mut Engine,
106 hashes: StaticVec<u64>,
108 _marker: PhantomData<T>,
109}
110
111impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
112 #[inline(always)]
114 fn new(engine: &'a mut Engine) -> Self {
115 Self {
116 engine,
117 hashes: StaticVec::new_const(),
118 _marker: PhantomData,
119 }
120 }
121}
122
123impl<T: Variant + Clone> TypeBuilder<'_, T> {
124 #[inline(always)]
126 pub fn with_name(&mut self, name: &str) -> &mut Self {
127 self.engine.register_type_with_name::<T>(name);
128 self
129 }
130
131 #[cfg(feature = "metadata")]
137 #[inline(always)]
138 pub fn with_comments(&mut self, comments: &[&str]) -> &mut Self {
139 let namespace = self.engine.global_namespace_mut();
140 if let Some(name) = namespace
141 .get_custom_type_raw::<T>()
142 .map(|ty| ty.display_name.clone())
143 {
144 namespace.set_custom_type_with_comments::<T>(name.as_str(), comments);
145 }
146
147 self
148 }
149
150 #[inline(always)]
152 pub fn on_print(
153 &mut self,
154 on_print: impl Fn(&mut T) -> String + SendSync + 'static,
155 ) -> &mut Self {
156 let FuncMetadata { hash, .. } =
157 FuncRegistration::new(FUNC_TO_STRING).register_into_engine(self.engine, on_print);
158 self.hashes.clear();
159 self.hashes.push(*hash);
160 self
161 }
162
163 #[inline(always)]
165 pub fn on_debug(
166 &mut self,
167 on_debug: impl Fn(&mut T) -> String + SendSync + 'static,
168 ) -> &mut Self {
169 let FuncMetadata { hash, .. } =
170 FuncRegistration::new(FUNC_TO_DEBUG).register_into_engine(self.engine, on_debug);
171 self.hashes.clear();
172 self.hashes.push(*hash);
173 self
174 }
175
176 #[inline(always)]
178 pub fn with_fn<A: 'static, const N: usize, const X: bool, R: Variant + Clone, const F: bool>(
179 &mut self,
180 name: impl AsRef<str> + Into<Identifier>,
181 method: impl RhaiNativeFunc<A, N, X, R, F> + SendSync + 'static,
182 ) -> &mut Self {
183 let FuncMetadata { hash, .. } =
184 FuncRegistration::new(name).register_into_engine(self.engine, method);
185 self.hashes.clear();
186 self.hashes.push(*hash);
187 self
188 }
189
190 #[cfg(feature = "metadata")]
193 #[inline(always)]
194 pub fn and_comments(&mut self, comments: &[&str]) -> &mut Self {
195 let module = self.engine.global_namespace_mut();
196
197 for &hash in &self.hashes {
198 if let Some(f) = module.get_fn_metadata_mut(hash) {
199 f.comments = comments.into_iter().map(|&s| s.into()).collect();
200 }
201 }
202
203 self
204 }
205}
206
207impl<T> TypeBuilder<'_, T>
208where
209 T: Variant + Clone + IntoIterator,
210 <T as IntoIterator>::Item: Variant + Clone,
211{
212 #[inline(always)]
215 pub fn is_iterable(&mut self) -> &mut Self {
216 self.engine.register_iterator::<T>();
217 self
218 }
219}
220
221#[cfg(not(feature = "no_object"))]
222impl<T: Variant + Clone> TypeBuilder<'_, T> {
223 #[inline(always)]
229 pub fn with_get<const X: bool, R: Variant + Clone, const F: bool>(
230 &mut self,
231 name: impl AsRef<str>,
232 get_fn: impl RhaiNativeFunc<(Mut<T>,), 1, X, R, F> + SendSync + 'static,
233 ) -> &mut Self {
234 let FuncMetadata { hash, .. } =
235 FuncRegistration::new_getter(name).register_into_engine(self.engine, get_fn);
236 self.hashes.clear();
237 self.hashes.push(*hash);
238
239 self
240 }
241
242 #[inline(always)]
246 pub fn with_set<const X: bool, R: Variant + Clone, const F: bool>(
247 &mut self,
248 name: impl AsRef<str>,
249 set_fn: impl RhaiNativeFunc<(Mut<T>, R), 2, X, (), F> + SendSync + 'static,
250 ) -> &mut Self {
251 let FuncMetadata { hash, .. } =
252 FuncRegistration::new_setter(name).register_into_engine(self.engine, set_fn);
253 self.hashes.clear();
254 self.hashes.push(*hash);
255
256 self
257 }
258
259 #[inline(always)]
265 pub fn with_get_set<
266 const X1: bool,
267 const X2: bool,
268 R: Variant + Clone,
269 const F1: bool,
270 const F2: bool,
271 >(
272 &mut self,
273 name: impl AsRef<str>,
274 get_fn: impl RhaiNativeFunc<(Mut<T>,), 1, X1, R, F1> + SendSync + 'static,
275 set_fn: impl RhaiNativeFunc<(Mut<T>, R), 2, X2, (), F2> + SendSync + 'static,
276 ) -> &mut Self {
277 let hash_1 = FuncRegistration::new_getter(&name)
278 .register_into_engine(self.engine, get_fn)
279 .hash;
280 let hash_2 = FuncRegistration::new_setter(&name)
281 .register_into_engine(self.engine, set_fn)
282 .hash;
283 self.hashes.clear();
284 self.hashes.push(hash_1);
285 self.hashes.push(hash_2);
286
287 self
288 }
289}
290
291#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
292impl<T: Variant + Clone> TypeBuilder<'_, T> {
293 #[inline(always)]
299 pub fn with_indexer_get<
300 IDX: Variant + Clone,
301 const X: bool,
302 R: Variant + Clone,
303 const F: bool,
304 >(
305 &mut self,
306 get_fn: impl RhaiNativeFunc<(Mut<T>, IDX), 2, X, R, F> + SendSync + 'static,
307 ) -> &mut Self {
308 let FuncMetadata { hash, .. } =
309 FuncRegistration::new_index_getter().register_into_engine(self.engine, get_fn);
310 self.hashes.clear();
311 self.hashes.push(*hash);
312
313 self
314 }
315
316 #[inline(always)]
320 pub fn with_indexer_set<
321 IDX: Variant + Clone,
322 const X: bool,
323 R: Variant + Clone,
324 const F: bool,
325 >(
326 &mut self,
327 set_fn: impl RhaiNativeFunc<(Mut<T>, IDX, R), 3, X, (), F> + SendSync + 'static,
328 ) -> &mut Self {
329 let FuncMetadata { hash, .. } =
330 FuncRegistration::new_index_setter().register_into_engine(self.engine, set_fn);
331 self.hashes.clear();
332 self.hashes.push(*hash);
333
334 self
335 }
336
337 #[inline(always)]
341 pub fn with_indexer_get_set<
342 IDX: Variant + Clone,
343 const X1: bool,
344 const X2: bool,
345 R: Variant + Clone,
346 const F1: bool,
347 const F2: bool,
348 >(
349 &mut self,
350 get_fn: impl RhaiNativeFunc<(Mut<T>, IDX), 2, X1, R, F1> + SendSync + 'static,
351 set_fn: impl RhaiNativeFunc<(Mut<T>, IDX, R), 3, X2, (), F2> + SendSync + 'static,
352 ) -> &mut Self {
353 let hash_1 = FuncRegistration::new_index_getter()
354 .register_into_engine(self.engine, get_fn)
355 .hash;
356 let hash_2 = FuncRegistration::new_index_setter()
357 .register_into_engine(self.engine, set_fn)
358 .hash;
359 self.hashes.clear();
360 self.hashes.push(hash_1);
361 self.hashes.push(hash_2);
362
363 self
364 }
365}