ion/
bigint.rs

1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 */
6
7use 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	/// Creates a [BigInt] from a boolean.
24	pub fn from_bool(cx: &Context, boolean: bool) -> BigInt<'_> {
25		BigInt::from(cx.root(unsafe { BigIntFromBool(cx.as_ptr(), boolean) }))
26	}
27
28	/// Creates a [BigInt] from a 64-bit signed integer.
29	pub fn from_i64(cx: &Context, number: i64) -> BigInt<'_> {
30		BigInt::from(cx.root(unsafe { BigIntFromInt64(cx.as_ptr(), number) }))
31	}
32
33	/// Creates a [BigInt] from a 64-bit unsigned integer.
34	pub fn from_u64(cx: &Context, number: u64) -> BigInt<'_> {
35		BigInt::from(cx.root(unsafe { BigIntFromUint64(cx.as_ptr(), number) }))
36	}
37
38	/// Creates a [BigInt] from a double.
39	/// Returns an error if `number` is `NaN`, `Infinity`, `-Infinity` or contains a fractional component.
40	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	/// Creates a [BigInt] from a string.
50	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	/// Converts a [BigInt] to a 64-bit signed integer if possible.
81	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	/// Converts a [BigInt] to a 64-bit unsigned integer if possible.
87	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	/// Converts a [BigInt] to a double.
93	/// Returns `Infinity` or `-Infinity` if it does not fit in a double.
94	pub fn to_f64(&self) -> f64 {
95		unsafe { BigIntToNumber(self.get()) }
96	}
97
98	/// Converts a [BigInt] to a double if it fits in a double.
99	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	/// Converts a [BigInt] to a string.
105	/// Returns `None` if the radix is not within the range (2..=36).
106	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	/// Checks if the [BigInt] is negative.
116	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}