1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
// ---------------------------------------------------------------------------
// Copyright: (c) 2021 ff. Michael Amrhein (michael@adrhinum.de)
// License: This program is part of a larger application. For license
// details please read the file LICENSE.TXT provided together
// with the application.
// ---------------------------------------------------------------------------
// $Source: fpdec-macros/src/lib.rs $
// $Revision: 2022-08-17T18:32:32+02:00 $
#![doc = include_str ! ("../README.md")]
use ::proc_macro::TokenStream;
use ::quote::quote;
use fpdec_core::{str_to_dec, ParseDecimalError, MAX_N_FRAC_DIGITS};
/// Macro used to convert a number literal into a `Decimal`.
///
/// The literal must be in the form
/// \[+|-]\<int\>\[.\<frac\>]\[<e|E>\[+|-]\<exp\>] or
/// \[+|-].\<frac\>\[<e|E>\[+|-]\<exp\>].
///
/// The resulting number of fractional digits is determined by the number of
/// digits in the fractional part of the literal minus the value of the signed
/// exponent.
///
/// The resulting value must not exceed the limits given by the internal
/// representaion of `Decimal`:
/// * The coefficient must fit into an `i128`.
/// * The number of fractional digits must not exceed the constant
/// `MAX_N_FRAC_DIGITS`.
///
/// # Panics
///
/// The macro panics if the conditions listed above are not met!
///
/// # Examples
///
/// ```ignore
/// let d = Dec!(17.5);
/// assert_eq!(d.to_string(), "17.5");
///
/// let d = Dec!(-170.5e-2);
/// assert_eq!(d.to_string(), "-1.705");
/// ```
#[allow(non_snake_case)]
#[proc_macro]
pub fn Dec(input: TokenStream) -> TokenStream {
let mut src = input.to_string();
// "-" and "+" get separated by a blank => remove it
if src.starts_with("- ") || src.starts_with("+ ") {
src.remove(1);
}
match str_to_dec(&src) {
Err(e) => panic!("{}", e),
Ok((mut coeff, mut exponent)) => {
if -exponent > (MAX_N_FRAC_DIGITS as isize) {
panic!("{}", ParseDecimalError::FracDigitLimitExceeded)
}
if exponent > 38 {
// 10 ^ 39 > int128::MAX
panic!("{}", ParseDecimalError::InternalOverflow);
}
if exponent > 0 {
match coeff.checked_mul(10i128.pow(exponent as u32)) {
None => panic!("{}", ParseDecimalError::InternalOverflow),
Some(val) => {
coeff = val;
}
}
exponent = 0;
}
let n_frac_digits = -exponent as u8;
quote!(
Decimal::new_raw(#coeff, #n_frac_digits)
)
.into()
}
}
}