jsbind/
bigint.rs

1use crate::error::{RangeError, SyntaxError};
2use crate::utils::bind;
3use alloc::format;
4use alloc::str::FromStr;
5use alloc::string::String;
6
7/// JavaScript BigInt type.
8///
9/// BigInt is a built-in object in JavaScript that provides a way to represent
10/// whole numbers larger than 2^53 - 1.
11#[derive(Clone, Debug)]
12#[repr(transparent)]
13pub struct BigInt {
14    inner: emlite::Val,
15}
16
17bind!(BigInt);
18
19impl FromStr for BigInt {
20    type Err = SyntaxError;
21
22    fn from_str(s: &str) -> Result<Self, Self::Err> {
23        let ctor = emlite::Val::global("BigInt");
24        let result = ctor.invoke(&[s.into()]);
25        result.as_::<Result<Self, SyntaxError>>()
26    }
27}
28
29impl BigInt {
30    /// Creates a new BigInt from an i64.
31    ///
32    /// # Arguments  
33    /// * `value` - The integer value
34    ///
35    /// # Examples
36    /// ```rust
37    /// use jsbind::prelude::*;
38    ///
39    /// let big_num = BigInt::from_i64(9223372036854775807i64);
40    /// ```
41    pub fn from_i64(value: i64) -> Self {
42        let ctor = emlite::Val::global("BigInt");
43        let val = ctor.invoke(&[value.into()]);
44        Self { inner: val }
45    }
46
47    /// Creates a new BigInt from a u64.
48    ///
49    /// # Arguments
50    /// * `value` - The unsigned integer value  
51    ///
52    /// # Examples
53    /// ```rust
54    /// use jsbind::prelude::*;
55    ///
56    /// let big_num = BigInt::from_u64(18446744073709551615u64);
57    /// ```
58    pub fn from_u64(value: u64) -> Self {
59        let ctor = emlite::Val::global("BigInt");
60        let val = ctor.invoke(&[value.into()]);
61        Self { inner: val }
62    }
63
64    /// Converts this BigInt to a string representation.
65    ///
66    /// # Arguments
67    /// * `radix` - Optional radix (base) for the conversion (2-36)
68    ///
69    /// # Returns
70    /// String representation of this BigInt
71    ///
72    /// # Examples
73    /// ```rust
74    /// use jsbind::prelude::*;
75    ///
76    /// let big_num = BigInt::from_str("255");
77    /// assert_eq!(big_num.to_string_with_radix(Some(16)), "ff");
78    /// assert_eq!(big_num.to_string_with_radix(None), "255");
79    /// ```
80    pub fn to_string_with_radix(&self, radix: Option<u32>) -> String {
81        match radix {
82            Some(r) => self
83                .inner
84                .call("toString", &[r.into()])
85                .as_::<Option<String>>()
86                .unwrap_or_default(),
87            None => self
88                .inner
89                .call("toString", &[])
90                .as_::<Option<String>>()
91                .unwrap_or_default(),
92        }
93    }
94
95    /// Converts this BigInt to a string representation (base 10).
96    ///
97    /// # Examples
98    /// ```rust
99    /// use jsbind::prelude::*;
100    ///
101    /// let big_num = BigInt::from_str("123456789");
102    /// assert_eq!(big_num.to_string_repr(), "123456789");
103    /// ```
104    pub fn to_string_repr(&self) -> String {
105        self.to_string_with_radix(None)
106    }
107
108    /// Returns the primitive value of this BigInt.
109    ///
110    /// # Examples
111    /// ```rust  
112    /// use jsbind::prelude::*;
113    ///
114    /// let big_num = BigInt::from_str("42");
115    /// let primitive = big_num.value_of();
116    /// ```
117    pub fn value_of(&self) -> Self {
118        let val = self.inner.call("valueOf", &[]);
119        Self { inner: val }
120    }
121
122    /// Converts this BigInt to a standard Rust i64.
123    ///
124    /// # Returns
125    /// `Result<i64, RangeError>` with specific error details if conversion fails
126    ///
127    /// # Examples
128    /// ```rust
129    /// use jsbind::prelude::*;
130    ///
131    /// let small = BigInt::from_i64(42);
132    /// assert!(small.to_i64().is_ok());
133    ///
134    /// let too_big = BigInt::from_str("999999999999999999999999999999").unwrap();
135    /// assert!(too_big.to_i64().is_err());
136    /// ```
137    pub fn to_i64(&self) -> Result<i64, RangeError> {
138        // Check if it's within i64 range by comparing with MAX/MIN
139        let max_check = emlite::Val::global("eval").invoke(&[format!(
140            "({}) <= {}n",
141            self.to_string_repr(),
142            i64::MAX
143        )
144        .into()]);
145        let min_check = emlite::Val::global("eval").invoke(&[format!(
146            "({}) >= {}n",
147            self.to_string_repr(),
148            i64::MIN
149        )
150        .into()]);
151
152        if max_check.as_::<bool>() && min_check.as_::<bool>() {
153            Ok(emlite::Val::global("Number")
154                .invoke(&[self.inner.clone()])
155                .as_::<i64>())
156        } else {
157            Err(RangeError::new(&format!(
158                "BigInt value {} is out of i64 range",
159                self.to_string_repr()
160            )))
161        }
162    }
163
164    /// Converts this BigInt to a standard Rust u64.
165    ///
166    /// # Returns
167    /// `Result<u64, RangeError>` with specific error details if conversion fails
168    ///
169    /// # Examples
170    /// ```rust
171    /// use jsbind::prelude::*;
172    ///
173    /// let positive = BigInt::from_u64(42);
174    /// assert!(positive.to_u64().is_ok());
175    ///
176    /// let negative = BigInt::from_i64(-1);
177    /// assert!(negative.to_u64().is_err());
178    /// ```
179    pub fn to_u64(&self) -> Result<u64, RangeError> {
180        // Check if non-negative and within u64 range
181        let pos_check =
182            emlite::Val::global("eval")
183                .invoke(&[format!("({}) >= 0n", self.to_string_repr()).into()]);
184        let max_check = emlite::Val::global("eval").invoke(&[format!(
185            "({}) <= {}n",
186            self.to_string_repr(),
187            u64::MAX
188        )
189        .into()]);
190
191        if pos_check.as_::<bool>() && max_check.as_::<bool>() {
192            Ok(emlite::Val::global("Number")
193                .invoke(&[self.inner.clone()])
194                .as_::<u64>())
195        } else if !pos_check.as_::<bool>() {
196            Err(RangeError::new(&format!(
197                "BigInt value {} is negative and cannot be converted to u64",
198                self.to_string_repr()
199            )))
200        } else {
201            Err(RangeError::new(&format!(
202                "BigInt value {} is too large for u64",
203                self.to_string_repr()
204            )))
205        }
206    }
207
208    /// Power operation
209    pub fn pow(&self, other: &BigInt) -> BigInt {
210        let result = emlite::Val::global("eval").invoke(&[format!(
211            "({}) ** ({})",
212            self.to_string_repr(),
213            other.to_string_repr()
214        )
215        .into()]);
216        Self { inner: result }
217    }
218
219    /// Gets hash code for BigInt  
220    pub fn get_hash(&self) -> u64 {
221        use emlite::FromVal;
222        // Simple hash based on the handle value
223        self.inner.as_handle() as u64
224    }
225
226    /// Checks if BigInt equals zero
227    pub fn is_zero(&self) -> bool {
228        self == &Self::zero()
229    }
230
231    /// Checks if BigInt is positive
232    pub fn is_positive(&self) -> bool {
233        self > &Self::zero()
234    }
235
236    /// Checks if BigInt is negative
237    pub fn is_negative(&self) -> bool {
238        self < &Self::zero()
239    }
240
241    /// Gets absolute value
242    pub fn abs(&self) -> BigInt {
243        if self.is_negative() {
244            -self
245        } else {
246            self.clone()
247        }
248    }
249
250    /// Creates BigInt(0)
251    pub fn zero() -> BigInt {
252        Self::from_i64(0)
253    }
254
255    /// Creates BigInt(1)
256    pub fn one() -> BigInt {
257        Self::from_i64(1)
258    }
259
260    /// Creates BigInt(-1)
261    pub fn minus_one() -> BigInt {
262        Self::from_i64(-1)
263    }
264
265    /// Returns signed n-bit BigInt value
266    pub fn as_int_n(width: u32, bigint: &BigInt) -> BigInt {
267        let result =
268            emlite::Val::global("BigInt").call("asIntN", &[width.into(), bigint.inner.clone()]);
269        Self { inner: result }
270    }
271
272    /// Returns unsigned n-bit BigInt value  
273    pub fn as_uint_n(width: u32, bigint: &BigInt) -> BigInt {
274        let result =
275            emlite::Val::global("BigInt").call("asUintN", &[width.into(), bigint.inner.clone()]);
276        Self { inner: result }
277    }
278
279    /// Converts BigInt to locale-specific string
280    pub fn to_locale_string(&self) -> String {
281        self.inner
282            .call("toLocaleString", &[])
283            .as_::<Option<String>>()
284            .unwrap_or_default()
285    }
286
287    /// Parses BigInt from string with error checking
288    pub fn parse(s: &str) -> Result<BigInt, SyntaxError> {
289        Self::from_str(s)
290    }
291}
292
293impl crate::prelude::DynCast for BigInt {
294    fn instanceof(val: &emlite::Val) -> bool {
295        val.type_of() == "bigint"
296    }
297
298    fn unchecked_from_val(v: emlite::Val) -> Self {
299        Self { inner: v }
300    }
301
302    fn unchecked_from_val_ref(v: &emlite::Val) -> &Self {
303        unsafe { &*(v as *const emlite::Val as *const Self) }
304    }
305
306    fn unchecked_from_val_mut(v: &mut emlite::Val) -> &mut Self {
307        unsafe { &mut *(v as *mut emlite::Val as *mut Self) }
308    }
309}
310
311impl core::fmt::Display for BigInt {
312    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
313        write!(f, "{}", self.to_string_repr())
314    }
315}
316
317// Arithmetic operators
318impl core::ops::Add for BigInt {
319    type Output = BigInt;
320    fn add(self, rhs: BigInt) -> Self::Output {
321        let result = emlite::Val::global("eval").invoke(&[format!(
322            "({}) + ({})",
323            self.to_string_repr(),
324            rhs.to_string_repr()
325        )
326        .into()]);
327        BigInt { inner: result }
328    }
329}
330
331impl core::ops::Add for &BigInt {
332    type Output = BigInt;
333    fn add(self, rhs: &BigInt) -> Self::Output {
334        let result = emlite::Val::global("eval").invoke(&[format!(
335            "({}) + ({})",
336            self.to_string_repr(),
337            rhs.to_string_repr()
338        )
339        .into()]);
340        BigInt { inner: result }
341    }
342}
343
344impl core::ops::Sub for BigInt {
345    type Output = BigInt;
346    fn sub(self, rhs: BigInt) -> Self::Output {
347        let result = emlite::Val::global("eval").invoke(&[format!(
348            "({}) - ({})",
349            self.to_string_repr(),
350            rhs.to_string_repr()
351        )
352        .into()]);
353        BigInt { inner: result }
354    }
355}
356
357impl core::ops::Sub for &BigInt {
358    type Output = BigInt;
359    fn sub(self, rhs: &BigInt) -> Self::Output {
360        let result = emlite::Val::global("eval").invoke(&[format!(
361            "({}) - ({})",
362            self.to_string_repr(),
363            rhs.to_string_repr()
364        )
365        .into()]);
366        BigInt { inner: result }
367    }
368}
369
370impl core::ops::Mul for BigInt {
371    type Output = BigInt;
372    fn mul(self, rhs: BigInt) -> Self::Output {
373        let result = emlite::Val::global("eval").invoke(&[format!(
374            "({}) * ({})",
375            self.to_string_repr(),
376            rhs.to_string_repr()
377        )
378        .into()]);
379        BigInt { inner: result }
380    }
381}
382
383impl core::ops::Mul for &BigInt {
384    type Output = BigInt;
385    fn mul(self, rhs: &BigInt) -> Self::Output {
386        let result = emlite::Val::global("eval").invoke(&[format!(
387            "({}) * ({})",
388            self.to_string_repr(),
389            rhs.to_string_repr()
390        )
391        .into()]);
392        BigInt { inner: result }
393    }
394}
395
396impl core::ops::Div for BigInt {
397    type Output = BigInt;
398    fn div(self, rhs: BigInt) -> Self::Output {
399        let result = emlite::Val::global("eval").invoke(&[format!(
400            "({}) / ({})",
401            self.to_string_repr(),
402            rhs.to_string_repr()
403        )
404        .into()]);
405        BigInt { inner: result }
406    }
407}
408
409impl core::ops::Div for &BigInt {
410    type Output = BigInt;
411    fn div(self, rhs: &BigInt) -> Self::Output {
412        let result = emlite::Val::global("eval").invoke(&[format!(
413            "({}) / ({})",
414            self.to_string_repr(),
415            rhs.to_string_repr()
416        )
417        .into()]);
418        BigInt { inner: result }
419    }
420}
421
422impl core::ops::Rem for BigInt {
423    type Output = BigInt;
424    fn rem(self, rhs: BigInt) -> Self::Output {
425        let result = emlite::Val::global("eval").invoke(&[format!(
426            "({}) % ({})",
427            self.to_string_repr(),
428            rhs.to_string_repr()
429        )
430        .into()]);
431        BigInt { inner: result }
432    }
433}
434
435impl core::ops::Rem for &BigInt {
436    type Output = BigInt;
437    fn rem(self, rhs: &BigInt) -> Self::Output {
438        let result = emlite::Val::global("eval").invoke(&[format!(
439            "({}) % ({})",
440            self.to_string_repr(),
441            rhs.to_string_repr()
442        )
443        .into()]);
444        BigInt { inner: result }
445    }
446}
447
448impl core::ops::Neg for BigInt {
449    type Output = BigInt;
450    fn neg(self) -> Self::Output {
451        let result =
452            emlite::Val::global("eval").invoke(&[format!("-({})", self.to_string_repr()).into()]);
453        BigInt { inner: result }
454    }
455}
456
457impl core::ops::Neg for &BigInt {
458    type Output = BigInt;
459    fn neg(self) -> Self::Output {
460        let result =
461            emlite::Val::global("eval").invoke(&[format!("-({})", self.to_string_repr()).into()]);
462        BigInt { inner: result }
463    }
464}
465
466// Bitwise operators
467impl core::ops::BitAnd for BigInt {
468    type Output = BigInt;
469    fn bitand(self, rhs: BigInt) -> Self::Output {
470        let result = emlite::Val::global("eval").invoke(&[format!(
471            "({}) & ({})",
472            self.to_string_repr(),
473            rhs.to_string_repr()
474        )
475        .into()]);
476        BigInt { inner: result }
477    }
478}
479
480impl core::ops::BitAnd for &BigInt {
481    type Output = BigInt;
482    fn bitand(self, rhs: &BigInt) -> Self::Output {
483        let result = emlite::Val::global("eval").invoke(&[format!(
484            "({}) & ({})",
485            self.to_string_repr(),
486            rhs.to_string_repr()
487        )
488        .into()]);
489        BigInt { inner: result }
490    }
491}
492
493impl core::ops::BitOr for BigInt {
494    type Output = BigInt;
495    fn bitor(self, rhs: BigInt) -> Self::Output {
496        let result = emlite::Val::global("eval").invoke(&[format!(
497            "({}) | ({})",
498            self.to_string_repr(),
499            rhs.to_string_repr()
500        )
501        .into()]);
502        BigInt { inner: result }
503    }
504}
505
506impl core::ops::BitOr for &BigInt {
507    type Output = BigInt;
508    fn bitor(self, rhs: &BigInt) -> Self::Output {
509        let result = emlite::Val::global("eval").invoke(&[format!(
510            "({}) | ({})",
511            self.to_string_repr(),
512            rhs.to_string_repr()
513        )
514        .into()]);
515        BigInt { inner: result }
516    }
517}
518
519impl core::ops::BitXor for BigInt {
520    type Output = BigInt;
521    fn bitxor(self, rhs: BigInt) -> Self::Output {
522        let result = emlite::Val::global("eval").invoke(&[format!(
523            "({}) ^ ({})",
524            self.to_string_repr(),
525            rhs.to_string_repr()
526        )
527        .into()]);
528        BigInt { inner: result }
529    }
530}
531
532impl core::ops::BitXor for &BigInt {
533    type Output = BigInt;
534    fn bitxor(self, rhs: &BigInt) -> Self::Output {
535        let result = emlite::Val::global("eval").invoke(&[format!(
536            "({}) ^ ({})",
537            self.to_string_repr(),
538            rhs.to_string_repr()
539        )
540        .into()]);
541        BigInt { inner: result }
542    }
543}
544
545impl core::ops::Not for BigInt {
546    type Output = BigInt;
547    fn not(self) -> Self::Output {
548        let result =
549            emlite::Val::global("eval").invoke(&[format!("~({})", self.to_string_repr()).into()]);
550        BigInt { inner: result }
551    }
552}
553
554impl core::ops::Not for &BigInt {
555    type Output = BigInt;
556    fn not(self) -> Self::Output {
557        let result =
558            emlite::Val::global("eval").invoke(&[format!("~({})", self.to_string_repr()).into()]);
559        BigInt { inner: result }
560    }
561}
562
563impl core::ops::Shl<BigInt> for BigInt {
564    type Output = BigInt;
565    fn shl(self, rhs: BigInt) -> Self::Output {
566        let result = emlite::Val::global("eval").invoke(&[format!(
567            "({}) << ({})",
568            self.to_string_repr(),
569            rhs.to_string_repr()
570        )
571        .into()]);
572        BigInt { inner: result }
573    }
574}
575
576impl core::ops::Shl<&BigInt> for &BigInt {
577    type Output = BigInt;
578    fn shl(self, rhs: &BigInt) -> Self::Output {
579        let result = emlite::Val::global("eval").invoke(&[format!(
580            "({}) << ({})",
581            self.to_string_repr(),
582            rhs.to_string_repr()
583        )
584        .into()]);
585        BigInt { inner: result }
586    }
587}
588
589impl core::ops::Shr<BigInt> for BigInt {
590    type Output = BigInt;
591    fn shr(self, rhs: BigInt) -> Self::Output {
592        let result = emlite::Val::global("eval").invoke(&[format!(
593            "({}) >> ({})",
594            self.to_string_repr(),
595            rhs.to_string_repr()
596        )
597        .into()]);
598        BigInt { inner: result }
599    }
600}
601
602impl core::ops::Shr<&BigInt> for &BigInt {
603    type Output = BigInt;
604    fn shr(self, rhs: &BigInt) -> Self::Output {
605        let result = emlite::Val::global("eval").invoke(&[format!(
606            "({}) >> ({})",
607            self.to_string_repr(),
608            rhs.to_string_repr()
609        )
610        .into()]);
611        BigInt { inner: result }
612    }
613}
614
615// Comparison operators
616impl PartialEq for BigInt {
617    fn eq(&self, other: &Self) -> bool {
618        emlite::Val::global("eval")
619            .invoke(&[format!(
620                "({}) === ({})",
621                self.to_string_repr(),
622                other.to_string_repr()
623            )
624            .into()])
625            .as_::<bool>()
626    }
627}
628
629impl Eq for BigInt {}
630
631impl PartialOrd for BigInt {
632    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
633        Some(self.cmp(other))
634    }
635}
636
637impl Ord for BigInt {
638    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
639        let lt = emlite::Val::global("eval")
640            .invoke(&[format!("({}) < ({})", self.to_string_repr(), other.to_string_repr()).into()])
641            .as_::<bool>();
642        let gt = emlite::Val::global("eval")
643            .invoke(&[format!("({}) > ({})", self.to_string_repr(), other.to_string_repr()).into()])
644            .as_::<bool>();
645
646        if lt {
647            core::cmp::Ordering::Less
648        } else if gt {
649            core::cmp::Ordering::Greater
650        } else {
651            core::cmp::Ordering::Equal
652        }
653    }
654}
655
656impl core::hash::Hash for BigInt {
657    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
658        use emlite::FromVal;
659        self.inner.as_handle().hash(state);
660    }
661}
662
663// Assignment operators
664impl core::ops::AddAssign for BigInt {
665    fn add_assign(&mut self, rhs: BigInt) {
666        *self = core::mem::take(self) + rhs;
667    }
668}
669
670impl core::ops::AddAssign<&BigInt> for BigInt {
671    fn add_assign(&mut self, rhs: &BigInt) {
672        *self = &*self + rhs;
673    }
674}
675
676impl core::ops::SubAssign for BigInt {
677    fn sub_assign(&mut self, rhs: BigInt) {
678        *self = core::mem::take(self) - rhs;
679    }
680}
681
682impl core::ops::SubAssign<&BigInt> for BigInt {
683    fn sub_assign(&mut self, rhs: &BigInt) {
684        *self = &*self - rhs;
685    }
686}
687
688impl core::ops::MulAssign for BigInt {
689    fn mul_assign(&mut self, rhs: BigInt) {
690        *self = core::mem::take(self) * rhs;
691    }
692}
693
694impl core::ops::MulAssign<&BigInt> for BigInt {
695    fn mul_assign(&mut self, rhs: &BigInt) {
696        *self = &*self * rhs;
697    }
698}
699
700impl core::ops::DivAssign for BigInt {
701    fn div_assign(&mut self, rhs: BigInt) {
702        *self = core::mem::take(self) / rhs;
703    }
704}
705
706impl core::ops::DivAssign<&BigInt> for BigInt {
707    fn div_assign(&mut self, rhs: &BigInt) {
708        *self = &*self / rhs;
709    }
710}
711
712impl core::ops::RemAssign for BigInt {
713    fn rem_assign(&mut self, rhs: BigInt) {
714        *self = core::mem::take(self) % rhs;
715    }
716}
717
718impl core::ops::RemAssign<&BigInt> for BigInt {
719    fn rem_assign(&mut self, rhs: &BigInt) {
720        *self = &*self % rhs;
721    }
722}
723
724impl core::ops::BitAndAssign for BigInt {
725    fn bitand_assign(&mut self, rhs: BigInt) {
726        *self = core::mem::take(self) & rhs;
727    }
728}
729
730impl core::ops::BitAndAssign<&BigInt> for BigInt {
731    fn bitand_assign(&mut self, rhs: &BigInt) {
732        *self = &*self & rhs;
733    }
734}
735
736impl core::ops::BitOrAssign for BigInt {
737    fn bitor_assign(&mut self, rhs: BigInt) {
738        *self = core::mem::take(self) | rhs;
739    }
740}
741
742impl core::ops::BitOrAssign<&BigInt> for BigInt {
743    fn bitor_assign(&mut self, rhs: &BigInt) {
744        *self = &*self | rhs;
745    }
746}
747
748impl core::ops::BitXorAssign for BigInt {
749    fn bitxor_assign(&mut self, rhs: BigInt) {
750        *self = core::mem::take(self) ^ rhs;
751    }
752}
753
754impl core::ops::BitXorAssign<&BigInt> for BigInt {
755    fn bitxor_assign(&mut self, rhs: &BigInt) {
756        *self = &*self ^ rhs;
757    }
758}
759
760impl core::ops::ShlAssign<BigInt> for BigInt {
761    fn shl_assign(&mut self, rhs: BigInt) {
762        *self = core::mem::take(self) << rhs;
763    }
764}
765
766impl core::ops::ShlAssign<&BigInt> for BigInt {
767    fn shl_assign(&mut self, rhs: &BigInt) {
768        *self = &*self << rhs;
769    }
770}
771
772impl core::ops::ShrAssign<BigInt> for BigInt {
773    fn shr_assign(&mut self, rhs: BigInt) {
774        *self = core::mem::take(self) >> rhs;
775    }
776}
777
778impl core::ops::ShrAssign<&BigInt> for BigInt {
779    fn shr_assign(&mut self, rhs: &BigInt) {
780        *self = &*self >> rhs;
781    }
782}
783
784impl Default for BigInt {
785    fn default() -> Self {
786        Self::zero()
787    }
788}