1use std::marker::PhantomData;
8use std::ops::{Deref, DerefMut};
9
10use mozjs::jsapi::mozilla::{Range, RangedPtr};
11use mozjs::jsapi::{
12 BigInt as JSBigInt, BigIntFitsNumber, BigIntFromBool, BigIntFromInt64, BigIntFromUint64, BigIntIsInt64,
13 BigIntIsNegative, BigIntIsUint64, BigIntToNumber, BigIntToString, NumberToBigInt, StringToBigInt1,
14};
15
16use crate::{Context, Exception, Local, String};
17
18pub struct BigInt<'b> {
19 bi: Local<'b, *mut JSBigInt>,
20}
21
22impl<'b> BigInt<'b> {
23 pub fn from_bool(cx: &Context, boolean: bool) -> BigInt<'_> {
25 BigInt::from(cx.root(unsafe { BigIntFromBool(cx.as_ptr(), boolean) }))
26 }
27
28 pub fn from_i64(cx: &Context, number: i64) -> BigInt<'_> {
30 BigInt::from(cx.root(unsafe { BigIntFromInt64(cx.as_ptr(), number) }))
31 }
32
33 pub fn from_u64(cx: &Context, number: u64) -> BigInt<'_> {
35 BigInt::from(cx.root(unsafe { BigIntFromUint64(cx.as_ptr(), number) }))
36 }
37
38 pub fn from_f64(cx: &Context, number: f64) -> Result<BigInt<'_>, Exception> {
41 let bi = unsafe { NumberToBigInt(cx.as_ptr(), number) };
42 if !bi.is_null() {
43 Ok(BigInt::from(cx.root(bi)))
44 } else {
45 Err(Exception::new(cx)?.unwrap())
46 }
47 }
48
49 pub fn from_string(cx: &'b Context, string: &str) -> Result<BigInt<'b>, Option<Exception>> {
51 let mut string: Vec<u16> = string.encode_utf16().collect();
52 let range = string.as_mut_ptr_range();
53 let chars = Range {
54 mStart: RangedPtr {
55 mPtr: range.start,
56 #[cfg(feature = "debugmozjs")]
57 mRangeStart: range.start,
58 #[cfg(feature = "debugmozjs")]
59 mRangeEnd: range.end,
60 _phantom_0: PhantomData,
61 },
62 mEnd: RangedPtr {
63 mPtr: range.end,
64 #[cfg(feature = "debugmozjs")]
65 mRangeStart: range.start,
66 #[cfg(feature = "debugmozjs")]
67 mRangeEnd: range.end,
68 _phantom_0: PhantomData,
69 },
70 _phantom_0: PhantomData,
71 };
72 let bi = unsafe { StringToBigInt1(cx.as_ptr(), &raw const chars) };
73 if !bi.is_null() {
74 Ok(BigInt::from(cx.root(bi)))
75 } else {
76 Err(Exception::new(cx).map_err(|e| Some(Exception::Error(e)))?)
77 }
78 }
79
80 pub fn to_i64(&self) -> Option<i64> {
82 let mut result = 0;
83 unsafe { BigIntIsInt64(self.get(), &raw mut result).then_some(result) }
84 }
85
86 pub fn to_u64(&self) -> Option<u64> {
88 let mut result = 0;
89 unsafe { BigIntIsUint64(self.get(), &raw mut result).then_some(result) }
90 }
91
92 pub fn to_f64(&self) -> f64 {
95 unsafe { BigIntToNumber(self.get()) }
96 }
97
98 pub fn fits_f64(&self) -> Option<f64> {
100 let mut result = 0.0;
101 unsafe { BigIntFitsNumber(self.get(), &raw mut result).then_some(result) }
102 }
103
104 pub fn to_string<'cx>(&self, cx: &'cx Context, radix: u8) -> Option<String<'cx>> {
107 if !(2..=36).contains(&radix) {
108 None
109 } else {
110 let string = unsafe { BigIntToString(cx.as_ptr(), self.handle().into(), radix) };
111 Some(String::from(cx.root(string)))
112 }
113 }
114
115 pub fn is_negative(&self) -> bool {
117 unsafe { BigIntIsNegative(self.get()) }
118 }
119}
120
121impl<'b> From<Local<'b, *mut JSBigInt>> for BigInt<'b> {
122 fn from(bi: Local<'b, *mut JSBigInt>) -> BigInt<'b> {
123 BigInt { bi }
124 }
125}
126
127impl<'o> Deref for BigInt<'o> {
128 type Target = Local<'o, *mut JSBigInt>;
129
130 fn deref(&self) -> &Self::Target {
131 &self.bi
132 }
133}
134
135impl DerefMut for BigInt<'_> {
136 fn deref_mut(&mut self) -> &mut Self::Target {
137 &mut self.bi
138 }
139}