• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // This file is part of ICU4X. For terms of use, please see the file
2 // called LICENSE at the top level of the ICU4X source tree
3 // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4 
5 use ffi::FixedDecimalSignedRoundingMode;
6 
7 #[diplomat::bridge]
8 #[diplomat::abi_rename = "icu4x_{0}_mv1"]
9 #[diplomat::attr(auto, namespace = "icu4x")]
10 pub mod ffi {
11     use alloc::boxed::Box;
12 
13     use crate::errors::ffi::{FixedDecimalLimitError, FixedDecimalParseError};
14 
15     use writeable::Writeable;
16 
17     #[diplomat::opaque]
18     #[diplomat::rust_link(fixed_decimal::FixedDecimal, Struct)]
19     #[diplomat::rust_link(fixed_decimal::Decimal, Typedef, hidden)]
20     pub struct Decimal(pub fixed_decimal::Decimal);
21 
22     /// The sign of a FixedDecimal, as shown in formatting.
23     #[diplomat::rust_link(fixed_decimal::Sign, Enum)]
24     #[diplomat::enum_convert(fixed_decimal::Sign, needs_wildcard)]
25     pub enum FixedDecimalSign {
26         /// No sign (implicitly positive, e.g., 1729).
27         None,
28         /// A negative sign, e.g., -1729.
29         Negative,
30         /// An explicit positive sign, e.g., +1729.
31         Positive,
32     }
33 
34     /// ECMA-402 compatible sign display preference.
35     #[diplomat::rust_link(fixed_decimal::SignDisplay, Enum)]
36     #[diplomat::enum_convert(fixed_decimal::SignDisplay, needs_wildcard)]
37     pub enum FixedDecimalSignDisplay {
38         Auto,
39         Never,
40         Always,
41         ExceptZero,
42         Negative,
43     }
44 
45     /// Increment used in a rounding operation.
46     #[diplomat::rust_link(fixed_decimal::RoundingIncrement, Enum)]
47     #[diplomat::enum_convert(fixed_decimal::RoundingIncrement, needs_wildcard)]
48     pub enum FixedDecimalRoundingIncrement {
49         MultiplesOf1,
50         MultiplesOf2,
51         MultiplesOf5,
52         MultiplesOf25,
53     }
54 
55     /// Mode used in a rounding operation for signed numbers.
56     #[diplomat::rust_link(fixed_decimal::SignedRoundingMode, Enum)]
57     pub enum FixedDecimalSignedRoundingMode {
58         Expand,
59         Trunc,
60         HalfExpand,
61         HalfTrunc,
62         HalfEven,
63         Ceil,
64         Floor,
65         HalfCeil,
66         HalfFloor,
67     }
68 
69     impl Decimal {
70         /// Construct an [`Decimal`] from an integer.
71         #[diplomat::rust_link(fixed_decimal::FixedDecimal, Struct)]
72         #[diplomat::attr(dart, disable)]
73         #[diplomat::attr(js, rename = "from_number")]
74         #[diplomat::attr(supports = method_overloading, rename = "from")]
75         #[diplomat::attr(auto, named_constructor)]
from_int32(v: i32) -> Box<Decimal>76         pub fn from_int32(v: i32) -> Box<Decimal> {
77             Box::new(Decimal(fixed_decimal::Decimal::from(v)))
78         }
79 
80         /// Construct an [`Decimal`] from an integer.
81         #[diplomat::rust_link(fixed_decimal::FixedDecimal, Struct)]
82         #[diplomat::attr(dart, disable)]
83         #[diplomat::attr(js, disable)]
84         #[diplomat::attr(supports = method_overloading, rename = "from")]
85         #[diplomat::attr(auto, named_constructor)]
from_uint32(v: u32) -> Box<Decimal>86         pub fn from_uint32(v: u32) -> Box<Decimal> {
87             Box::new(Decimal(fixed_decimal::Decimal::from(v)))
88         }
89 
90         /// Construct an [`Decimal`] from an integer.
91         #[diplomat::rust_link(fixed_decimal::FixedDecimal, Struct)]
92         #[diplomat::attr(dart, rename = "from_int")]
93         #[diplomat::attr(js, rename = "from_big_int")]
94         #[diplomat::attr(supports = method_overloading, rename = "from")]
95         #[diplomat::attr(auto, named_constructor)]
from_int64(v: i64) -> Box<Decimal>96         pub fn from_int64(v: i64) -> Box<Decimal> {
97             Box::new(Decimal(fixed_decimal::Decimal::from(v)))
98         }
99 
100         /// Construct an [`Decimal`] from an integer.
101         #[diplomat::rust_link(fixed_decimal::FixedDecimal, Struct)]
102         #[diplomat::attr(any(dart, js), disable)]
103         #[diplomat::attr(supports = method_overloading, rename = "from")]
104         #[diplomat::attr(auto, named_constructor)]
from_uint64(v: u64) -> Box<Decimal>105         pub fn from_uint64(v: u64) -> Box<Decimal> {
106             Box::new(Decimal(fixed_decimal::Decimal::from(v)))
107         }
108 
109         /// Construct an [`Decimal`] from an integer-valued float
110         #[diplomat::rust_link(fixed_decimal::FixedDecimal::try_from_f64, FnInStruct)]
111         #[diplomat::rust_link(fixed_decimal::FloatPrecision, Enum)]
112         #[diplomat::rust_link(fixed_decimal::DoublePrecision, Enum, hidden)]
113         #[diplomat::attr(any(dart, js), disable)]
114         #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)]
from_double_with_integer_precision( f: f64, ) -> Result<Box<Decimal>, FixedDecimalLimitError>115         pub fn from_double_with_integer_precision(
116             f: f64,
117         ) -> Result<Box<Decimal>, FixedDecimalLimitError> {
118             let precision = fixed_decimal::DoublePrecision::Integer;
119             Ok(Box::new(Decimal(fixed_decimal::Decimal::try_from_f64(
120                 f, precision,
121             )?)))
122         }
123 
124         /// Construct an [`Decimal`] from an float, with a given power of 10 for the lower magnitude
125         #[diplomat::rust_link(fixed_decimal::FixedDecimal::try_from_f64, FnInStruct)]
126         #[diplomat::rust_link(fixed_decimal::FloatPrecision, Enum)]
127         #[diplomat::rust_link(fixed_decimal::DoublePrecision, Enum, hidden)]
128         #[diplomat::attr(js, rename = "from_number_with_lower_magnitude")]
129         #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)]
130         #[diplomat::demo(default_constructor)]
from_double_with_lower_magnitude( f: f64, magnitude: i16, ) -> Result<Box<Decimal>, FixedDecimalLimitError>131         pub fn from_double_with_lower_magnitude(
132             f: f64,
133             magnitude: i16,
134         ) -> Result<Box<Decimal>, FixedDecimalLimitError> {
135             let precision = fixed_decimal::DoublePrecision::Magnitude(magnitude);
136             Ok(Box::new(Decimal(fixed_decimal::Decimal::try_from_f64(
137                 f, precision,
138             )?)))
139         }
140 
141         /// Construct an [`Decimal`] from an float, for a given number of significant digits
142         #[diplomat::rust_link(fixed_decimal::FixedDecimal::try_from_f64, FnInStruct)]
143         #[diplomat::rust_link(fixed_decimal::FloatPrecision, Enum)]
144         #[diplomat::rust_link(fixed_decimal::DoublePrecision, Enum, hidden)]
145         #[diplomat::attr(js, rename = "from_number_with_significant_digits")]
146         #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)]
from_double_with_significant_digits( f: f64, digits: u8, ) -> Result<Box<Decimal>, FixedDecimalLimitError>147         pub fn from_double_with_significant_digits(
148             f: f64,
149             digits: u8,
150         ) -> Result<Box<Decimal>, FixedDecimalLimitError> {
151             let precision = fixed_decimal::DoublePrecision::SignificantDigits(digits);
152             Ok(Box::new(Decimal(fixed_decimal::Decimal::try_from_f64(
153                 f, precision,
154             )?)))
155         }
156 
157         /// Construct an [`Decimal`] from an float, with enough digits to recover
158         /// the original floating point in IEEE 754 without needing trailing zeros
159         #[diplomat::rust_link(fixed_decimal::Decimal::try_from_f64, FnInStruct)]
160         #[diplomat::rust_link(fixed_decimal::FloatPrecision, Enum)]
161         #[diplomat::rust_link(fixed_decimal::DoublePrecision, Enum, hidden)]
162         #[diplomat::attr(js, rename = "from_number_with_round_trip_precision")]
163         #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)]
from_double_with_round_trip_precision( f: f64, ) -> Result<Box<Decimal>, FixedDecimalLimitError>164         pub fn from_double_with_round_trip_precision(
165             f: f64,
166         ) -> Result<Box<Decimal>, FixedDecimalLimitError> {
167             let precision = fixed_decimal::DoublePrecision::RoundTrip;
168             Ok(Box::new(Decimal(fixed_decimal::Decimal::try_from_f64(
169                 f, precision,
170             )?)))
171         }
172 
173         /// Construct an [`Decimal`] from a string.
174         #[diplomat::rust_link(fixed_decimal::Decimal::try_from_str, FnInStruct)]
175         #[diplomat::rust_link(fixed_decimal::Decimal::try_from_utf8, FnInStruct, hidden)]
176         #[diplomat::rust_link(fixed_decimal::Decimal::from_str, FnInStruct, hidden)]
177         #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)]
from_string(v: &DiplomatStr) -> Result<Box<Decimal>, FixedDecimalParseError>178         pub fn from_string(v: &DiplomatStr) -> Result<Box<Decimal>, FixedDecimalParseError> {
179             Ok(Box::new(Decimal(fixed_decimal::Decimal::try_from_utf8(v)?)))
180         }
181 
182         #[diplomat::rust_link(fixed_decimal::UnsignedDecimal::digit_at, FnInStruct)]
digit_at(&self, magnitude: i16) -> u8183         pub fn digit_at(&self, magnitude: i16) -> u8 {
184             self.0.absolute.digit_at(magnitude)
185         }
186 
187         #[diplomat::rust_link(fixed_decimal::UnsignedDecimal::magnitude_range, FnInStruct)]
188         #[diplomat::attr(auto, getter)]
magnitude_start(&self) -> i16189         pub fn magnitude_start(&self) -> i16 {
190             *self.0.absolute.magnitude_range().start()
191         }
192 
193         #[diplomat::rust_link(fixed_decimal::UnsignedDecimal::magnitude_range, FnInStruct)]
194         #[diplomat::attr(auto, getter)]
magnitude_end(&self) -> i16195         pub fn magnitude_end(&self) -> i16 {
196             *self.0.absolute.magnitude_range().end()
197         }
198 
199         #[diplomat::rust_link(fixed_decimal::UnsignedDecimal::nonzero_magnitude_start, FnInStruct)]
200         #[diplomat::attr(auto, getter)]
nonzero_magnitude_start(&self) -> i16201         pub fn nonzero_magnitude_start(&self) -> i16 {
202             self.0.absolute.nonzero_magnitude_start()
203         }
204 
205         #[diplomat::rust_link(fixed_decimal::UnsignedDecimal::nonzero_magnitude_end, FnInStruct)]
206         #[diplomat::attr(auto, getter)]
nonzero_magnitude_end(&self) -> i16207         pub fn nonzero_magnitude_end(&self) -> i16 {
208             self.0.absolute.nonzero_magnitude_end()
209         }
210 
211         #[diplomat::rust_link(fixed_decimal::UnsignedDecimal::is_zero, FnInStruct)]
212         #[diplomat::attr(auto, getter)]
is_zero(&self) -> bool213         pub fn is_zero(&self) -> bool {
214             self.0.absolute.is_zero()
215         }
216 
217         /// Multiply the [`Decimal`] by a given power of ten.
218         #[diplomat::rust_link(fixed_decimal::Decimal::multiply_pow10, FnInStruct)]
219         #[diplomat::rust_link(fixed_decimal::Decimal::multiplied_pow10, FnInStruct, hidden)]
multiply_pow10(&mut self, power: i16)220         pub fn multiply_pow10(&mut self, power: i16) {
221             self.0.multiply_pow10(power)
222         }
223 
224         #[diplomat::rust_link(fixed_decimal::Decimal::sign, FnInStruct)]
225         #[diplomat::attr(auto, getter)]
sign(&self) -> FixedDecimalSign226         pub fn sign(&self) -> FixedDecimalSign {
227             self.0.sign().into()
228         }
229 
230         /// Set the sign of the [`Decimal`].
231         #[diplomat::rust_link(fixed_decimal::Decimal::set_sign, FnInStruct)]
232         #[diplomat::rust_link(fixed_decimal::Decimal::with_sign, FnInStruct, hidden)]
233         #[diplomat::attr(auto, setter = "sign")]
set_sign(&mut self, sign: FixedDecimalSign)234         pub fn set_sign(&mut self, sign: FixedDecimalSign) {
235             self.0.set_sign(sign.into())
236         }
237 
238         #[diplomat::rust_link(fixed_decimal::Decimal::apply_sign_display, FnInStruct)]
239         #[diplomat::rust_link(fixed_decimal::Decimal::with_sign_display, FnInStruct, hidden)]
apply_sign_display(&mut self, sign_display: FixedDecimalSignDisplay)240         pub fn apply_sign_display(&mut self, sign_display: FixedDecimalSignDisplay) {
241             self.0.apply_sign_display(sign_display.into())
242         }
243 
244         #[diplomat::rust_link(fixed_decimal::FixedDecimal::trim_start, FnInStruct)]
245         #[diplomat::rust_link(fixed_decimal::FixedDecimal::trimmed_start, FnInStruct, hidden)]
trim_start(&mut self)246         pub fn trim_start(&mut self) {
247             self.0.absolute.trim_start()
248         }
249 
250         #[diplomat::rust_link(fixed_decimal::FixedDecimal::trim_end, FnInStruct)]
251         #[diplomat::rust_link(fixed_decimal::FixedDecimal::trimmed_end, FnInStruct, hidden)]
trim_end(&mut self)252         pub fn trim_end(&mut self) {
253             self.0.absolute.trim_end()
254         }
255 
256         #[diplomat::rust_link(fixed_decimal::UnsignedDecimal::trim_end_if_integer, FnInStruct)]
257         #[diplomat::rust_link(
258             fixed_decimal::UnsignedDecimal::trimmed_end_if_integer,
259             FnInStruct,
260             hidden
261         )]
trim_end_if_integer(&mut self)262         pub fn trim_end_if_integer(&mut self) {
263             self.0.absolute.trim_end_if_integer()
264         }
265 
266         /// Zero-pad the [`Decimal`] on the left to a particular position
267         #[diplomat::rust_link(fixed_decimal::FixedDecimal::pad_start, FnInStruct)]
268         #[diplomat::rust_link(fixed_decimal::FixedDecimal::padded_start, FnInStruct, hidden)]
pad_start(&mut self, position: i16)269         pub fn pad_start(&mut self, position: i16) {
270             self.0.absolute.pad_start(position)
271         }
272 
273         /// Zero-pad the [`Decimal`] on the right to a particular position
274         #[diplomat::rust_link(fixed_decimal::FixedDecimal::pad_end, FnInStruct)]
275         #[diplomat::rust_link(fixed_decimal::FixedDecimal::padded_end, FnInStruct, hidden)]
pad_end(&mut self, position: i16)276         pub fn pad_end(&mut self, position: i16) {
277             self.0.absolute.pad_end(position)
278         }
279 
280         /// Truncate the [`Decimal`] on the left to a particular position, deleting digits if necessary. This is useful for, e.g. abbreviating years
281         /// ("2022" -> "22")
282         #[diplomat::rust_link(fixed_decimal::FixedDecimal::set_max_position, FnInStruct)]
283         #[diplomat::rust_link(fixed_decimal::FixedDecimal::with_max_position, FnInStruct, hidden)]
set_max_position(&mut self, position: i16)284         pub fn set_max_position(&mut self, position: i16) {
285             self.0.absolute.set_max_position(position)
286         }
287 
288         /// Round the number at a particular digit position.
289         ///
290         /// This uses half to even rounding, which resolves ties by selecting the nearest
291         /// even integer to the original value.
292         #[diplomat::rust_link(fixed_decimal::Decimal::round, FnInStruct)]
293         #[diplomat::rust_link(fixed_decimal::Decimal::rounded, FnInStruct, hidden)]
round(&mut self, position: i16)294         pub fn round(&mut self, position: i16) {
295             self.0.round(position)
296         }
297 
298         #[diplomat::rust_link(fixed_decimal::Decimal::ceil, FnInStruct)]
299         #[diplomat::rust_link(fixed_decimal::Decimal::ceiled, FnInStruct, hidden)]
ceil(&mut self, position: i16)300         pub fn ceil(&mut self, position: i16) {
301             self.0.ceil(position)
302         }
303 
304         #[diplomat::rust_link(fixed_decimal::Decimal::expand, FnInStruct)]
305         #[diplomat::rust_link(fixed_decimal::Decimal::expanded, FnInStruct, hidden)]
expand(&mut self, position: i16)306         pub fn expand(&mut self, position: i16) {
307             self.0.expand(position)
308         }
309 
310         #[diplomat::rust_link(fixed_decimal::Decimal::floor, FnInStruct)]
311         #[diplomat::rust_link(fixed_decimal::Decimal::floored, FnInStruct, hidden)]
floor(&mut self, position: i16)312         pub fn floor(&mut self, position: i16) {
313             self.0.floor(position)
314         }
315 
316         #[diplomat::rust_link(fixed_decimal::Decimal::trunc, FnInStruct)]
317         #[diplomat::rust_link(fixed_decimal::Decimal::trunced, FnInStruct, hidden)]
trunc(&mut self, position: i16)318         pub fn trunc(&mut self, position: i16) {
319             self.0.trunc(position)
320         }
321 
322         #[diplomat::rust_link(fixed_decimal::Decimal::round_with_mode, FnInStruct)]
323         #[diplomat::rust_link(fixed_decimal::Decimal::rounded_with_mode, FnInStruct, hidden)]
round_with_mode(&mut self, position: i16, mode: FixedDecimalSignedRoundingMode)324         pub fn round_with_mode(&mut self, position: i16, mode: FixedDecimalSignedRoundingMode) {
325             self.0.round_with_mode(position, mode.into())
326         }
327 
328         #[diplomat::rust_link(
329             fixed_decimal::FixedDecimal::round_with_mode_and_increment,
330             FnInStruct
331         )]
332         #[diplomat::rust_link(
333             fixed_decimal::FixedDecimal::rounded_with_mode_and_increment,
334             FnInStruct,
335             hidden
336         )]
round_with_mode_and_increment( &mut self, position: i16, mode: FixedDecimalSignedRoundingMode, increment: FixedDecimalRoundingIncrement, )337         pub fn round_with_mode_and_increment(
338             &mut self,
339             position: i16,
340             mode: FixedDecimalSignedRoundingMode,
341             increment: FixedDecimalRoundingIncrement,
342         ) {
343             self.0
344                 .round_with_mode_and_increment(position, mode.into(), increment.into())
345         }
346 
347         /// Concatenates `other` to the end of `self`.
348         ///
349         /// If successful, `other` will be set to 0 and a successful status is returned.
350         ///
351         /// If not successful, `other` will be unchanged and an error is returned.
352         #[diplomat::rust_link(fixed_decimal::FixedDecimal::concatenate_end, FnInStruct)]
353         #[diplomat::rust_link(fixed_decimal::FixedDecimal::concatenated_end, FnInStruct, hidden)]
concatenate_end(&mut self, other: &mut Decimal) -> Result<(), ()>354         pub fn concatenate_end(&mut self, other: &mut Decimal) -> Result<(), ()> {
355             let x = core::mem::take(&mut other.0);
356             self.0.absolute.concatenate_end(x.absolute).map_err(|y| {
357                 other.0.absolute = y;
358             })
359         }
360 
361         /// Format the [`Decimal`] as a string.
362         #[diplomat::rust_link(fixed_decimal::FixedDecimal::write_to, FnInStruct)]
363         #[diplomat::rust_link(fixed_decimal::FixedDecimal::to_string, FnInStruct, hidden)]
364         #[diplomat::attr(auto, stringifier)]
to_string(&self, to: &mut diplomat_runtime::DiplomatWrite)365         pub fn to_string(&self, to: &mut diplomat_runtime::DiplomatWrite) {
366             let _ = self.0.write_to(to);
367         }
368     }
369 }
370 
371 impl From<FixedDecimalSignedRoundingMode> for fixed_decimal::SignedRoundingMode {
from(mode: FixedDecimalSignedRoundingMode) -> Self372     fn from(mode: FixedDecimalSignedRoundingMode) -> Self {
373         match mode {
374             FixedDecimalSignedRoundingMode::Expand => fixed_decimal::SignedRoundingMode::Unsigned(
375                 fixed_decimal::UnsignedRoundingMode::Expand,
376             ),
377             FixedDecimalSignedRoundingMode::Trunc => fixed_decimal::SignedRoundingMode::Unsigned(
378                 fixed_decimal::UnsignedRoundingMode::Trunc,
379             ),
380             FixedDecimalSignedRoundingMode::HalfExpand => {
381                 fixed_decimal::SignedRoundingMode::Unsigned(
382                     fixed_decimal::UnsignedRoundingMode::HalfExpand,
383                 )
384             }
385             FixedDecimalSignedRoundingMode::HalfTrunc => {
386                 fixed_decimal::SignedRoundingMode::Unsigned(
387                     fixed_decimal::UnsignedRoundingMode::HalfTrunc,
388                 )
389             }
390             FixedDecimalSignedRoundingMode::HalfEven => {
391                 fixed_decimal::SignedRoundingMode::Unsigned(
392                     fixed_decimal::UnsignedRoundingMode::HalfEven,
393                 )
394             }
395             FixedDecimalSignedRoundingMode::Ceil => fixed_decimal::SignedRoundingMode::Ceil,
396             FixedDecimalSignedRoundingMode::Floor => fixed_decimal::SignedRoundingMode::Floor,
397             FixedDecimalSignedRoundingMode::HalfCeil => fixed_decimal::SignedRoundingMode::HalfCeil,
398             FixedDecimalSignedRoundingMode::HalfFloor => {
399                 fixed_decimal::SignedRoundingMode::HalfFloor
400             }
401         }
402     }
403 }
404