1use std::{
36 any::TypeId,
37 cmp::Ordering,
38 fmt::{Debug, Display},
39 mem::{take, transmute, transmute_copy},
40 ops::*,
41 result::Result as StdResult,
42 str::FromStr,
43 sync::Arc,
44};
45
46use crate::{
47 export,
48 exports::utils::transparent_upcast,
49 report::system_panic,
50 runtime::{
51 ops::{
52 ScriptAdd,
53 ScriptAssign,
54 ScriptBitAnd,
55 ScriptBitOr,
56 ScriptBitXor,
57 ScriptClone,
58 ScriptConcat,
59 ScriptDebug,
60 ScriptDefault,
61 ScriptDisplay,
62 ScriptDiv,
63 ScriptHash,
64 ScriptMul,
65 ScriptNeg,
66 ScriptOrd,
67 ScriptPartialEq,
68 ScriptPartialOrd,
69 ScriptRem,
70 ScriptShl,
71 ScriptShr,
72 ScriptSub,
73 },
74 Arg,
75 Cell,
76 Downcast,
77 NumberCastCause,
78 NumericOperationKind,
79 Origin,
80 Provider,
81 RuntimeError,
82 RuntimeResult,
83 ScriptType,
84 TypeHint,
85 },
86 type_family,
87};
88
89type_family!(
90 pub(crate) static NUMBER_FAMILY = "number";
92);
93
94macro_rules! impl_num {
95 (type $alias:ident($name:expr) = $ty:ty $( as $bool:ident)?) => {
96 #[export(include)]
97 #[export(family(&NUMBER_FAMILY))]
98 #[export(name $name)]
99 pub(crate) type $alias = $ty;
100
101 impl<'a> Downcast<'a> for $ty {
102 fn downcast(origin: Origin, provider: Provider<'a>) -> RuntimeResult<Self> {
103 let mut type_match = provider.type_match();
104
105 if type_match.is::<f32>() {
106 let from = provider.to_owned().take::<f32>(origin)?;
107
108 return from.cast_to(&origin);
109 }
110
111 if type_match.is::<f64>() {
112 let from = provider.to_owned().take::<f64>(origin)?;
113
114 return from.cast_to(&origin);
115 }
116
117 if type_match.is::<i8>() {
118 let from = provider.to_owned().take::<i8>(origin)?;
119
120 return from.cast_to(&origin);
121 }
122
123 if type_match.is::<i16>() {
124 let from = provider.to_owned().take::<i16>(origin)?;
125
126 return from.cast_to(&origin);
127 }
128
129 if type_match.is::<i32>() {
130 let from = provider.to_owned().take::<i32>(origin)?;
131
132 return from.cast_to(&origin);
133 }
134
135 if type_match.is::<i64>() {
136 let from = provider.to_owned().take::<i64>(origin)?;
137
138 return from.cast_to(&origin);
139 }
140
141 if type_match.is::<i128>() {
142 let from = provider.to_owned().take::<i128>(origin)?;
143
144 return from.cast_to(&origin);
145 }
146
147 if type_match.is::<isize>() {
148 let from = provider.to_owned().take::<isize>(origin)?;
149
150 return from.cast_to(&origin);
151 }
152
153 if type_match.is::<str>() {
154 let mut cell = provider.to_owned();
155 let string = cell.borrow_str(origin)?;
156
157 return match <$ty>::from_str(string) {
158 Ok(number) => Ok(number),
159
160 Err(error) => Err(RuntimeError::PrimitiveParse {
161 access_origin: origin,
162 from: string.to_string(),
163 to: <$ty>::type_meta(),
164 cause: Arc::new(error)
165 })
166 };
167 }
168
169 if type_match.is::<u8>() {
170 let from = provider.to_owned().take::<u8>(origin)?;
171
172 return from.cast_to(&origin);
173 }
174
175 if type_match.is::<u16>() {
176 let from = provider.to_owned().take::<u16>(origin)?;
177
178 return from.cast_to(&origin);
179 }
180
181 if type_match.is::<u32>() {
182 let from = provider.to_owned().take::<u32>(origin)?;
183
184 return from.cast_to(&origin);
185 }
186
187 if type_match.is::<u64>() {
188 let from = provider.to_owned().take::<u64>(origin)?;
189
190 return from.cast_to(&origin);
191 }
192
193 if type_match.is::<u128>() {
194 let from = provider.to_owned().take::<u128>(origin)?;
195
196 return from.cast_to(&origin);
197 }
198
199 if type_match.is::<usize>() {
200 let from = provider.to_owned().take::<usize>(origin)?;
201
202 return from.cast_to(&origin);
203 }
204
205 $(if type_match.is::<$bool>() {
206 let from = provider.to_owned().take::<bool>(origin)?;
207
208 return Ok(from as Self);
209 })?
210
211 return Err(type_match.mismatch(origin));
212 }
213
214 #[inline(always)]
215 fn hint() -> TypeHint {
216 TypeHint::Type(<$ty>::type_meta())
217 }
218 }
219
220 impl<'a> Downcast<'a> for &'a $ty {
221 fn downcast(origin: Origin, provider: Provider<'a>) -> RuntimeResult<Self> {
222 let mut type_match = provider.type_match();
223
224 if type_match.is::<$ty>() {
225 return provider.to_borrowed(&origin)?.borrow_ref(origin);
226 }
227
228 return Err(type_match.mismatch(origin));
229 }
230
231 #[inline(always)]
232 fn hint() -> TypeHint {
233 TypeHint::Type(<$ty>::type_meta())
234 }
235 }
236
237 impl<'a> Downcast<'a> for &'a mut $ty {
238 fn downcast(origin: Origin, provider: Provider<'a>) -> RuntimeResult<Self> {
239 let mut type_match = provider.type_match();
240
241 if type_match.is::<$ty>() {
242 return provider.to_borrowed(&origin)?.borrow_mut(origin);
243 }
244
245 return Err(type_match.mismatch(origin));
246 }
247
248 #[inline(always)]
249 fn hint() -> TypeHint {
250 TypeHint::Type(<$ty>::type_meta())
251 }
252 }
253
254 transparent_upcast!($ty);
255
256 #[export(include)]
257 impl ScriptAssign for $ty {
258 type RHS = $ty;
259
260 fn script_assign(
261 _origin: Origin,
262 mut lhs: Arg,
263 mut rhs: Arg,
264 ) -> RuntimeResult<()> {
265 let rhs = <$ty>::downcast(rhs.origin, rhs.provider())?;
266 let lhs = lhs.data.borrow_mut::<$ty>(lhs.origin)?;
267
268 *lhs = rhs;
269
270 Ok(())
271 }
272 }
273
274 #[export(include)]
275 impl ScriptConcat for $ty {
276 type Result = $ty;
277
278 fn script_concat(
279 origin: Origin,
280 items: &mut [Arg],
281 ) -> RuntimeResult<Cell> {
282 canonical_num_concat(origin, items)
283 }
284 }
285
286 #[export(include)]
287 impl ScriptClone for $ty {}
288
289 #[export(include)]
290 impl ScriptDebug for $ty {}
291
292 #[export(include)]
293 impl ScriptDisplay for $ty {}
294
295 #[export(include)]
296 impl ScriptPartialEq for $ty {
297 type RHS = $ty;
298
299 fn script_eq(
300 _origin: Origin,
301 lhs: Arg,
302 mut rhs: Arg,
303 ) -> RuntimeResult<bool> {
304 let lhs = lhs.data.take::<$ty>(lhs.origin)?;
305 let rhs = <$ty>::downcast(rhs.origin, rhs.provider())?;
306
307 Ok(lhs == rhs)
308 }
309 }
310
311 #[export(include)]
312 impl ScriptDefault for $ty {
313 fn script_default(origin: Origin) -> RuntimeResult<Cell> {
314 Cell::give(origin, <$ty>::default())
315 }
316 }
317
318 impl NumConcat for $ty {
319 fn num_concat(origin: Origin, items: &mut [Arg]) -> RuntimeResult<Cell>
320 {
321 let mut result = Vec::<Self>::new();
322
323 for item in items {
324 if item.data.is_nil() {
325 continue;
326 }
327
328 let mut type_match = item.data.type_match();
329
330 if type_match.is::<f32>() {
331 let item_slice = take(&mut item.data).take_vec::<f32>(item.origin)?;
332
333 if TypeId::of::<Self>() == TypeId::of::<f32>() {
334 let mut item_slice = unsafe { transmute::<Vec<f32>, Vec<Self>>(item_slice) };
336
337 result.append(&mut item_slice);
338 continue;
339 }
340
341 CastTo::append_to(item_slice, &item.origin, &mut result)?;
342 continue;
343 }
344
345 if type_match.is::<f64>() {
346 let item_slice = take(&mut item.data).take_vec::<f64>(item.origin)?;
347
348 if TypeId::of::<Self>() == TypeId::of::<f64>() {
349 let mut item_slice = unsafe { transmute::<Vec<f64>, Vec<Self>>(item_slice) };
351
352 result.append(&mut item_slice);
353 continue;
354 }
355
356 CastTo::append_to(item_slice, &item.origin, &mut result)?;
357 continue;
358 }
359
360 if type_match.is::<i128>() {
361 let item_slice = take(&mut item.data).take_vec::<i128>(item.origin)?;
362
363 if TypeId::of::<Self>() == TypeId::of::<i128>() {
364 let mut item_slice = unsafe { transmute::<Vec<i128>, Vec<Self>>(item_slice) };
366
367 result.append(&mut item_slice);
368 continue;
369 }
370
371 CastTo::append_to(item_slice, &item.origin, &mut result)?;
372 continue;
373 }
374
375 if type_match.is::<i16>() {
376 let item_slice = take(&mut item.data).take_vec::<i16>(item.origin)?;
377
378 if TypeId::of::<Self>() == TypeId::of::<i16>() {
379 let mut item_slice = unsafe { transmute::<Vec<i16>, Vec<Self>>(item_slice) };
381
382 result.append(&mut item_slice);
383 continue;
384 }
385
386 CastTo::append_to(item_slice, &item.origin, &mut result)?;
387 continue;
388 }
389
390 if type_match.is::<i32>() {
391 let item_slice = take(&mut item.data).take_vec::<i32>(item.origin)?;
392
393 if TypeId::of::<Self>() == TypeId::of::<i32>() {
394 let mut item_slice = unsafe { transmute::<Vec<i32>, Vec<Self>>(item_slice) };
396
397 result.append(&mut item_slice);
398 continue;
399 }
400
401 CastTo::append_to(item_slice, &item.origin, &mut result)?;
402 continue;
403 }
404
405 if type_match.is::<i64>() {
406 let item_slice = take(&mut item.data).take_vec::<i64>(item.origin)?;
407
408 if TypeId::of::<Self>() == TypeId::of::<i64>() {
409 let mut item_slice = unsafe { transmute::<Vec<i64>, Vec<Self>>(item_slice) };
411
412 result.append(&mut item_slice);
413 continue;
414 }
415
416 CastTo::append_to(item_slice, &item.origin, &mut result)?;
417 continue;
418 }
419
420 if type_match.is::<i8>() {
421 let item_slice = take(&mut item.data).take_vec::<i8>(item.origin)?;
422
423 if TypeId::of::<Self>() == TypeId::of::<i8>() {
424 let mut item_slice = unsafe { transmute::<Vec<i8>, Vec<Self>>(item_slice) };
426
427 result.append(&mut item_slice);
428 continue;
429 }
430
431 CastTo::append_to(item_slice, &item.origin, &mut result)?;
432 continue;
433 }
434
435 if type_match.is::<isize>() {
436 let item_slice = take(&mut item.data).take_vec::<isize>(item.origin)?;
437
438 if TypeId::of::<Self>() == TypeId::of::<isize>() {
439 let mut item_slice = unsafe { transmute::<Vec<isize>, Vec<Self>>(item_slice) };
441
442 result.append(&mut item_slice);
443 continue;
444 }
445
446 CastTo::append_to(item_slice, &item.origin, &mut result)?;
447 continue;
448 }
449
450 if type_match.is::<u128>() {
451 let item_slice = take(&mut item.data).take_vec::<u128>(item.origin)?;
452
453 if TypeId::of::<Self>() == TypeId::of::<u128>() {
454 let mut item_slice = unsafe { transmute::<Vec<u128>, Vec<Self>>(item_slice) };
456
457 result.append(&mut item_slice);
458 continue;
459 }
460
461 CastTo::append_to(item_slice, &item.origin, &mut result)?;
462 continue;
463 }
464
465 if type_match.is::<u16>() {
466 let item_slice = take(&mut item.data).take_vec::<u16>(item.origin)?;
467
468 if TypeId::of::<Self>() == TypeId::of::<u16>() {
469 let mut item_slice = unsafe { transmute::<Vec<u16>, Vec<Self>>(item_slice) };
471
472 result.append(&mut item_slice);
473 continue;
474 }
475
476 CastTo::append_to(item_slice, &item.origin, &mut result)?;
477 continue;
478 }
479
480 if type_match.is::<u32>() {
481 let item_slice = take(&mut item.data).take_vec::<u32>(item.origin)?;
482
483 if TypeId::of::<Self>() == TypeId::of::<u32>() {
484 let mut item_slice = unsafe { transmute::<Vec<u32>, Vec<Self>>(item_slice) };
486
487 result.append(&mut item_slice);
488 continue;
489 }
490
491 CastTo::append_to(item_slice, &item.origin, &mut result)?;
492 continue;
493 }
494
495 if type_match.is::<u64>() {
496 let item_slice = take(&mut item.data).take_vec::<u64>(item.origin)?;
497
498 if TypeId::of::<Self>() == TypeId::of::<u64>() {
499 let mut item_slice = unsafe { transmute::<Vec<u64>, Vec<Self>>(item_slice) };
501
502 result.append(&mut item_slice);
503 continue;
504 }
505
506 CastTo::append_to(item_slice, &item.origin, &mut result)?;
507 continue;
508 }
509
510 if type_match.is::<str>() {
511 let string = item.data.borrow_str(item.origin)?;
512
513 match Self::from_str(string) {
514 Ok(number) => result.push(number),
515
516 Err(error) => {
517 return Err(RuntimeError::PrimitiveParse {
518 access_origin: item.origin,
519 from: string.to_string(),
520 to: Self::type_meta(),
521 cause: Arc::new(error),
522 });
523 }
524 };
525
526 continue;
527 }
528
529 if type_match.is::<u8>() {
530 let item_slice = take(&mut item.data).take_vec::<u8>(item.origin)?;
531
532 if TypeId::of::<Self>() == TypeId::of::<u8>() {
533 let mut item_slice = unsafe { transmute::<Vec<u8>, Vec<Self>>(item_slice) };
535
536 result.append(&mut item_slice);
537 continue;
538 }
539
540 CastTo::append_to(item_slice, &item.origin, &mut result)?;
541 continue;
542 }
543
544 if type_match.is::<usize>() {
545 let item_slice = take(&mut item.data).take_vec::<usize>(item.origin)?;
546
547 if TypeId::of::<Self>() == TypeId::of::<usize>() {
548 let mut item_slice = unsafe { transmute::<Vec<usize>, Vec<Self>>(item_slice) };
550
551 result.append(&mut item_slice);
552 continue;
553 }
554
555 CastTo::append_to(item_slice, &item.origin, &mut result)?;
556 continue;
557 }
558
559 $(if type_match.is::<$bool>() {
560 let item_slice = take(&mut item.data).take_vec::<bool>(item.origin)?;
561
562 for value in item_slice {
563 result.push(value as Self);
564 }
565
566 continue;
567 })?
568
569 return Err(type_match.mismatch(item.origin));
570 }
571
572 if result.is_empty() {
573 return Ok(Cell::nil());
574 };
575
576 Cell::give_vec(origin, result)
577 }
578 }
579 };
580}
581
582macro_rules! impl_int {
583 ($ty:ty) => {
584 #[export(include)]
585 impl ScriptPartialOrd for $ty {
586 type RHS = $ty;
587
588 fn script_partial_cmp(
589 _origin: Origin,
590 mut lhs: Arg,
591 mut rhs: Arg,
592 ) -> RuntimeResult<Option<Ordering>> {
593 let lhs = lhs.data.borrow_ref::<$ty>(lhs.origin)?;
594 let rhs = <$ty>::downcast(rhs.origin, rhs.provider())?;
595
596 Ok(lhs.partial_cmp(&rhs))
597 }
598 }
599
600 #[export(include)]
601 impl ScriptOrd for $ty {
602 fn script_cmp(_origin: Origin, mut lhs: Arg, mut rhs: Arg) -> RuntimeResult<Ordering> {
603 let lhs = lhs.data.borrow_ref::<$ty>(lhs.origin)?;
604 let rhs = rhs.data.borrow_ref::<$ty>(rhs.origin)?;
605
606 Ok(lhs.cmp(&rhs))
607 }
608 }
609
610 #[export(include)]
611 impl ScriptHash for $ty {}
612
613 #[export(include)]
614 impl ScriptAdd for $ty {
615 type RHS = Self;
616 type Result = Self;
617
618 fn script_add(origin: Origin, lhs: Arg, mut rhs: Arg) -> RuntimeResult<Cell> {
619 let lhs = lhs.data.take::<$ty>(lhs.origin)?;
620 let rhs_type = rhs.data.ty();
621 let rhs = <$ty>::downcast(rhs.origin, rhs.provider())?;
622
623 match lhs.checked_add(rhs) {
624 Some(result) => Cell::give(origin, result),
625
626 None => Err(RuntimeError::NumericOperation {
627 invoke_origin: origin,
628 kind: NumericOperationKind::Add,
629 lhs: (<$ty>::type_meta(), Arc::new(lhs)),
630 rhs: Some((rhs_type, Arc::new(rhs))),
631 target: <$ty>::type_meta(),
632 }),
633 }
634 }
635 }
636
637 #[export(include)]
638 impl ScriptSub for $ty {
639 type RHS = Self;
640 type Result = Self;
641
642 fn script_sub(origin: Origin, lhs: Arg, mut rhs: Arg) -> RuntimeResult<Cell> {
643 let lhs = lhs.data.take::<$ty>(lhs.origin)?;
644 let rhs_type = rhs.data.ty();
645 let rhs = <$ty>::downcast(rhs.origin, rhs.provider())?;
646
647 match lhs.checked_sub(rhs) {
648 Some(result) => Cell::give(origin, result),
649
650 None => Err(RuntimeError::NumericOperation {
651 invoke_origin: origin,
652 kind: NumericOperationKind::Sub,
653 lhs: (<$ty>::type_meta(), Arc::new(lhs)),
654 rhs: Some((rhs_type, Arc::new(rhs))),
655 target: <$ty>::type_meta(),
656 }),
657 }
658 }
659 }
660
661 #[export(include)]
662 impl ScriptMul for $ty {
663 type RHS = Self;
664 type Result = Self;
665
666 fn script_mul(origin: Origin, lhs: Arg, mut rhs: Arg) -> RuntimeResult<Cell> {
667 let lhs = lhs.data.take::<$ty>(lhs.origin)?;
668 let rhs_type = rhs.data.ty();
669 let rhs = <$ty>::downcast(rhs.origin, rhs.provider())?;
670
671 match lhs.checked_mul(rhs) {
672 Some(result) => Cell::give(origin, result),
673
674 None => Err(RuntimeError::NumericOperation {
675 invoke_origin: origin,
676 kind: NumericOperationKind::Mul,
677 lhs: (<$ty>::type_meta(), Arc::new(lhs)),
678 rhs: Some((rhs_type, Arc::new(rhs))),
679 target: <$ty>::type_meta(),
680 }),
681 }
682 }
683 }
684
685 #[export(include)]
686 impl ScriptDiv for $ty {
687 type RHS = Self;
688 type Result = Self;
689
690 fn script_div(origin: Origin, lhs: Arg, mut rhs: Arg) -> RuntimeResult<Cell> {
691 let lhs = lhs.data.take::<$ty>(lhs.origin)?;
692 let rhs_type = rhs.data.ty();
693 let rhs = <$ty>::downcast(rhs.origin, rhs.provider())?;
694
695 match lhs.checked_div(rhs) {
696 Some(result) => Cell::give(origin, result),
697
698 None => Err(RuntimeError::NumericOperation {
699 invoke_origin: origin,
700 kind: NumericOperationKind::Div,
701 lhs: (<$ty>::type_meta(), Arc::new(lhs)),
702 rhs: Some((rhs_type, Arc::new(rhs))),
703 target: <$ty>::type_meta(),
704 }),
705 }
706 }
707 }
708
709 #[export(include)]
710 impl ScriptNeg for $ty {
711 type Result = Self;
712
713 fn script_neg(origin: Origin, lhs: Arg) -> RuntimeResult<Cell> {
714 let lhs = lhs.data.take::<$ty>(lhs.origin)?;
715
716 match lhs.checked_neg() {
717 Some(result) => Cell::give(origin, result),
718
719 None => Err(RuntimeError::NumericOperation {
720 invoke_origin: origin,
721 kind: NumericOperationKind::Neg,
722 lhs: (<$ty>::type_meta(), Arc::new(lhs)),
723 rhs: None,
724 target: <$ty>::type_meta(),
725 }),
726 }
727 }
728 }
729
730 #[export(include)]
731 impl ScriptBitAnd for $ty {
732 type RHS = Self;
733 type Result = Self;
734
735 fn script_bit_and(origin: Origin, lhs: Arg, mut rhs: Arg) -> RuntimeResult<Cell> {
736 let lhs = lhs.data.take::<$ty>(lhs.origin)?;
737 let rhs = <$ty>::downcast(rhs.origin, rhs.provider())?;
738 let result = lhs.bitand(rhs);
739
740 Cell::give(origin, result)
741 }
742 }
743
744 #[export(include)]
745 impl ScriptBitOr for $ty {
746 type RHS = Self;
747 type Result = Self;
748
749 fn script_bit_or(origin: Origin, lhs: Arg, mut rhs: Arg) -> RuntimeResult<Cell> {
750 let lhs = lhs.data.take::<$ty>(lhs.origin)?;
751 let rhs = <$ty>::downcast(rhs.origin, rhs.provider())?;
752 let result = lhs.bitor(rhs);
753
754 Cell::give(origin, result)
755 }
756 }
757
758 #[export(include)]
759 impl ScriptBitXor for $ty {
760 type RHS = Self;
761 type Result = Self;
762
763 fn script_bit_xor(origin: Origin, lhs: Arg, mut rhs: Arg) -> RuntimeResult<Cell> {
764 let lhs = lhs.data.take::<$ty>(lhs.origin)?;
765 let rhs = <$ty>::downcast(rhs.origin, rhs.provider())?;
766 let result = lhs.bitxor(rhs);
767
768 Cell::give(origin, result)
769 }
770 }
771
772 #[export(include)]
773 impl ScriptShl for $ty {
774 type RHS = u32;
775 type Result = Self;
776
777 fn script_shl(origin: Origin, lhs: Arg, mut rhs: Arg) -> RuntimeResult<Cell> {
778 let lhs = lhs.data.take::<$ty>(lhs.origin)?;
779 let rhs_type = rhs.data.ty();
780 let rhs = <u32>::downcast(rhs.origin, rhs.provider())?;
781
782 match lhs.checked_shl(rhs) {
783 Some(result) => Cell::give(origin, result),
784
785 None => Err(RuntimeError::NumericOperation {
786 invoke_origin: origin,
787 kind: NumericOperationKind::Shl,
788 lhs: (<$ty>::type_meta(), Arc::new(lhs)),
789 rhs: Some((rhs_type, Arc::new(rhs))),
790 target: <$ty>::type_meta(),
791 }),
792 }
793 }
794 }
795
796 #[export(include)]
797 impl ScriptShr for $ty {
798 type RHS = u32;
799 type Result = Self;
800
801 fn script_shr(origin: Origin, lhs: Arg, mut rhs: Arg) -> RuntimeResult<Cell> {
802 let lhs = lhs.data.take::<$ty>(lhs.origin)?;
803 let rhs_type = rhs.data.ty();
804 let rhs = <u32>::downcast(rhs.origin, rhs.provider())?;
805
806 match lhs.checked_shr(rhs) {
807 Some(result) => Cell::give(origin, result),
808
809 None => Err(RuntimeError::NumericOperation {
810 invoke_origin: origin,
811 kind: NumericOperationKind::Shr,
812 lhs: (<$ty>::type_meta(), Arc::new(lhs)),
813 rhs: Some((rhs_type, Arc::new(rhs))),
814 target: <$ty>::type_meta(),
815 }),
816 }
817 }
818 }
819
820 #[export(include)]
821 impl ScriptRem for $ty {
822 type RHS = Self;
823 type Result = Self;
824
825 fn script_rem(origin: Origin, lhs: Arg, mut rhs: Arg) -> RuntimeResult<Cell> {
826 let lhs = lhs.data.take::<$ty>(lhs.origin)?;
827 let rhs_type = rhs.data.ty();
828 let rhs = <$ty>::downcast(rhs.origin, rhs.provider())?;
829
830 match lhs.checked_rem(rhs) {
831 Some(result) => Cell::give(origin, result),
832
833 None => Err(RuntimeError::NumericOperation {
834 invoke_origin: origin,
835 kind: NumericOperationKind::Rem,
836 lhs: (<$ty>::type_meta(), Arc::new(lhs)),
837 rhs: Some((rhs_type, Arc::new(rhs))),
838 target: <$ty>::type_meta(),
839 }),
840 }
841 }
842 }
843 };
844}
845
846macro_rules! impl_float {
847 ($ty:ty) => {
848 #[export(include)]
849 impl ScriptPartialOrd for $ty {
850 type RHS = $ty;
851
852 fn script_partial_cmp(
853 _origin: Origin,
854 mut lhs: Arg,
855 mut rhs: Arg,
856 ) -> RuntimeResult<Option<Ordering>> {
857 let lhs = lhs.data.borrow_ref::<$ty>(lhs.origin)?;
858 let rhs = <$ty>::downcast(rhs.origin, rhs.provider())?;
859
860 Ok(lhs.partial_cmp(&rhs))
861 }
862 }
863
864 #[export(include)]
865 impl ScriptAdd for $ty {
866 type RHS = Self;
867 type Result = Self;
868
869 fn script_add(origin: Origin, lhs: Arg, mut rhs: Arg) -> RuntimeResult<Cell> {
870 let lhs = lhs.data.take::<$ty>(lhs.origin)?;
871 let rhs = <$ty>::downcast(rhs.origin, rhs.provider())?;
872
873 Cell::give(origin, lhs + rhs)
874 }
875 }
876
877 #[export(include)]
878 impl ScriptSub for $ty {
879 type RHS = Self;
880 type Result = Self;
881
882 fn script_sub(origin: Origin, lhs: Arg, mut rhs: Arg) -> RuntimeResult<Cell> {
883 let lhs = lhs.data.take::<$ty>(lhs.origin)?;
884 let rhs = <$ty>::downcast(rhs.origin, rhs.provider())?;
885
886 Cell::give(origin, lhs - rhs)
887 }
888 }
889
890 #[export(include)]
891 impl ScriptMul for $ty {
892 type RHS = Self;
893 type Result = Self;
894
895 fn script_mul(origin: Origin, lhs: Arg, mut rhs: Arg) -> RuntimeResult<Cell> {
896 let lhs = lhs.data.take::<$ty>(lhs.origin)?;
897 let rhs = <$ty>::downcast(rhs.origin, rhs.provider())?;
898
899 Cell::give(origin, lhs * rhs)
900 }
901 }
902
903 #[export(include)]
904 impl ScriptDiv for $ty {
905 type RHS = Self;
906 type Result = Self;
907
908 fn script_div(origin: Origin, lhs: Arg, mut rhs: Arg) -> RuntimeResult<Cell> {
909 let lhs = lhs.data.take::<$ty>(lhs.origin)?;
910 let rhs = <$ty>::downcast(rhs.origin, rhs.provider())?;
911
912 Cell::give(origin, lhs / rhs)
913 }
914 }
915 };
916}
917
918impl_num!(type F32("f32") = f32);
919impl_float!(f32);
920
921impl_num!(type F64("f64") = f64);
922impl_float!(f64);
923
924impl_num!(type I128("i128") = i128 as bool);
925impl_int!(i128);
926
927impl_num!(type I16("i16") = i16 as bool);
928impl_int!(i16);
929
930impl_num!(type I32("i32") = i32 as bool);
931impl_int!(i32);
932
933impl_num!(type I64("i64") = i64 as bool);
934impl_int!(i64);
935
936impl_num!(type I8("i8") = i8 as bool);
937impl_int!(i8);
938
939impl_num!(type ISIZE("isize") = isize as bool);
940impl_int!(isize);
941
942impl_num!(type U128("u128") = u128 as bool);
943impl_int!(u128);
944
945impl_num!(type U16("u16") = u16 as bool);
946impl_int!(u16);
947
948impl_num!(type U32("u32") = u32 as bool);
949impl_int!(u32);
950
951impl_num!(type U64("u64") = u64 as bool);
952impl_int!(u64);
953
954impl_num!(type U8("u8") = u8 as bool);
955impl_int!(u8);
956
957impl_num!(type USIZE("usize") = usize as bool);
958impl_int!(usize);
959
960#[inline(always)]
961fn canonical_num_concat(origin: Origin, items: &mut [Arg]) -> RuntimeResult<Cell> {
962 #[derive(Clone, Copy, PartialEq, Eq)]
963 enum ExactDepth {
964 Depth8,
965 Depth16,
966 Depth32,
967 Depth64,
968 }
969
970 impl PartialOrd for ExactDepth {
971 #[inline(always)]
972 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
973 Some(self.cmp(other))
974 }
975 }
976
977 impl Ord for ExactDepth {
978 #[inline(always)]
979 fn cmp(&self, other: &Self) -> Ordering {
980 self.depth().cmp(&other.depth())
981 }
982 }
983
984 impl ExactDepth {
985 #[inline(always)]
986 fn platform() -> Self {
987 #[cfg(target_pointer_width = "64")]
988 {
989 return Self::Depth64;
990 }
991
992 #[cfg(target_pointer_width = "32")]
993 {
994 return Self::Depth32;
995 }
996
997 #[cfg(target_pointer_width = "16")]
998 {
999 return Self::Depth16;
1000 }
1001
1002 #[allow(unreachable_code)]
1003 {
1004 return Self::Depth64;
1005 }
1006 }
1007
1008 #[inline(always)]
1009 fn depth(&self) -> u8 {
1010 match self {
1011 ExactDepth::Depth8 => 8,
1012 ExactDepth::Depth16 => 16,
1013 ExactDepth::Depth32 => 32,
1014 ExactDepth::Depth64 => 64,
1015 }
1016 }
1017 }
1018
1019 #[derive(Clone, Copy)]
1020 enum BitDepth {
1021 Unknown,
1022 Platform,
1023 Exact(ExactDepth),
1024 }
1025
1026 impl BitDepth {
1027 #[inline(always)]
1028 fn impose_platform(&mut self) {
1029 match self {
1030 Self::Unknown => *self = Self::Platform,
1031 Self::Platform => (),
1032 Self::Exact(current) => *current = (*current).max(ExactDepth::platform()),
1033 }
1034 }
1035
1036 #[inline(always)]
1037 fn impose_exact(&mut self, depth: ExactDepth) {
1038 match self {
1039 Self::Unknown => *self = Self::Exact(depth),
1040 Self::Platform => *self = Self::Exact(ExactDepth::platform().max(depth)),
1041 Self::Exact(current) => *current = (*current).max(depth),
1042 }
1043 }
1044 }
1045
1046 struct Features {
1047 signed: bool,
1048 float: bool,
1049 bit_depth: BitDepth,
1050 }
1051
1052 impl Features {
1053 #[inline(always)]
1054 fn new() -> Self {
1055 Self {
1056 signed: false,
1057 float: false,
1058 bit_depth: BitDepth::Unknown,
1059 }
1060 }
1061
1062 #[inline(always)]
1063 fn impose_f32(&mut self) {
1064 self.signed = true;
1065 self.float = true;
1066 self.bit_depth.impose_exact(ExactDepth::Depth32);
1067 }
1068
1069 #[inline(always)]
1070 fn impose_f64(&mut self) {
1071 self.signed = true;
1072 self.float = true;
1073 self.bit_depth.impose_exact(ExactDepth::Depth64);
1074 }
1075
1076 #[inline(always)]
1077 fn impose_i128(&mut self) {
1078 self.signed = true;
1079 self.bit_depth.impose_exact(ExactDepth::Depth64);
1080 }
1081
1082 #[inline(always)]
1083 fn impose_i16(&mut self) {
1084 self.signed = true;
1085 self.bit_depth.impose_exact(ExactDepth::Depth16);
1086 }
1087
1088 #[inline(always)]
1089 fn impose_i32(&mut self) {
1090 self.signed = true;
1091 self.bit_depth.impose_exact(ExactDepth::Depth32);
1092 }
1093
1094 #[inline(always)]
1095 fn impose_i64(&mut self) {
1096 self.signed = true;
1097 self.bit_depth.impose_exact(ExactDepth::Depth64);
1098 }
1099
1100 #[inline(always)]
1101 fn impose_i8(&mut self) {
1102 self.signed = true;
1103 self.bit_depth.impose_exact(ExactDepth::Depth8);
1104 }
1105
1106 #[inline(always)]
1107 fn impose_isize(&mut self) {
1108 self.signed = true;
1109 self.bit_depth.impose_platform();
1110 }
1111
1112 #[inline(always)]
1113 fn impose_u128(&mut self) {
1114 self.bit_depth.impose_exact(ExactDepth::Depth64);
1115 }
1116
1117 #[inline(always)]
1118 fn impose_u16(&mut self) {
1119 self.bit_depth.impose_exact(ExactDepth::Depth16);
1120 }
1121
1122 #[inline(always)]
1123 fn impose_u32(&mut self) {
1124 self.bit_depth.impose_exact(ExactDepth::Depth32);
1125 }
1126
1127 #[inline(always)]
1128 fn impose_u64(&mut self) {
1129 self.bit_depth.impose_exact(ExactDepth::Depth64);
1130 }
1131
1132 #[inline(always)]
1133 fn impose_u8(&mut self) {
1134 self.bit_depth.impose_exact(ExactDepth::Depth8);
1135 }
1136
1137 #[inline(always)]
1138 fn impose_usize(&mut self) {
1139 self.bit_depth.impose_platform();
1140 }
1141 }
1142
1143 let mut features = Features::new();
1144
1145 for item in items.iter() {
1146 let id = *item.data.ty().id();
1147
1148 if id == TypeId::of::<f32>() {
1149 features.impose_f32();
1150 continue;
1151 }
1152
1153 if id == TypeId::of::<f64>() {
1154 features.impose_f64();
1155 continue;
1156 }
1157
1158 if id == TypeId::of::<i128>() {
1159 features.impose_i128();
1160 continue;
1161 }
1162
1163 if id == TypeId::of::<i16>() {
1164 features.impose_i16();
1165 continue;
1166 }
1167
1168 if id == TypeId::of::<i32>() {
1169 features.impose_i32();
1170 continue;
1171 }
1172
1173 if id == TypeId::of::<i64>() {
1174 features.impose_i64();
1175 continue;
1176 }
1177
1178 if id == TypeId::of::<i8>() {
1179 features.impose_i8();
1180 continue;
1181 }
1182
1183 if id == TypeId::of::<isize>() {
1184 features.impose_isize();
1185 continue;
1186 }
1187
1188 if id == TypeId::of::<u128>() {
1189 features.impose_u128();
1190 continue;
1191 }
1192
1193 if id == TypeId::of::<u16>() {
1194 features.impose_u16();
1195 continue;
1196 }
1197
1198 if id == TypeId::of::<u32>() {
1199 features.impose_u32();
1200 continue;
1201 }
1202
1203 if id == TypeId::of::<u64>() {
1204 features.impose_u64();
1205 continue;
1206 }
1207
1208 if id == TypeId::of::<u8>() {
1209 features.impose_u8();
1210 continue;
1211 }
1212
1213 if id == TypeId::of::<usize>() {
1214 features.impose_usize();
1215 continue;
1216 }
1217 }
1218
1219 match (features.float, features.signed, features.bit_depth) {
1220 (
1221 true,
1222 _,
1223 BitDepth::Exact(ExactDepth::Depth8 | ExactDepth::Depth16 | ExactDepth::Depth32),
1224 ) => f32::num_concat(origin, items),
1225
1226 (true, _, _) => f64::num_concat(origin, items),
1227
1228 (false, true, BitDepth::Unknown | BitDepth::Platform) => isize::num_concat(origin, items),
1229
1230 (false, true, BitDepth::Exact(ExactDepth::Depth8)) => i8::num_concat(origin, items),
1231
1232 (false, true, BitDepth::Exact(ExactDepth::Depth16)) => i16::num_concat(origin, items),
1233
1234 (false, true, BitDepth::Exact(ExactDepth::Depth32)) => i32::num_concat(origin, items),
1235
1236 (false, true, BitDepth::Exact(ExactDepth::Depth64)) => i64::num_concat(origin, items),
1237
1238 (false, false, BitDepth::Unknown | BitDepth::Platform) => usize::num_concat(origin, items),
1239
1240 (false, false, BitDepth::Exact(ExactDepth::Depth8)) => u8::num_concat(origin, items),
1241
1242 (false, false, BitDepth::Exact(ExactDepth::Depth16)) => u16::num_concat(origin, items),
1243
1244 (false, false, BitDepth::Exact(ExactDepth::Depth32)) => u32::num_concat(origin, items),
1245
1246 (false, false, BitDepth::Exact(ExactDepth::Depth64)) => u64::num_concat(origin, items),
1247 }
1248}
1249
1250trait NumConcat {
1251 fn num_concat(origin: Origin, items: &mut [Arg]) -> RuntimeResult<Cell>;
1252}
1253
1254trait CastTo<To> {
1255 fn cast_to(self, origin: &Origin) -> RuntimeResult<To>;
1256
1257 fn append_to(from: Vec<Self>, origin: &Origin, to: &mut Vec<To>) -> RuntimeResult<()>
1258 where
1259 Self: Sized;
1260}
1261
1262impl<From, To> CastTo<To> for From
1263where
1264 From: ScriptType + Debug + Display + Copy,
1265 To: cast::From<From> + ScriptType,
1266 <To as cast::From<From>>::Output: 'static,
1267{
1268 fn cast_to(self, origin: &Origin) -> RuntimeResult<To> {
1269 let to = <To as cast::From<From>>::cast(self);
1270
1271 let to_id = TypeId::of::<To>();
1272 let to_result_id = TypeId::of::<StdResult<To, cast::Error>>();
1273
1274 return match TypeId::of::<<To as cast::From<From>>::Output>() {
1275 id if id == to_id => {
1276 Ok(unsafe { transmute_copy::<<To as cast::From<From>>::Output, To>(&to) })
1278 }
1279
1280 id if id == to_result_id => {
1281 let result = unsafe {
1283 transmute_copy::<<To as cast::From<From>>::Output, StdResult<To, cast::Error>>(
1284 &to,
1285 )
1286 };
1287
1288 match result {
1289 Ok(to) => Ok(to),
1290 Err(cause) => {
1291 let cause = match cause {
1292 cast::Error::Infinite => NumberCastCause::Infinite,
1293 cast::Error::NaN => NumberCastCause::NAN,
1294 cast::Error::Overflow => NumberCastCause::Overflow,
1295 cast::Error::Underflow => NumberCastCause::Underflow,
1296 };
1297
1298 Err(RuntimeError::NumberCast {
1299 access_origin: *origin,
1300 from: From::type_meta(),
1301 to: To::type_meta(),
1302 cause,
1303 value: Arc::new(self),
1304 })
1305 }
1306 }
1307 }
1308
1309 _ => {
1310 system_panic!("Cast Output format has been changed.")
1311 }
1312 };
1313 }
1314
1315 #[inline(always)]
1316 fn append_to(from: Vec<Self>, origin: &Origin, to: &mut Vec<To>) -> RuntimeResult<()>
1317 where
1318 Self: Sized,
1319 {
1320 for item in from {
1321 to.push(item.cast_to(origin)?);
1322 }
1323
1324 Ok(())
1325 }
1326}