1use std::any::TypeId;
2use std::cell::RefCell;
3use std::iter::once;
4use std::ops::Deref;
5use std::ops::DerefMut;
6use std::path::Path;
7use std::rc::Rc;
8
9use rhai::CustomType;
10use rhai::{
11 packages::{CorePackage, Package},
12 Dynamic, Engine, EvalAltResult, ImmutableString, Scope, Variant, FLOAT, INT,
13};
14
15use crate::internal::ToBe;
16
17pub type ScriptResult<T> = Result<T, Box<EvalAltResult>>;
41
42pub struct FormattingEngine {
62 engine: Engine,
63 messages: Rc<RefCell<Vec<String>>>,
64}
65
66impl Deref for FormattingEngine {
67 type Target = Engine;
68
69 fn deref(&self) -> &Self::Target {
70 &self.engine
71 }
72}
73
74impl DerefMut for FormattingEngine {
75 fn deref_mut(&mut self) -> &mut Self::Target {
76 &mut self.engine
77 }
78}
79
80#[inline(always)]
81fn minus_deprecation() {
82 eprintln!(
83 "Using '-' for printing is deprecated and will be removed in future versions. Use '~' instead."
84 )
85}
86
87impl FormattingEngine {
88 fn register_value<T: Variant + Clone + std::fmt::Display>(&mut self) {
89 self.engine
90 .register_fn("++", move |a: T, b: serde_value::Value| {
91 vec![a.to_string(), serde_json::to_string(&b).unwrap()]
92 });
93 self.engine
94 .register_fn("++", move |a: serde_value::Value, b: T| {
95 vec![serde_json::to_string(&a).unwrap(), b.to_string()]
96 });
97 }
98
99 fn register_string_concat_void<T: Variant + Clone + std::fmt::Display>(&mut self) {
100 self.engine
101 .register_fn("++", move |a: T, _b: ()| vec![a.to_string()]);
102 self.engine
103 .register_fn("++", move |_a: (), b: T| vec![b.to_string()]);
104 }
105
106 fn register_string_concat<T: Variant + Clone + std::fmt::Display>(&mut self) {
107 self.engine.register_fn("++", move |a: T, b: &str| {
108 vec![a.to_string(), b.to_string()]
109 });
110 self.engine.register_fn("++", move |a: &str, b: T| {
111 vec![a.to_string(), b.to_string()]
112 });
113 self.engine
114 .register_fn("++", move |a: T, b: T| vec![a.to_string(), b.to_string()]);
115 }
116
117 fn register_string_concat_vec<T: Variant + Clone + std::fmt::Display>(&mut self) {
118 self.engine.register_fn("++", move |a: Vec<T>, b: &str| {
119 a.iter()
120 .map(ToString::to_string)
121 .chain(once(b.to_owned()))
122 .collect::<Vec<_>>()
123 });
124 self.engine.register_fn("++", move |a: &str, b: Vec<T>| {
125 b.iter()
126 .map(ToString::to_string)
127 .chain(once(a.to_owned()))
128 .collect::<Vec<_>>()
129 });
130 self.engine.register_fn("++", move |a: Vec<T>, b: Vec<T>| {
131 a.iter()
132 .map(ToString::to_string)
133 .chain(b.iter().map(ToString::to_string))
134 .collect::<Vec<_>>()
135 });
136 }
137
138 fn register_concat<T: Variant + Clone + std::fmt::Display>(&mut self) {
139 self.register_string_concat::<T>();
140 self.register_string_concat_vec::<T>();
141 self.register_string_concat_void::<T>();
142 }
143
144 fn register_msg<T: Variant + Clone + std::fmt::Display>(&mut self) {
145 self.register_msg_single::<T>();
146 self.register_msg_multi::<T, &str>();
147 self.register_msg_multi::<T, String>();
148 self.register_msg_multi::<T, bool>();
149 self.register_msg_multi::<T, i64>();
150 self.register_msg_multi::<T, u64>();
151 self.register_msg_multi::<T, i32>();
152 self.register_msg_multi::<T, u32>();
153 self.register_msg_multi::<T, i16>();
154 self.register_msg_multi::<T, u16>();
155 self.register_msg_multi::<T, i8>();
156 self.register_msg_multi::<T, u8>();
157 self.register_msg_multi::<T, usize>();
158 self.register_msg_multi::<T, isize>();
159 self.register_msg_multi::<T, i128>();
160 self.register_msg_multi::<T, u128>();
161 self.register_msg_multi::<T, f32>();
162 self.register_msg_multi::<T, f64>();
163 }
164
165 fn register_msg_multi<
166 A: Variant + Clone + std::fmt::Display,
167 B: Variant + Clone + std::fmt::Display,
168 >(
169 &mut self,
170 ) {
171 self.engine
172 .register_fn("++", move |a: A, b: B| vec![a.to_string(), b.to_string()]);
173
174 self.engine
175 .register_fn("++", move |b: B, a: A| vec![b.to_string(), a.to_string()]);
176
177 self.engine.register_fn("++", move |a: Option<A>, b: B| {
178 if let Some(a) = a {
179 vec![a.to_string(), b.to_string()]
180 } else {
181 vec![b.to_string()]
182 }
183 });
184
185 self.engine.register_fn("++", move |a: A, b: Option<B>| {
186 if let Some(b) = b {
187 vec![a.to_string(), b.to_string()]
188 } else {
189 vec![a.to_string()]
190 }
191 });
192
193 self.engine
194 .register_fn("++", move |a: Option<A>, b: Option<B>| match (a, b) {
195 (Some(a), Some(b)) => vec![a.to_string(), b.to_string()],
196 (Some(a), None) => vec![a.to_string()],
197 (None, Some(b)) => vec![b.to_string()],
198 (None, None) => vec![],
199 });
200 }
201
202 fn register_msg_single<T: Variant + Clone + std::fmt::Display>(&mut self) {
203 let messages = self.clone_messages();
204 self.engine.register_fn("-", move |msg: T| {
205 minus_deprecation();
206 messages.borrow_mut().push(msg.to_string());
207 });
208
209 self.engine.register_fn("++", move |a: Option<T>, _: ()| {
210 if let Some(a) = a {
211 vec![a.to_string()]
212 } else {
213 vec![]
214 }
215 });
216
217 self.engine.register_fn("++", move |_: (), a: Option<T>| {
218 if let Some(a) = a {
219 vec![a.to_string()]
220 } else {
221 vec![]
222 }
223 });
224
225 let messages = self.clone_messages();
226 self.engine.register_fn("-", move |msg: Option<T>| {
227 minus_deprecation();
228 if let Some(msg) = msg {
229 messages.borrow_mut().push(msg.to_string());
230 }
231 });
232 }
233
234 fn register_vec<T: Variant + Clone>(&mut self) {
235 self.engine
236 .register_type::<Vec<T>>()
237 .register_fn("len", |v: Vec<T>| v.len())
238 .register_iterator::<Vec<T>>()
239 .register_iterator::<&Vec<&T>>()
240 .register_iterator::<Vec<T>>()
241 .register_iterator::<&Vec<&T>>()
242 .register_indexer_get(|v: &mut Vec<T>, i: i64| {
243 v[usize::try_from(i).unwrap()].to_owned()
244 });
245 }
246
247 fn register_vec_printable<T: Variant + Clone + std::fmt::Display>(&mut self) {
248 self.register_vec::<T>();
249 self.engine.register_fn("++", move |a: Vec<T>| {
250 a.iter().map(ToString::to_string).collect::<Vec<_>>()
251 });
252
253 self.register_vec_printable_single::<T, &str>();
254 self.register_vec_printable_single::<T, String>();
255 self.register_vec_printable_single::<T, bool>();
256 self.register_vec_printable_single::<T, i64>();
257 self.register_vec_printable_single::<T, u64>();
258 self.register_vec_printable_single::<T, i32>();
259 self.register_vec_printable_single::<T, u32>();
260 self.register_vec_printable_single::<T, i16>();
261 self.register_vec_printable_single::<T, u16>();
262 self.register_vec_printable_single::<T, i8>();
263 self.register_vec_printable_single::<T, u8>();
264 self.register_vec_printable_single::<T, usize>();
265 self.register_vec_printable_single::<T, isize>();
266 self.register_vec_printable_single::<T, i128>();
267 self.register_vec_printable_single::<T, u128>();
268 self.register_vec_printable_single::<T, f32>();
269 self.register_vec_printable_single::<T, f64>();
270
271 self.register_vec_printable_multi::<T, &str>();
272 self.register_vec_printable_multi::<T, String>();
273 self.register_vec_printable_multi::<T, bool>();
274 self.register_vec_printable_multi::<T, i64>();
275 self.register_vec_printable_multi::<T, u64>();
276 self.register_vec_printable_multi::<T, i32>();
277 self.register_vec_printable_multi::<T, u32>();
278 self.register_vec_printable_multi::<T, i16>();
279 self.register_vec_printable_multi::<T, u16>();
280 self.register_vec_printable_multi::<T, i8>();
281 self.register_vec_printable_multi::<T, u8>();
282 self.register_vec_printable_multi::<T, usize>();
283 self.register_vec_printable_multi::<T, isize>();
284 self.register_vec_printable_multi::<T, i128>();
285 self.register_vec_printable_multi::<T, u128>();
286 self.register_vec_printable_multi::<T, f32>();
287 self.register_vec_printable_multi::<T, f64>();
288
289 self.register_vec_printable_void::<&str>();
290 self.register_vec_printable_void::<String>();
291 self.register_vec_printable_void::<bool>();
292 self.register_vec_printable_void::<i64>();
293 self.register_vec_printable_void::<u64>();
294 self.register_vec_printable_void::<i32>();
295 self.register_vec_printable_void::<u32>();
296 self.register_vec_printable_void::<i16>();
297 self.register_vec_printable_void::<u16>();
298 self.register_vec_printable_void::<i8>();
299 self.register_vec_printable_void::<u8>();
300 self.register_vec_printable_void::<usize>();
301 self.register_vec_printable_void::<isize>();
302 self.register_vec_printable_void::<i128>();
303 self.register_vec_printable_void::<u128>();
304 self.register_vec_printable_void::<f32>();
305 self.register_vec_printable_void::<f64>();
306 }
307
308 fn register_vec_printable_void<T: Variant + Clone + std::fmt::Display>(&mut self) {
309 self.engine.register_fn("++", move |a: Vec<T>, _b: ()| {
310 a.iter().map(ToString::to_string).collect::<Vec<_>>()
311 });
312 self.engine.register_fn("++", move |_a: (), b: Vec<T>| {
313 b.iter().map(ToString::to_string).collect::<Vec<_>>()
314 });
315 self.engine
316 .register_fn("++", move |a: Option<Vec<T>>, _b: ()| {
317 a.unwrap_or_default()
318 .iter()
319 .map(ToString::to_string)
320 .collect::<Vec<_>>()
321 });
322 self.engine
323 .register_fn("++", move |_a: (), b: Option<Vec<T>>| {
324 b.unwrap_or_default()
325 .iter()
326 .map(ToString::to_string)
327 .collect::<Vec<_>>()
328 });
329 }
330
331 fn register_vec_printable_multi<
332 A: Variant + Clone + std::fmt::Display,
333 B: Variant + Clone + std::fmt::Display,
334 >(
335 &mut self,
336 ) {
337 self.engine.register_fn("++", move |a: Vec<A>, b: Vec<B>| {
338 a.iter()
339 .map(ToString::to_string)
340 .chain(b.iter().map(ToString::to_string))
341 .collect::<Vec<_>>()
342 });
343
344 self.engine
345 .register_fn("++", move |a: Option<Vec<A>>, b: Vec<B>| {
346 let a: Vec<A> = a.unwrap_or_default();
347 a.iter()
348 .map(ToString::to_string)
349 .chain(b.iter().map(ToString::to_string))
350 .collect::<Vec<_>>()
351 });
352 self.engine
353 .register_fn("++", move |a: Vec<A>, b: Option<Vec<B>>| {
354 let b: Vec<B> = b.unwrap_or_default();
355 a.iter()
356 .map(ToString::to_string)
357 .chain(b.iter().map(ToString::to_string))
358 .collect::<Vec<_>>()
359 });
360 }
361
362 fn register_vec_printable_single<
363 A: Variant + Clone + std::fmt::Display,
364 B: Variant + Clone + std::fmt::Display,
365 >(
366 &mut self,
367 ) {
368 self.engine.register_fn("++", move |a: Vec<A>, b: B| {
369 a.iter()
370 .map(ToString::to_string)
371 .chain(once(b.to_string()))
372 .collect::<Vec<_>>()
373 });
374 self.engine.register_fn("++", move |a: A, b: Vec<B>| {
375 once(a.to_string())
376 .chain(b.iter().map(ToString::to_string))
377 .collect::<Vec<_>>()
378 });
379
380 self.engine
381 .register_fn("++", move |a: Option<Vec<A>>, b: B| {
382 let a: Vec<A> = a.unwrap_or_default();
383 a.iter()
384 .map(ToString::to_string)
385 .chain(once(b.to_string()))
386 .collect::<Vec<_>>()
387 });
388 self.engine
389 .register_fn("++", move |a: A, b: Option<Vec<B>>| {
390 let b: Vec<B> = b.unwrap_or_default();
391 once(a.to_string())
392 .chain(b.iter().map(ToString::to_string))
393 .collect::<Vec<_>>()
394 });
395
396 self.engine
397 .register_fn("++", move |a: Vec<A>, b: Option<B>| {
398 let mut res = a.iter().map(ToString::to_string).collect::<Vec<_>>();
399 if let Some(b) = b {
400 res.push(b.to_string());
401 }
402 res
403 });
404 self.engine
405 .register_fn("++", move |a: Option<A>, b: Vec<B>| {
406 a.iter()
407 .map(ToString::to_string)
408 .chain(b.iter().map(ToString::to_string))
409 .collect::<Vec<_>>()
410 });
411 }
412
413 fn register_type_dynamic<T: Variant + Clone + 'static, C: From<T> + PartialEq + 'static>(
414 &mut self,
415 is_call: fn(&Dynamic) -> bool,
416 as_call: fn(&Dynamic) -> Result<C, &'static str>,
417 ) {
418 self.engine
419 .register_fn("any", move |arr: rhai::Array, v: T| {
420 let value: C = v.into();
421 arr.iter()
422 .filter(|a| is_call(a))
423 .map(|a| {
424 let a: C = as_call(&a).unwrap().into();
425 a
426 })
427 .filter(|a| *a == value)
428 .into_iter()
429 .count()
430 > 0
431 });
432 self.engine
433 .register_fn("all", move |arr: rhai::Array, v: T| {
434 let value: C = v.into();
435 let expected = arr.len();
436 arr.iter()
437 .filter(|a| is_call(a))
438 .map(|a| {
439 let a: C = as_call(&a).unwrap().into();
440 a
441 })
442 .filter(|a| *a == value)
443 .into_iter()
444 .count()
445 == expected
446 });
447 self.engine
448 .register_fn("none", move |arr: rhai::Array, v: T| {
449 let value: C = v.into();
450 arr.iter()
451 .filter(|a| is_call(a))
452 .map(|a| {
453 let a: C = as_call(&a).unwrap().into();
454 a
455 })
456 .filter(|a| *a == value)
457 .into_iter()
458 .count()
459 == 0
460 });
461 }
462
463 fn register_comparison<
464 A: Variant + Clone + AsCast<C>,
465 B: Variant + Clone + AsCast<C>,
466 C: PartialEq + PartialOrd,
467 >(
468 &mut self,
469 ) {
470 self.engine
471 .register_fn(">", |left: A, right: B| left.as_cast() > right.as_cast());
472 self.engine
473 .register_fn(">=", |left: A, right: B| left.as_cast() >= right.as_cast());
474 self.engine
475 .register_fn("<", |left: A, right: B| left.as_cast() < right.as_cast());
476 self.engine
477 .register_fn("<=", |left: A, right: B| left.as_cast() <= right.as_cast());
478 self.engine
479 .register_fn("!=", |left: A, right: B| left.as_cast() != right.as_cast());
480 self.engine
481 .register_fn("==", |left: A, right: B| left.as_cast() == right.as_cast());
482
483 self.engine
484 .register_fn(">", |left: B, right: A| left.as_cast() > right.as_cast());
485 self.engine
486 .register_fn(">=", |left: B, right: A| left.as_cast() >= right.as_cast());
487 self.engine
488 .register_fn("<", |left: B, right: A| left.as_cast() < right.as_cast());
489 self.engine
490 .register_fn("<=", |left: B, right: A| left.as_cast() <= right.as_cast());
491 self.engine
492 .register_fn("!=", |left: B, right: A| left.as_cast() != right.as_cast());
493 self.engine
494 .register_fn("==", |left: B, right: A| left.as_cast() == right.as_cast());
495 }
496
497 fn register_options<T: Variant + Clone>(&mut self) {
498 self.engine
499 .register_fn("is_some", crate::internal::script_is_some::<T>)
500 .register_fn("unwrap", crate::internal::script_unwrap::<T>)
501 .register_fn("unwrap_or", crate::internal::script_unwrap_or::<T>);
502 }
503}
504
505impl FormattingEngine {
506 #[must_use]
516 pub fn new(debug: bool) -> Self {
517 build_engine(debug)
518 }
519
520 pub fn register_type<T: Variant + Clone>(&mut self) -> &mut Self {
533 self.engine.register_type::<T>();
534 self.register_vec::<T>();
535 self.register_options::<T>();
536
537 self
538 }
539
540 pub fn make_comparable<T: Variant + PartialEq + Clone>(&mut self) -> &mut Self {
553 self.register_type::<T>();
554 self.register_options::<T>();
555 self.register_vec::<T>();
556 self.register_fn("any", crate::internal::script_any_type::<T>)
557 .register_fn("all", crate::internal::script_all_type::<T>)
558 .register_fn("none", crate::internal::script_none_type::<T>);
559 self
560 }
561
562 pub fn build_type<T: Variant + CustomType + Clone>(&mut self) -> &mut Self {
593 self.engine.build_type::<T>();
594 self.register_type::<T>();
595 self
596 }
597
598 pub fn format_with_scope(&mut self, scope: &mut Scope, script: &str) -> ScriptResult<String> {
616 scope.push_constant("NL", "\n");
617
618 self.messages.borrow_mut().clear();
619 self.engine.run_with_scope(scope, script)?;
620
621 Ok(self.messages.borrow().join(""))
622 }
623
624 #[cfg(not(feature = "web"))]
642 pub fn format_from_file_with_scope<P: AsRef<Path>>(
643 &mut self,
644 scope: &mut Scope,
645 script: P,
646 ) -> ScriptResult<String> {
647 match std::fs::read_to_string(script.as_ref()) {
648 Ok(script) => self.format_with_scope(scope, &script),
649 Err(e) => Err(e.to_string().into()),
650 }
651 }
652
653 pub fn clone_messages(&self) -> Rc<RefCell<Vec<String>>> {
661 self.messages.clone()
662 }
663
664 pub fn format<T: Variant + Clone>(
682 &mut self,
683 name: &str,
684 data: T,
685 script: &str,
686 ) -> ScriptResult<String> {
687 self.register_type::<T>();
688
689 let mut scope = Scope::new();
690 scope.push_constant(name, data);
691
692 self.format_with_scope(&mut scope, script)
693 }
694
695 #[cfg(not(feature = "web"))]
713 pub fn format_from_file<T: Variant + Clone, P: AsRef<Path>>(
714 &mut self,
715 name: &str,
716 data: T,
717 script: P,
718 ) -> ScriptResult<String> {
719 match std::fs::read_to_string(script.as_ref()) {
720 Ok(script) => self.format(name, data, &script),
721 Err(e) => Err(e.to_string().into()),
722 }
723 }
724}
725
726fn option_to_string<T: std::fmt::Display>(value: Option<T>) -> Option<String> {
727 if let Some(v) = value {
728 Some(format!("{v}"))
729 } else {
730 None
731 }
732}
733
734fn dynamic_to_string(v: Dynamic) -> ScriptResult<Option<String>> {
735 let t = v.type_id();
736 if t == TypeId::of::<()>() {
737 Ok(None)
738 } else if v.is_array() {
739 let flattened = flatten_dynamic(v)?;
740 if flattened.len() > 0 {
741 Ok(Some(flattened.join("")))
742 } else {
743 Ok(None)
744 }
745 } else if t == TypeId::of::<Option<&str>>() {
746 Ok(option_to_string::<&str>(v.cast()))
747 } else if t == TypeId::of::<Option<bool>>() {
748 Ok(option_to_string::<bool>(v.cast()))
749 } else if t == TypeId::of::<Option<i8>>() {
750 Ok(option_to_string::<i8>(v.cast()))
751 } else if t == TypeId::of::<Option<i16>>() {
752 Ok(option_to_string::<i16>(v.cast()))
753 } else if t == TypeId::of::<Option<i32>>() {
754 Ok(option_to_string::<i32>(v.cast()))
755 } else if t == TypeId::of::<Option<i64>>() {
756 Ok(option_to_string::<i64>(v.cast()))
757 } else if t == TypeId::of::<Option<i128>>() {
758 Ok(option_to_string::<i128>(v.cast()))
759 } else if t == TypeId::of::<Option<u8>>() {
760 Ok(option_to_string::<u8>(v.cast()))
761 } else if t == TypeId::of::<Option<u16>>() {
762 Ok(option_to_string::<u16>(v.cast()))
763 } else if t == TypeId::of::<Option<u32>>() {
764 Ok(option_to_string::<u32>(v.cast()))
765 } else if t == TypeId::of::<Option<u64>>() {
766 Ok(option_to_string::<u64>(v.cast()))
767 } else if t == TypeId::of::<Option<f32>>() {
768 Ok(option_to_string::<f32>(v.cast()))
769 } else if t == TypeId::of::<Option<f64>>() {
770 Ok(option_to_string::<f64>(v.cast()))
771 } else if t == TypeId::of::<Option<u128>>() {
772 Ok(option_to_string::<u128>(v.cast()))
773 } else if t == TypeId::of::<Option<char>>() {
774 Ok(option_to_string::<char>(v.cast()))
775 } else if t == TypeId::of::<Option<String>>() {
776 Ok(if let Some(v) = v.cast::<Option<String>>() {
777 Some(v)
778 } else {
779 None
780 })
781 } else if t == TypeId::of::<Option<Dynamic>>() {
782 Ok(if let Some(v) = v.cast::<Option<Dynamic>>() {
783 dynamic_to_string(v)?
784 } else {
785 None
786 })
787 } else if t == TypeId::of::<bool>() {
788 Ok(Some(v.as_bool()?.to_string()))
789 } else if t == TypeId::of::<ImmutableString>() {
790 Ok(Some(v.into_immutable_string()?.to_string()))
791 } else if t == TypeId::of::<char>() {
792 Ok(Some(v.as_char()?.to_string()))
793 } else if t == TypeId::of::<INT>() {
794 Ok(Some(v.as_int()?.to_string()))
795 } else if t == TypeId::of::<FLOAT>() {
796 Ok(Some(v.as_float()?.to_string()))
797 } else {
798 eprintln!("{}", v.type_name());
799 Err("unsupported type".into())
800 }
801}
802
803fn flatten_dynamic(vs: Dynamic) -> Result<Vec<String>, Box<EvalAltResult>> {
804 let mut res = Vec::new();
805 if vs.is_array() {
806 for v in vs.into_array()? {
807 if v.is_array() {
808 let mut values = flatten_dynamic(v)?;
809 res.append(&mut values);
810 } else {
811 if let Some(s) = dynamic_to_string(v)? {
812 res.push(s);
813 }
814 }
815 }
816 } else if vs.type_id() == TypeId::of::<Option<Vec<String>>>() {
817 if let Some(mut vs) = vs.cast::<Option<Vec<String>>>() {
818 res.append(&mut vs);
819 }
820 } else if vs.type_id() == TypeId::of::<Vec<String>>() {
821 let mut vs = vs.cast::<Vec<String>>();
822 res.append(&mut vs);
823 } else if let Some(s) = dynamic_to_string(vs)? {
824 res.push(s);
825 }
826 Ok(res)
827}
828
829#[allow(clippy::too_many_lines)]
830fn build_engine(debug: bool) -> FormattingEngine {
831 let mut engine = FormattingEngine {
832 engine: rhai::Engine::new(),
833 messages: Rc::new(RefCell::new(Vec::new())),
834 };
835 engine.set_max_expr_depths(128, 64);
836
837 let package = CorePackage::new();
838
839 engine.register_global_module(package.as_shared_module());
840
841 {
843 let messages = engine.clone_messages();
844 engine
845 .register_custom_syntax(
846 ["~", "$expr$"],
847 true,
848 move |context: &mut rhai::EvalContext,
849 inputs: &[rhai::Expression]|
850 -> ScriptResult<Dynamic> {
851 for e in inputs {
852 let result = context.eval_expression_tree(&e)?;
853 let mut m = flatten_dynamic(result)?;
854 messages.borrow_mut().append(&mut m);
855 }
856 Ok(Dynamic::UNIT)
857 },
858 )
859 .unwrap();
860 }
861
862 let indent = Rc::new(RefCell::new(" ".to_owned()));
863
864 {
865 let indent = indent.clone();
866
867 #[allow(deprecated)]
869 engine.on_var(move |name, _, _| match name {
870 "IND" => Ok(Some(indent.borrow().clone().into())),
871 _ => Ok(None),
872 });
873 }
874
875 {
876 let indent = indent.clone();
877 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
878 engine.register_fn("IND", move |count: i64| {
879 indent.borrow().repeat(count as usize)
880 });
881 }
882
883 {
884 let indent = indent.clone();
885 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
886 engine.register_fn("SET_INDENT", move |value: &str| {
887 value.clone_into(&mut indent.borrow_mut());
888 });
889 }
890
891 {
892 let indent = indent.clone();
893 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
894 engine.register_fn("SET_INDENT", move |value: &str, count: i64| {
895 *indent.borrow_mut() = value.repeat(count as usize)
896 });
897 }
898
899 {
900 let indent = indent.clone();
901 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
902 engine.register_fn("SET_INDENT", move |count: i64| {
903 *indent.borrow_mut() = " ".repeat(count as usize)
904 });
905 }
906
907 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
908 engine.register_fn("NL", |count: i64| "\n".repeat(count as usize));
909
910 engine.register_iterator::<Vec<serde_value::Value>>();
911
912 engine.register_options::<&str>();
913 engine.register_options::<String>();
914 engine.register_options::<bool>();
915 engine.register_options::<i64>();
916 engine.register_options::<u64>();
917 engine.register_options::<i32>();
918 engine.register_options::<u32>();
919 engine.register_options::<i16>();
920 engine.register_options::<u16>();
921 engine.register_options::<i8>();
922 engine.register_options::<u8>();
923 engine.register_options::<usize>();
924 engine.register_options::<isize>();
925 engine.register_options::<i128>();
926 engine.register_options::<u128>();
927 engine.register_options::<f32>();
928 engine.register_options::<f64>();
929
930 engine.register_type_dynamic::<i8, i64>(Dynamic::is_int, Dynamic::as_int);
931 engine.register_type_dynamic::<i16, i64>(Dynamic::is_int, Dynamic::as_int);
932 engine.register_type_dynamic::<i32, i64>(Dynamic::is_int, Dynamic::as_int);
933 engine.register_type_dynamic::<i64, i64>(Dynamic::is_int, Dynamic::as_int);
934
935 engine.register_type_dynamic::<u8, i64>(Dynamic::is_int, Dynamic::as_int);
936 engine.register_type_dynamic::<u16, i64>(Dynamic::is_int, Dynamic::as_int);
937 engine.register_type_dynamic::<u32, i64>(Dynamic::is_int, Dynamic::as_int);
938
939 engine.register_type_dynamic::<f32, f64>(Dynamic::is_float, Dynamic::as_float);
940 engine.register_type_dynamic::<f64, f64>(Dynamic::is_float, Dynamic::as_float);
941
942 engine.register_type_dynamic::<bool, bool>(Dynamic::is_bool, Dynamic::as_bool);
943
944 fn dynamic_as_string(dynamic: &Dynamic) -> Result<String, &'static str> {
945 dynamic.to_owned().into_string()
946 }
947
948 engine.register_type_dynamic::<String, String>(Dynamic::is_string, dynamic_as_string);
949 engine.register_type_dynamic::<&str, String>(Dynamic::is_string, dynamic_as_string);
950
951 engine
952 .register_fn("join", crate::internal::script_join)
953 .register_fn("split", crate::internal::script_split)
954 .register_fn("splitn", crate::internal::script_splitn)
955 .register_fn("rsplitn", crate::internal::script_rsplitn)
956 .register_fn("is_empty", crate::internal::script_string_is_empty)
957 .register_fn("is_empty", crate::internal::script_array_is_empty)
958 .register_fn("starts_with", crate::internal::script_starts_with)
959 .register_fn("ends_with", crate::internal::script_ends_with)
960 .register_fn("trim", crate::internal::script_trim)
961 .register_fn("is_string", crate::internal::script_is_no_string)
962 .register_fn("is_string", crate::internal::script_is_string);
963
964 engine.build_type::<ToBe>();
966 engine
967 .register_custom_operator("zip", 65)
968 .unwrap()
969 .register_custom_operator("to_be", 60)
970 .unwrap()
971 .register_custom_operator("and", 60)
972 .unwrap()
973 .register_fn("and", |a: bool, b: bool| a && b)
974 .register_custom_operator("or", 30)
975 .unwrap()
976 .register_fn("or", |a: bool, b: bool| a || b)
977 .register_custom_operator("xor", 30)
978 .unwrap()
979 .register_fn("xor", |a: bool, b: bool| a ^ b)
980 .register_custom_operator("contains", 25)
981 .unwrap()
982 .register_custom_operator("equals", 25)
983 .unwrap()
984 .register_custom_operator("require", 25)
985 .unwrap()
986 .register_custom_operator("any", 25)
987 .unwrap()
988 .register_custom_operator("all", 25)
989 .unwrap()
990 .register_custom_operator("none", 25)
991 .unwrap()
992 .register_fn("contains", crate::internal::script_map_contains)
993 .register_fn("contains", crate::internal::script_string_contains)
994 .register_fn("equals", crate::internal::script_map_equals)
995 .register_fn("equals", crate::internal::script_value_equals)
996 .register_fn("equals", crate::internal::script_array_equals)
997 .register_fn("contains", crate::internal::script_array_contains)
998 .register_fn("require", crate::internal::script_require)
999 .register_fn("to_be", crate::internal::script_to_be)
1000 .register_fn("any", crate::internal::script_any)
1001 .register_fn("any", crate::internal::script_any_void)
1002 .register_fn("all", crate::internal::script_all)
1003 .register_fn("all", crate::internal::script_all_void)
1004 .register_fn("none", crate::internal::script_none)
1005 .register_fn("none", crate::internal::script_none_void);
1006
1007 engine.register_msg_single::<&str>();
1008 engine.register_msg_single::<String>();
1009 engine.register_msg_single::<bool>();
1010 engine.register_msg_single::<i64>();
1011 engine.register_msg_single::<u64>();
1012 engine.register_msg_single::<i32>();
1013 engine.register_msg_single::<u32>();
1014 engine.register_msg_single::<i16>();
1015 engine.register_msg_single::<u16>();
1016 engine.register_msg_single::<i8>();
1017 engine.register_msg_single::<u8>();
1018 engine.register_msg_single::<usize>();
1019 engine.register_msg_single::<isize>();
1020 engine.register_msg_single::<i128>();
1021 engine.register_msg_single::<u128>();
1022 engine.register_msg_single::<f32>();
1023 engine.register_msg_single::<f64>();
1024
1025 engine.register_msg::<&str>();
1026 engine.register_msg::<String>();
1027 engine.register_msg::<bool>();
1028 engine.register_msg::<i64>();
1029 engine.register_msg::<u64>();
1030 engine.register_msg::<i32>();
1031 engine.register_msg::<u32>();
1032 engine.register_msg::<i16>();
1033 engine.register_msg::<u16>();
1034 engine.register_msg::<i8>();
1035 engine.register_msg::<u8>();
1036 engine.register_msg::<usize>();
1037 engine.register_msg::<isize>();
1038 engine.register_msg::<i128>();
1039 engine.register_msg::<u128>();
1040 engine.register_msg::<f32>();
1041 engine.register_msg::<f64>();
1042
1043 engine.register_comparison::<u8, u8, u8>();
1044 engine.register_comparison::<u8, u16, u16>();
1045 engine.register_comparison::<u8, u32, u32>();
1046 engine.register_comparison::<u8, u64, u64>();
1047 engine.register_comparison::<u8, usize, u128>();
1048 engine.register_comparison::<u8, u128, u128>();
1049
1050 engine.register_comparison::<u16, u16, u16>();
1051 engine.register_comparison::<u16, u32, u32>();
1052 engine.register_comparison::<u16, u64, u64>();
1053 engine.register_comparison::<u16, usize, u128>();
1054 engine.register_comparison::<u16, u128, u128>();
1055
1056 engine.register_comparison::<u32, u32, u32>();
1057 engine.register_comparison::<u32, u64, u64>();
1058 engine.register_comparison::<u32, usize, u128>();
1059 engine.register_comparison::<u32, u128, u128>();
1060
1061 engine.register_comparison::<u64, u64, u64>();
1062 engine.register_comparison::<u64, usize, u128>();
1063 engine.register_comparison::<u64, u128, u128>();
1064
1065 engine.register_comparison::<usize, usize, u128>();
1066 engine.register_comparison::<usize, u128, u128>();
1067
1068 engine.register_comparison::<u128, u128, u128>();
1069
1070 engine.register_comparison::<i8, i8, i8>();
1071 engine.register_comparison::<i8, i16, i16>();
1072 engine.register_comparison::<i8, i32, i32>();
1073 engine.register_comparison::<i8, i64, i64>();
1074 engine.register_comparison::<i8, isize, i128>();
1075 engine.register_comparison::<i8, i128, i128>();
1076
1077 engine.register_comparison::<i16, i16, i16>();
1078 engine.register_comparison::<i16, i32, i32>();
1079 engine.register_comparison::<i16, i64, i64>();
1080 engine.register_comparison::<i8, isize, i128>();
1081 engine.register_comparison::<i16, i128, i128>();
1082
1083 engine.register_comparison::<i32, i32, i32>();
1084 engine.register_comparison::<i32, i64, i64>();
1085 engine.register_comparison::<i32, isize, i128>();
1086 engine.register_comparison::<i32, i128, i128>();
1087
1088 engine.register_comparison::<i64, i64, i64>();
1089 engine.register_comparison::<i64, isize, i128>();
1090 engine.register_comparison::<i64, i128, i128>();
1091
1092 engine.register_comparison::<isize, isize, i128>();
1093 engine.register_comparison::<isize, i128, i128>();
1094
1095 engine.register_comparison::<i128, i128, i128>();
1096
1097 engine.register_comparison::<f32, f32, f32>();
1098 engine.register_comparison::<f32, f64, f64>();
1099
1100 engine.register_comparison::<u8, f32, f32>();
1101 engine.register_comparison::<u16, f32, f32>();
1102 engine.register_comparison::<u32, f64, f64>();
1103
1104 engine.register_comparison::<i8, f32, f32>();
1105 engine.register_comparison::<i16, f32, f32>();
1106 engine.register_comparison::<i32, f64, f64>();
1107
1108 engine.register_value::<&str>();
1109 engine.register_value::<String>();
1110 engine.register_value::<bool>();
1111 engine.register_value::<i64>();
1112 engine.register_value::<u64>();
1113 engine.register_value::<i32>();
1114 engine.register_value::<u32>();
1115 engine.register_value::<i16>();
1116 engine.register_value::<u16>();
1117 engine.register_value::<i8>();
1118 engine.register_value::<u8>();
1119 engine.register_value::<usize>();
1120 engine.register_value::<isize>();
1121 engine.register_value::<i128>();
1122 engine.register_value::<u128>();
1123 engine.register_value::<f32>();
1124 engine.register_value::<f64>();
1125
1126 {
1127 let messages = engine.clone_messages();
1128 engine.register_fn("-", move |msg: Dynamic| -> ScriptResult<()> {
1129 minus_deprecation();
1130 if msg.is_array() {
1131 let arr = msg.into_array().unwrap();
1132 for m in arr {
1133 if let Some(msg) = dynamic_to_string(m)? {
1134 messages.borrow_mut().push(msg);
1135 }
1136 }
1137 } else {
1138 if let Some(msg) = dynamic_to_string(msg)? {
1139 messages.borrow_mut().push(msg);
1140 }
1141 }
1142 Ok(())
1143 });
1144 }
1145
1146 let messages = engine.clone_messages();
1147 engine.register_fn("-", move |msg: serde_value::Value| {
1148 minus_deprecation();
1149 messages
1150 .borrow_mut()
1151 .push(serde_json::to_string(&msg).unwrap());
1152 });
1153
1154 engine.register_fn("++", move |a: serde_value::Value, b: serde_value::Value| {
1155 vec![
1156 serde_json::to_string(&a).unwrap(),
1157 serde_json::to_string(&b).unwrap(),
1158 ]
1159 });
1160
1161 engine.register_concat::<&str>();
1162 engine.register_concat::<String>();
1163 engine.register_concat::<bool>();
1164 engine.register_concat::<i64>();
1165 engine.register_concat::<u64>();
1166 engine.register_concat::<i32>();
1167 engine.register_concat::<u32>();
1168 engine.register_concat::<i16>();
1169 engine.register_concat::<u16>();
1170 engine.register_concat::<i8>();
1171 engine.register_concat::<u8>();
1172 engine.register_concat::<usize>();
1173 engine.register_concat::<isize>();
1174 engine.register_concat::<i128>();
1175 engine.register_concat::<u128>();
1176 engine.register_concat::<f32>();
1177 engine.register_concat::<f64>();
1178
1179 engine.register_vec_printable::<&str>();
1180 engine.register_vec_printable::<String>();
1181 engine.register_vec_printable::<bool>();
1182 engine.register_vec_printable::<i64>();
1183 engine.register_vec_printable::<u64>();
1184 engine.register_vec_printable::<i32>();
1185 engine.register_vec_printable::<u32>();
1186 engine.register_vec_printable::<i16>();
1187 engine.register_vec_printable::<u16>();
1188 engine.register_vec_printable::<i8>();
1189 engine.register_vec_printable::<u8>();
1190 engine.register_vec_printable::<usize>();
1191 engine.register_vec_printable::<isize>();
1192 engine.register_vec_printable::<i128>();
1193 engine.register_vec_printable::<u128>();
1194 engine.register_vec_printable::<f32>();
1195 engine.register_vec_printable::<f64>();
1196
1197 engine.register_vec::<()>();
1198
1199 engine
1200 .register_fn("any", crate::internal::script_any_type::<bool>)
1201 .register_fn("all", crate::internal::script_any_type::<bool>)
1202 .register_fn("none", crate::internal::script_any_type::<bool>)
1203 .register_fn("++", move |(): (), b: &str| vec![b.to_owned()])
1204 .register_fn("++", move |(): (), b: usize| vec![b.to_string()]);
1205 engine
1206 .register_custom_operator("++", 15)
1207 .unwrap()
1208 .register_custom_operator("then_emit", 20)
1209 .unwrap()
1210 .register_fn(
1211 "then_emit",
1212 move |a: bool, msg: &str| {
1213 if a {
1214 Some(msg.to_owned())
1215 } else {
1216 None
1217 }
1218 },
1219 )
1220 .register_fn(
1221 "then_emit",
1222 move |a: bool, msg: Vec<String>| {
1223 if a {
1224 msg
1225 } else {
1226 Vec::new()
1227 }
1228 },
1229 )
1230 .register_custom_operator("or_emit", 20)
1231 .unwrap()
1232 .register_fn(
1233 "or_emit",
1234 move |a: bool, msg: &str| {
1235 if !a {
1236 Some(msg.to_owned())
1237 } else {
1238 None
1239 }
1240 },
1241 )
1242 .register_fn(
1243 "or_emit",
1244 move |a: bool, msg: Vec<String>| {
1245 if a {
1246 msg
1247 } else {
1248 Vec::new()
1249 }
1250 },
1251 );
1252 if debug {
1255 engine.on_print(move |x| eprintln!("INFO => {x}"));
1256 engine.on_debug(move |x, _, pos| eprintln!("DEBUG({pos:?}) => {x}"));
1257 } else {
1258 engine.on_print(|_| ());
1259 engine.on_debug(|_, _, _| ());
1260 }
1261
1262 engine.disable_symbol("eval");
1263
1264 engine
1265}
1266
1267macro_rules! impl_as_cast {
1268 ($A: ty, ($($B: ty),*)) => {
1269 $(
1270 impl AsCast<$B> for $A {
1271 fn as_cast(self) -> $B {
1272 self as $B
1273 }
1274 }
1275 )*
1276 }
1277}
1278
1279trait AsCast<T> {
1280 fn as_cast(self) -> T;
1281}
1282
1283impl_as_cast!(u8, (u8, u16, u32, u64, u128, usize));
1284impl_as_cast!(i8, (i8, i16, i32, i64, i128, isize));
1285
1286impl_as_cast!(u16, (u16, u32, u64, u128, usize));
1287impl_as_cast!(i16, (i16, i32, i64, i128, isize));
1288
1289impl_as_cast!(u32, (u32, u64, u128, usize));
1290impl_as_cast!(i32, (i32, i64, i128, isize));
1291
1292impl_as_cast!(u64, (u64, u128));
1293impl_as_cast!(i64, (i64, i128));
1294
1295impl_as_cast!(usize, (usize, u128));
1296impl_as_cast!(isize, (isize, i128));
1297
1298impl_as_cast!(u128, (u128));
1299impl_as_cast!(i128, (i128));
1300
1301impl_as_cast!(f32, (f32, f64));
1302impl_as_cast!(f64, (f64));
1303
1304impl_as_cast!(u8, (f32, f64));
1305impl_as_cast!(u16, (f32, f64));
1306impl_as_cast!(u32, (f64));
1307
1308impl_as_cast!(i8, (f32, f64));
1309impl_as_cast!(i16, (f32, f64));
1310impl_as_cast!(i32, (f64));