Skip to main content

ad_astra/exports/
number.rs

1////////////////////////////////////////////////////////////////////////////////
2// This file is part of "Ad Astra", an embeddable scripting programming       //
3// language platform.                                                         //
4//                                                                            //
5// This work is proprietary software with source-available code.              //
6//                                                                            //
7// To copy, use, distribute, or contribute to this work, you must agree to    //
8// the terms of the General License Agreement:                                //
9//                                                                            //
10// https://github.com/Eliah-Lakhin/ad-astra/blob/master/EULA.md               //
11//                                                                            //
12// The agreement grants a Basic Commercial License, allowing you to use       //
13// this work in non-commercial and limited commercial products with a total   //
14// gross revenue cap. To remove this commercial limit for one of your         //
15// products, you must acquire a Full Commercial License.                      //
16//                                                                            //
17// If you contribute to the source code, documentation, or related materials, //
18// you must grant me an exclusive license to these contributions.             //
19// Contributions are governed by the "Contributions" section of the General   //
20// License Agreement.                                                         //
21//                                                                            //
22// Copying the work in parts is strictly forbidden, except as permitted       //
23// under the General License Agreement.                                       //
24//                                                                            //
25// If you do not or cannot agree to the terms of this Agreement,              //
26// do not use this work.                                                      //
27//                                                                            //
28// This work is provided "as is", without any warranties, express or implied, //
29// except where such disclaimers are legally invalid.                         //
30//                                                                            //
31// Copyright (c) 2024 Ilya Lakhin (Илья Александрович Лахин).                 //
32// All rights reserved.                                                       //
33////////////////////////////////////////////////////////////////////////////////
34
35use 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    /// A numeric type: an integer or a real number, with or without a sign.
91    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                            // Safety: Types checked above.
335                            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                            // Safety: Types checked above.
350                            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                            // Safety: Types checked above.
365                            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                            // Safety: Types checked above.
380                            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                            // Safety: Types checked above.
395                            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                            // Safety: Types checked above.
410                            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                            // Safety: Types checked above.
425                            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                            // Safety: Types checked above.
440                            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                            // Safety: Types checked above.
455                            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                            // Safety: Types checked above.
470                            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                            // Safety: Types checked above.
485                            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                            // Safety: Types checked above.
500                            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                            // Safety: Types checked above.
534                            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                            // Safety: Types checked above.
549                            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                // Safety: TypeId is checked.
1277                Ok(unsafe { transmute_copy::<<To as cast::From<From>>::Output, To>(&to) })
1278            }
1279
1280            id if id == to_result_id => {
1281                // Safety: TypeId is checked.
1282                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}