use std::cmp::Ordering;
use std::convert::{TryFrom, TryInto};
use std::ffi::{CStr, CString};
use std::fmt::{self, Display, LowerExp};
use std::io::Write;
use std::iter::{Product, Sum};
use std::marker::PhantomData;
use std::mem::MaybeUninit;
use std::ops::{
Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
};
use std::str::FromStr;
use libc::c_char;
#[cfg(feature = "num-traits")]
use num_traits::{MulAdd, MulAddAssign, Pow, Zero};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::context::{Class, Context};
use crate::decimal128::Decimal128;
use crate::decimal32::Decimal32;
use crate::decimal64::Decimal64;
use crate::error::{
FromBcdError, InvalidCoefficientError, InvalidExponentError, InvalidPrecisionError,
ParseDecimalError, TryFromDecimalError, TryIntoDecimalError,
};
fn validate_n(n: usize) {
if n < 12 || n > 999_999_999 {
panic!("Decimal<N>:: N is not in the range [12, 999999999]");
}
}
#[repr(C)]
#[derive(Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Decimal<const N: usize> {
pub(crate) digits: u32,
pub(crate) exponent: i32,
pub(crate) bits: u8,
#[cfg_attr(feature = "serde", serde(with = "lsu_serde"))]
pub(crate) lsu: [u16; N],
}
#[cfg(feature = "serde")]
pub mod serde_decimal_from_non_float_primitives {
use std::convert::TryFrom;
use std::fmt;
use std::str::FromStr;
use serde::de::{self, MapAccess, SeqAccess, Visitor};
use serde::{Deserialize, Deserializer, Serialize};
use crate::Decimal;
pub fn serialize<S, const N: usize>(d: &Decimal<N>, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
Decimal<N>: Serialize,
{
Decimal::<N>::serialize(d, serializer)
}
pub fn deserialize<'de, D, const N: usize>(deserializer: D) -> Result<Decimal<N>, D::Error>
where
D: serde::Deserializer<'de>,
{
enum Field {
Digits,
Exponent,
Bits,
Lsu,
}
impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
where
D: Deserializer<'de>,
{
struct FieldVisitor;
impl<'de> Visitor<'de> for FieldVisitor {
type Value = Field;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("`digits`, `exponent`, `bits`, or `lsu`")
}
fn visit_str<E>(self, value: &str) -> Result<Field, E>
where
E: de::Error,
{
match value {
"digits" => Ok(Field::Digits),
"exponent" => Ok(Field::Exponent),
"bits" => Ok(Field::Bits),
"lsu" => Ok(Field::Lsu),
_ => Err(de::Error::unknown_field(value, FIELDS)),
}
}
}
deserializer.deserialize_identifier(FieldVisitor)
}
}
struct DecimalVisitor<const N: usize>;
macro_rules! deser_try_from {
($($t:ty),*) => {
$(
paste::paste! {
fn [< visit_ $t >]<E>(self, value: $t) -> Result<Self::Value, E>
where
E: de::Error,
{
Decimal::try_from(value).map_err(serde::de::Error::custom)
}
}
)*
};
}
impl<'de, const N: usize> Visitor<'de> for DecimalVisitor<N> {
type Value = Decimal<N>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct Decimal or compatible primitive")
}
deser_try_from!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Decimal::from_str(v).map_err(serde::de::Error::custom)
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: de::Error,
{
Decimal::from_str(&v).map_err(serde::de::Error::custom)
}
fn visit_seq<V>(self, mut seq: V) -> Result<Decimal<N>, V::Error>
where
V: SeqAccess<'de>,
{
let digits = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
let exponent = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
let bits = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(2, &self))?;
let lsu: Vec<u16> = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(3, &self))?;
let lsu = super::lsu_serde::check_deserialized_vec(lsu)?;
Ok(Decimal {
digits,
exponent,
bits,
lsu,
})
}
fn visit_map<V>(self, mut map: V) -> Result<Decimal<N>, V::Error>
where
V: MapAccess<'de>,
{
let mut digits = None;
let mut exponent = None;
let mut bits = None;
let mut lsu = None;
while let Some(key) = map.next_key()? {
match key {
Field::Digits => {
if digits.is_some() {
return Err(de::Error::duplicate_field("digits"));
}
digits = Some(map.next_value()?);
}
Field::Exponent => {
if exponent.is_some() {
return Err(de::Error::duplicate_field("exponent"));
}
exponent = Some(map.next_value()?);
}
Field::Bits => {
if bits.is_some() {
return Err(de::Error::duplicate_field("bits"));
}
bits = Some(map.next_value()?);
}
Field::Lsu => {
if lsu.is_some() {
return Err(de::Error::duplicate_field("lsu"));
}
let lsu_deserialized: Vec<u16> = map.next_value()?;
let lsu_deserialized =
super::lsu_serde::check_deserialized_vec(lsu_deserialized)?;
lsu = Some(lsu_deserialized);
}
}
}
let digits = digits.ok_or_else(|| de::Error::missing_field("digits"))?;
let exponent = exponent.ok_or_else(|| de::Error::missing_field("exponent"))?;
let bits = bits.ok_or_else(|| de::Error::missing_field("bits"))?;
let lsu = lsu.ok_or_else(|| de::Error::missing_field("lsu"))?;
Ok(Decimal {
digits,
exponent,
bits,
lsu,
})
}
}
const FIELDS: &'static [&'static str] = &["digits", "exponent", "bits", "lsu"];
deserializer.deserialize_any(DecimalVisitor)
}
}
#[cfg(feature = "serde")]
mod lsu_serde {
use std::convert::TryInto;
use serde::de::{Error, Unexpected};
use serde::ser::SerializeSeq;
use serde::Deserialize;
pub fn serialize<S, const N: usize>(v: &[u16; N], serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut seq = serializer.serialize_seq(Some(N))?;
for e in v.iter() {
seq.serialize_element(e)?;
}
seq.end()
}
pub fn deserialize<'de, D, const N: usize>(deserializer: D) -> Result<[u16; N], D::Error>
where
D: serde::Deserializer<'de>,
{
let lsu = Vec::<u16>::deserialize(deserializer)?;
check_deserialized_vec(lsu)
}
pub fn check_deserialized_vec<const N: usize, E>(lsu: Vec<u16>) -> Result<[u16; N], E>
where
E: Error,
{
lsu.try_into().map_err(|e: Vec<u16>| {
Error::invalid_value(
Unexpected::Other(&format!("&[u16] of length {}", e.len())),
&format!("&[u16] of length {}", N).as_str(),
)
})
}
}
impl<const N: usize> Decimal<N> {
pub(crate) fn as_ptr(&self) -> *const decnumber_sys::decNumber {
self as *const Decimal<N> as *const decnumber_sys::decNumber
}
pub(crate) fn as_mut_ptr(&mut self) -> *mut decnumber_sys::decNumber {
self as *mut Decimal<N> as *mut decnumber_sys::decNumber
}
pub fn zero() -> Decimal<N> {
Decimal::default()
}
pub fn infinity() -> Decimal<N> {
let mut d = Decimal::default();
d.bits = decnumber_sys::DECINF;
d
}
pub fn nan() -> Decimal<N> {
let mut d = Decimal::default();
d.bits = decnumber_sys::DECNAN;
d
}
fn two_pow_32() -> Decimal<N> {
let mut d = Decimal::default();
d.digits = 10;
d.lsu[0..4].copy_from_slice(&[296, 967, 294, 4]);
d
}
pub fn digits(&self) -> u32 {
self.digits
}
pub fn coefficient_digits(&self) -> Vec<u8> {
let mut buf = vec![0; usize::try_from(self.digits()).unwrap()];
unsafe {
decnumber_sys::decNumberGetBCD(self.as_ptr(), buf.as_mut_ptr() as *mut u8);
};
buf
}
pub fn coefficient_units(&self) -> &[u16] {
let units_len = Self::digits_to_lsu_elements_len(self.digits);
&self.lsu[0..units_len]
}
pub fn coefficient<T>(&mut self) -> Result<T, InvalidCoefficientError>
where
T: TryFrom<Decimal<N>>,
{
let cur_exp = self.exponent();
self.set_exponent(0);
let coefficient = <T>::try_from(*self);
self.set_exponent(cur_exp);
match coefficient {
Ok(d) => Ok(d),
Err(_) => Err(InvalidCoefficientError),
}
}
pub fn digits_to_lsu_elements_len(digits: u32) -> usize {
(usize::try_from(digits).unwrap() + decnumber_sys::DECDPUN - 1) / decnumber_sys::DECDPUN
}
pub fn exponent(&self) -> i32 {
self.exponent
}
pub fn set_exponent(&mut self, exponent: i32) {
self.exponent = exponent;
}
pub fn is_finite(&self) -> bool {
(self.bits & decnumber_sys::DECSPECIAL) == 0
}
pub fn is_infinite(&self) -> bool {
(self.bits & decnumber_sys::DECINF) != 0
}
pub fn is_nan(&self) -> bool {
(self.bits & (decnumber_sys::DECNAN | decnumber_sys::DECSNAN)) != 0
}
pub fn is_negative(&self) -> bool {
(self.bits & decnumber_sys::DECNEG) != 0
}
pub fn is_quiet_nan(&self) -> bool {
(self.bits & decnumber_sys::DECNAN) != 0
}
pub fn is_signaling_nan(&self) -> bool {
(self.bits & decnumber_sys::DECSNAN) != 0
}
pub fn is_special(&self) -> bool {
(self.bits & decnumber_sys::DECSPECIAL) != 0
}
pub fn is_zero(&self) -> bool {
self.is_finite() && self.lsu[0] == 0 && self.digits == 1
}
pub fn quantum_matches(&self, rhs: &Decimal<N>) -> bool {
let mut d = Decimal::<N>::zero();
unsafe {
decnumber_sys::decNumberSameQuantum(
d.as_mut_ptr() as *mut decnumber_sys::decNumber,
self.as_ptr(),
rhs.as_ptr(),
);
};
if d.is_zero() {
false
} else {
debug_assert!(!d.is_special());
true
}
}
pub fn to_decimal32(&self) -> Decimal32 {
Context::<Decimal32>::default().from_decimal(self)
}
pub fn to_decimal64(&self) -> Decimal64 {
Context::<Decimal64>::default().from_decimal(self)
}
pub fn to_decimal128(&self) -> Decimal128 {
Context::<Decimal128>::default().from_decimal(self)
}
pub fn to_raw_parts(&self) -> (u32, i32, u8, [u16; N]) {
(self.digits, self.exponent, self.bits, self.lsu)
}
pub fn from_raw_parts(digits: u32, exponent: i32, bits: u8, lsu: [u16; N]) -> Self {
Decimal {
digits,
exponent,
bits,
lsu,
}
}
pub fn to_packed_bcd(&mut self) -> Option<(Vec<u8>, i32)> {
if self.is_special() {
return None;
}
let mut len = (usize::try_from(self.digits).unwrap() + 1) / 2;
if self.digits % 2 == 0 {
len += 1;
}
let mut bcd = vec![0; len];
let mut scale: i32 = 0;
let ret = unsafe {
decnumber_sys::decPackedFromNumber(
bcd.as_mut_ptr() as *mut u8,
len.try_into().unwrap(),
&mut scale as *mut i32,
self.as_mut_ptr() as *mut decnumber_sys::decNumber,
)
};
assert!(!ret.is_null());
Some((bcd, scale))
}
pub fn from_packed_bcd(bcd: &[u8], scale: i32) -> Result<Decimal<N>, FromBcdError> {
let mut d = Decimal::default();
let ret = unsafe {
decnumber_sys::decPackedToNumber(
bcd.as_ptr() as *const u8,
bcd.len().try_into().unwrap(),
&scale as *const i32,
d.as_mut_ptr() as *mut decnumber_sys::decNumber,
)
};
if ret.is_null() {
Err(FromBcdError)
} else {
Ok(d)
}
}
pub fn to_standard_notation_string(&self) -> String {
if !self.is_finite() {
return self.to_string();
}
let digits = self.coefficient_digits();
let digits = {
let i = digits
.iter()
.position(|d| *d != 0)
.unwrap_or(digits.len() - 1);
&digits[i..]
};
let ndigits = digits.len() as i32;
let e = self.exponent();
let mut out = String::with_capacity(digits.len() + 3);
if self.is_negative() {
out.push('-');
}
if e >= 0 {
for d in digits {
out.push(char::from(b'0' + *d));
}
if !self.is_zero() {
for _ in 0..e {
out.push('0');
}
}
} else if ndigits > -e {
let e = (ndigits + e) as usize;
for d in &digits[..e] {
out.push(char::from(b'0' + *d));
}
out.push('.');
for d in &digits[e..] {
out.push(char::from(b'0' + *d));
}
} else {
out.push_str("0.");
for _ in 0..(-e - ndigits) {
out.push('0');
}
for d in digits {
out.push(char::from(b'0' + *d));
}
}
out
}
pub fn trim(&mut self) {
unsafe {
decnumber_sys::decNumberTrim(self.as_mut_ptr());
}
}
}
impl<const N: usize> Default for Decimal<N> {
fn default() -> Decimal<N> {
validate_n(N);
Decimal::<N> {
digits: 1,
bits: 0,
exponent: 0,
lsu: [0; N],
}
}
}
impl<const N: usize> PartialOrd for Decimal<N> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Context::<Decimal<N>>::default().partial_cmp(self, other)
}
}
impl<const N: usize> PartialEq for Decimal<N> {
fn eq(&self, other: &Self) -> bool {
self.partial_cmp(other) == Some(Ordering::Equal)
}
}
impl<const N: usize> Neg for Decimal<N> {
type Output = Decimal<N>;
fn neg(self) -> Decimal<N> {
let mut n = self.clone();
let n_ptr = n.as_mut_ptr();
unsafe {
decnumber_sys::decNumberCopyNegate(n_ptr, n_ptr);
}
n
}
}
impl<const M: usize, const N: usize> Add<Decimal<M>> for Decimal<N> {
type Output = Self;
fn add(self, rhs: Decimal<M>) -> Self {
let mut lhs = self.clone();
Context::<Self>::default().add(&mut lhs, &rhs);
lhs
}
}
impl<const M: usize, const N: usize> AddAssign<Decimal<M>> for Decimal<N> {
fn add_assign(&mut self, rhs: Decimal<M>) {
Context::<Self>::default().add(self, &rhs);
}
}
impl<const M: usize, const N: usize> Div<Decimal<M>> for Decimal<N> {
type Output = Self;
fn div(self, rhs: Decimal<M>) -> Self {
let mut lhs = self.clone();
Context::<Self>::default().div(&mut lhs, &rhs);
lhs
}
}
impl<const M: usize, const N: usize> DivAssign<Decimal<M>> for Decimal<N> {
fn div_assign(&mut self, rhs: Decimal<M>) {
Context::<Self>::default().div(self, &rhs);
}
}
impl<const M: usize, const N: usize> Mul<Decimal<M>> for Decimal<N> {
type Output = Self;
fn mul(self, rhs: Decimal<M>) -> Self {
let mut lhs = self.clone();
Context::<Self>::default().mul(&mut lhs, &rhs);
lhs
}
}
impl<const M: usize, const N: usize> MulAssign<Decimal<M>> for Decimal<N> {
fn mul_assign(&mut self, rhs: Decimal<M>) {
Context::<Self>::default().mul(self, &rhs);
}
}
impl<const M: usize, const N: usize> Rem<Decimal<M>> for Decimal<N> {
type Output = Self;
fn rem(self, rhs: Decimal<M>) -> Self {
let mut lhs = self.clone();
Context::<Self>::default().rem(&mut lhs, &rhs);
lhs
}
}
impl<const M: usize, const N: usize> RemAssign<Decimal<M>> for Decimal<N> {
fn rem_assign(&mut self, rhs: Decimal<M>) {
Context::<Self>::default().rem(self, &rhs);
}
}
impl<const M: usize, const N: usize> Sub<Decimal<M>> for Decimal<N> {
type Output = Self;
fn sub(self, rhs: Decimal<M>) -> Self {
let mut lhs = self.clone();
Context::<Self>::default().sub(&mut lhs, &rhs);
lhs
}
}
impl<const M: usize, const N: usize> SubAssign<Decimal<M>> for Decimal<N> {
fn sub_assign(&mut self, rhs: Decimal<M>) {
Context::<Self>::default().sub(self, &rhs);
}
}
impl<const M: usize, const N: usize> Sum<Decimal<M>> for Decimal<N> {
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = Decimal<M>>,
{
iter.map(|v| v).collect::<Vec<_>>().iter().sum()
}
}
impl<'a, const M: usize, const N: usize> Sum<&'a Decimal<M>> for Decimal<N> {
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = &'a Decimal<M>>,
{
let mut cx = Context::<Self>::default();
cx.sum(iter)
}
}
impl<const M: usize, const N: usize> Product<Decimal<M>> for Decimal<N> {
fn product<I>(iter: I) -> Self
where
I: Iterator<Item = Decimal<M>>,
{
iter.map(|v| v).collect::<Vec<_>>().iter().product()
}
}
impl<'a, const M: usize, const N: usize> Product<&'a Decimal<M>> for Decimal<N> {
fn product<I>(iter: I) -> Self
where
I: Iterator<Item = &'a Decimal<M>>,
{
let mut cx = Context::<Self>::default();
cx.product(iter)
}
}
impl<const N: usize> fmt::Debug for Decimal<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl<const N: usize> fmt::Display for Decimal<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut buf = Vec::with_capacity(self.digits as usize + 14);
let c_str = unsafe {
if f.alternate() {
decnumber_sys::decNumberToEngString(self.as_ptr(), buf.as_mut_ptr() as *mut c_char);
} else {
decnumber_sys::decNumberToString(self.as_ptr(), buf.as_mut_ptr() as *mut c_char);
}
CStr::from_ptr(buf.as_ptr() as *const c_char)
};
f.write_str(
c_str
.to_str()
.expect("decNumberToString yields valid UTF-8"),
)
}
}
impl<const N: usize> FromStr for Decimal<N> {
type Err = ParseDecimalError;
fn from_str(s: &str) -> Result<Decimal<N>, ParseDecimalError> {
Context::<Decimal<N>>::default().parse(s)
}
}
macro_rules! __decnum_tryinto_primitive {
($p:ty, $cx:expr, $max_digits:literal, $d:expr, $allow_neg:expr) => {{
$cx.rescale(&mut $d, &Decimal::<N>::zero());
let inexact = $cx.status().inexact();
let mut fail = || -> TryFromDecimalError {
let mut s = $cx.status();
s.set_invalid_operation();
$cx.set_status(s);
TryFromDecimalError
};
if $d.is_special()
|| $d.digits() > $max_digits
|| (!$allow_neg && $d.is_negative())
|| inexact
{
return Err(fail());
}
let accum_op = if $d.is_negative() {
<$p>::checked_sub
} else {
<$p>::checked_add
};
let ten: $p = 10;
let mut ten_pow = 0;
let mut accum = 0;
|| -> Option<$p> {
for v in $d.coefficient_units() {
let d = <$p>::from(*v).checked_mul(ten.pow(ten_pow))?;
accum = accum_op(accum, d)?;
ten_pow += decnumber_sys::DECDPUN as u32;
}
Some(accum)
}()
.ok_or_else(|| fail())
}};
}
macro_rules! decnum_tryinto_primitive_int {
($p:ty, $cx:expr, $max_digits:literal, $d:expr) => {{
__decnum_tryinto_primitive!($p, $cx, $max_digits, $d, true)
}};
}
macro_rules! decnum_tryinto_primitive_uint {
($p:ty, $cx:expr, $max_digits:literal, $d:expr) => {{
__decnum_tryinto_primitive!($p, $cx, $max_digits, $d, false)
}};
}
impl<const N: usize> TryFrom<Decimal<N>> for i8 {
type Error = TryFromDecimalError;
fn try_from(n: Decimal<N>) -> Result<i8, Self::Error> {
let mut cx = Context::<Decimal<N>>::default();
cx.try_into_i8(n)
}
}
impl<const N: usize> TryFrom<Decimal<N>> for u8 {
type Error = TryFromDecimalError;
fn try_from(n: Decimal<N>) -> Result<u8, Self::Error> {
let mut cx = Context::<Decimal<N>>::default();
cx.try_into_u8(n)
}
}
impl<const N: usize> TryFrom<Decimal<N>> for i16 {
type Error = TryFromDecimalError;
fn try_from(n: Decimal<N>) -> Result<i16, Self::Error> {
let mut cx = Context::<Decimal<N>>::default();
cx.try_into_i16(n)
}
}
impl<const N: usize> TryFrom<Decimal<N>> for u16 {
type Error = TryFromDecimalError;
fn try_from(n: Decimal<N>) -> Result<u16, Self::Error> {
let mut cx = Context::<Decimal<N>>::default();
cx.try_into_u16(n)
}
}
impl<const N: usize> TryFrom<Decimal<N>> for i32 {
type Error = TryFromDecimalError;
fn try_from(n: Decimal<N>) -> Result<i32, Self::Error> {
let mut cx = Context::<Decimal<N>>::default();
cx.try_into_i32(n)
}
}
impl<const N: usize> TryFrom<Decimal<N>> for u32 {
type Error = TryFromDecimalError;
fn try_from(n: Decimal<N>) -> Result<u32, Self::Error> {
let mut cx = Context::<Decimal<N>>::default();
cx.try_into_u32(n)
}
}
impl<const N: usize> TryFrom<Decimal<N>> for i64 {
type Error = TryFromDecimalError;
fn try_from(n: Decimal<N>) -> Result<i64, Self::Error> {
let mut cx = Context::<Decimal<N>>::default();
cx.try_into_i64(n)
}
}
impl<const N: usize> TryFrom<Decimal<N>> for u64 {
type Error = TryFromDecimalError;
fn try_from(n: Decimal<N>) -> Result<u64, Self::Error> {
let mut cx = Context::<Decimal<N>>::default();
cx.try_into_u64(n)
}
}
impl<const N: usize> TryFrom<Decimal<N>> for i128 {
type Error = TryFromDecimalError;
fn try_from(n: Decimal<N>) -> Result<i128, Self::Error> {
let mut cx = Context::<Decimal<N>>::default();
cx.try_into_i128(n)
}
}
impl<const N: usize> TryFrom<Decimal<N>> for u128 {
type Error = TryFromDecimalError;
fn try_from(n: Decimal<N>) -> Result<u128, Self::Error> {
let mut cx = Context::<Decimal<N>>::default();
cx.try_into_u128(n)
}
}
impl<const N: usize> TryFrom<Decimal<N>> for usize {
type Error = TryFromDecimalError;
fn try_from(n: Decimal<N>) -> Result<usize, Self::Error> {
let mut cx = Context::<Decimal<N>>::default();
cx.try_into_usize(n)
}
}
impl<const N: usize> TryFrom<Decimal<N>> for isize {
type Error = TryFromDecimalError;
fn try_from(n: Decimal<N>) -> Result<isize, Self::Error> {
let mut cx = Context::<Decimal<N>>::default();
cx.try_into_isize(n)
}
}
macro_rules! decnum_tryinto_primitive_float {
($p:ty, $cx:expr, $d:expr) => {{
if $d.is_infinite() {
return Ok(if $d.is_negative() {
<$p>::NEG_INFINITY
} else {
<$p>::INFINITY
});
}
if $d.is_nan() {
return Ok(<$p>::NAN);
}
const TEN: $p = 10.0;
const DECDPUN_F: $p = decnumber_sys::DECDPUN as $p;
let mut e = $d.exponent() as $p;
let mut f: $p = 0.0;
for u in $d.coefficient_units() {
f += <$p>::from(*u) * TEN.powf(e);
e += DECDPUN_F;
}
if $d.is_negative() {
f = -f;
}
if f.is_infinite() || f.is_nan() || (!$d.is_zero() && f == 0.0) {
let mut s = $cx.status();
s.set_invalid_operation();
$cx.set_status(s);
Err(TryFromDecimalError)
} else {
Ok(f)
}
}};
}
impl<const N: usize> TryFrom<Decimal<N>> for f32 {
type Error = TryFromDecimalError;
fn try_from(n: Decimal<N>) -> Result<f32, Self::Error> {
let mut cx = Context::<Decimal<N>>::default();
cx.try_into_f32(n)
}
}
impl<const N: usize> TryFrom<Decimal<N>> for f64 {
type Error = TryFromDecimalError;
fn try_from(n: Decimal<N>) -> Result<f64, Self::Error> {
let mut cx = Context::<Decimal<N>>::default();
cx.try_into_f64(n)
}
}
impl<const N: usize> From<f32> for Decimal<N> {
fn from(n: f32) -> Decimal<N> {
let mut cx = Context::<Decimal<N>>::default();
cx.from_f32(n)
}
}
impl<const N: usize> From<f64> for Decimal<N> {
fn from(n: f64) -> Decimal<N> {
let mut cx = Context::<Decimal<N>>::default();
cx.from_f64(n)
}
}
impl<const N: usize> From<i8> for Decimal<N> {
fn from(n: i8) -> Decimal<N> {
Decimal::<N>::from(i32::from(n))
}
}
impl<const N: usize> From<u8> for Decimal<N> {
fn from(n: u8) -> Decimal<N> {
Decimal::<N>::from(u32::from(n))
}
}
impl<const N: usize> From<i16> for Decimal<N> {
fn from(n: i16) -> Decimal<N> {
Decimal::<N>::from(i32::from(n))
}
}
impl<const N: usize> From<u16> for Decimal<N> {
fn from(n: u16) -> Decimal<N> {
Decimal::<N>::from(u32::from(n))
}
}
impl<const N: usize> From<i32> for Decimal<N> {
fn from(n: i32) -> Decimal<N> {
let mut d = Decimal::default();
unsafe {
decnumber_sys::decNumberFromInt32(d.as_mut_ptr() as *mut decnumber_sys::decNumber, n);
}
d
}
}
impl<const N: usize> From<u32> for Decimal<N> {
fn from(n: u32) -> Decimal<N> {
let mut d = Decimal::default();
unsafe {
decnumber_sys::decNumberFromUInt32(d.as_mut_ptr() as *mut decnumber_sys::decNumber, n);
}
d
}
}
impl<const N: usize> From<i64> for Decimal<N> {
fn from(n: i64) -> Decimal<N> {
let mut cx = Context::<Decimal<N>>::default();
cx.from_i64(n)
}
}
impl<const N: usize> From<u64> for Decimal<N> {
fn from(n: u64) -> Decimal<N> {
let mut cx = Context::<Decimal<N>>::default();
cx.from_u64(n)
}
}
impl<const N: usize> TryFrom<i128> for Decimal<N> {
type Error = TryIntoDecimalError;
fn try_from(n: i128) -> Result<Decimal<N>, Self::Error> {
let mut cx = Context::<Decimal<N>>::default();
let d = cx.from_i128(n);
return if cx.status().any() {
Err(TryIntoDecimalError)
} else {
Ok(d)
};
}
}
impl<const N: usize> TryFrom<u128> for Decimal<N> {
type Error = TryIntoDecimalError;
fn try_from(n: u128) -> Result<Decimal<N>, Self::Error> {
let mut cx = Context::<Decimal<N>>::default();
let d = cx.from_u128(n);
return if cx.status().any() {
Err(TryIntoDecimalError)
} else {
Ok(d)
};
}
}
#[cfg(target_pointer_width = "32")]
impl<const N: usize> From<usize> for Decimal<N> {
fn from(n: usize) -> Decimal<N> {
Decimal::<N>::from(n as u32)
}
}
#[cfg(target_pointer_width = "32")]
impl<const N: usize> From<isize> for Decimal<N> {
fn from(n: isize) -> Decimal<N> {
Decimal::<N>::from(n as i32)
}
}
#[cfg(target_pointer_width = "64")]
impl<const N: usize> From<usize> for Decimal<N> {
fn from(n: usize) -> Decimal<N> {
Decimal::<N>::from(n as u64)
}
}
#[cfg(target_pointer_width = "64")]
impl<const N: usize> From<isize> for Decimal<N> {
fn from(n: isize) -> Decimal<N> {
Decimal::<N>::from(n as i64)
}
}
impl<const N: usize> From<Decimal32> for Decimal<N> {
fn from(n: Decimal32) -> Decimal<N> {
let mut d = Decimal::default();
unsafe {
decnumber_sys::decimal32ToNumber(
&n.inner,
d.as_mut_ptr() as *mut decnumber_sys::decNumber,
);
}
d
}
}
impl<const N: usize> From<Decimal64> for Decimal<N> {
fn from(n: Decimal64) -> Decimal<N> {
let mut d = Decimal::default();
unsafe {
decnumber_sys::decimal64ToNumber(
&n.inner,
d.as_mut_ptr() as *mut decnumber_sys::decNumber,
);
}
d
}
}
impl<const N: usize> From<Decimal128> for Decimal<N> {
fn from(n: Decimal128) -> Decimal<N> {
let mut d = Decimal::default();
unsafe {
decnumber_sys::decimal128ToNumber(
&n.inner,
d.as_mut_ptr() as *mut decnumber_sys::decNumber,
);
}
d
}
}
impl<const N: usize> Default for Context<Decimal<N>> {
fn default() -> Context<Decimal<N>> {
let mut ctx = MaybeUninit::<decnumber_sys::decContext>::uninit();
let mut ctx = unsafe {
decnumber_sys::decContextDefault(ctx.as_mut_ptr(), decnumber_sys::DEC_INIT_BASE);
ctx.assume_init()
};
ctx.traps = 0;
ctx.digits = i32::try_from(N * decnumber_sys::DECDPUN)
.expect("decimal digit count does not fit into i32");
Context {
inner: ctx,
_phantom: PhantomData,
}
}
}
impl<const N: usize> Context<Decimal<N>> {
pub fn precision(&self) -> usize {
usize::try_from(self.inner.digits).expect("context digit count does not fit into usize")
}
pub fn set_precision(&mut self, precision: usize) -> Result<(), InvalidPrecisionError> {
if precision < 1 || precision > N * decnumber_sys::DECDPUN {
return Err(InvalidPrecisionError);
}
self.inner.digits = i32::try_from(precision).map_err(|_| InvalidPrecisionError)?;
Ok(())
}
pub fn clamp(&self) -> bool {
self.inner.clamp != 0
}
pub fn set_clamp(&mut self, clamp: bool) {
self.inner.clamp = u8::from(clamp)
}
pub fn max_exponent(&self) -> isize {
isize::try_from(self.inner.emax).expect("context max exponent does not fit into isize")
}
pub fn set_max_exponent(&mut self, e: isize) -> Result<(), InvalidExponentError> {
if e < 0 || e > 999999999 {
return Err(InvalidExponentError);
}
self.inner.emax = i32::try_from(e).map_err(|_| InvalidExponentError)?;
Ok(())
}
pub fn min_exponent(&self) -> isize {
isize::try_from(self.inner.emin).expect("context min exponent does not fit into isize")
}
pub fn set_min_exponent(&mut self, e: isize) -> Result<(), InvalidExponentError> {
if e > 0 || e < -999999999 {
return Err(InvalidExponentError);
}
self.inner.emin = i32::try_from(e).map_err(|_| InvalidExponentError)?;
Ok(())
}
pub fn parse<S>(&mut self, s: S) -> Result<Decimal<N>, ParseDecimalError>
where
S: Into<Vec<u8>>,
{
let c_string = CString::new(s).map_err(|_| ParseDecimalError)?;
self.parse_c_str(c_string.as_c_str())
}
pub fn parse_c_str(&mut self, s: &CStr) -> Result<Decimal<N>, ParseDecimalError> {
validate_n(N);
let mut d = Decimal::zero();
unsafe {
decnumber_sys::decNumberFromString(
d.as_mut_ptr() as *mut decnumber_sys::decNumber,
s.as_ptr(),
&mut self.inner,
);
};
if (self.inner.status & decnumber_sys::DEC_Conversion_syntax) != 0 {
Err(ParseDecimalError)
} else {
Ok(d)
}
}
pub fn class(&mut self, n: &Decimal<N>) -> Class {
Class::from_c(unsafe { decnumber_sys::decNumberClass(n.as_ptr(), &mut self.inner) })
}
pub fn abs(&mut self, n: &mut Decimal<N>) {
let n = n.as_mut_ptr();
unsafe {
decnumber_sys::decNumberAbs(n, n, &mut self.inner);
}
}
pub fn add<const M: usize>(&mut self, lhs: &mut Decimal<N>, rhs: &Decimal<M>) {
let lhs = lhs.as_mut_ptr();
unsafe {
decnumber_sys::decNumberAdd(lhs, lhs, rhs.as_ptr(), &mut self.inner);
}
}
pub fn and<const M: usize>(&mut self, lhs: &mut Decimal<N>, rhs: &Decimal<M>) {
let lhs = lhs.as_mut_ptr();
unsafe {
decnumber_sys::decNumberAnd(lhs, lhs, rhs.as_ptr(), &mut self.inner);
}
}
pub fn div<const M: usize>(&mut self, lhs: &mut Decimal<N>, rhs: &Decimal<M>) {
let lhs = lhs.as_mut_ptr();
unsafe {
decnumber_sys::decNumberDivide(lhs, lhs, rhs.as_ptr(), &mut self.inner);
}
}
pub fn div_integer<const M: usize>(&mut self, lhs: &mut Decimal<N>, rhs: &Decimal<M>) {
let lhs = lhs.as_mut_ptr();
unsafe {
decnumber_sys::decNumberDivideInteger(lhs, lhs, rhs.as_ptr(), &mut self.inner);
}
}
pub fn exp(&mut self, n: &mut Decimal<N>) {
let n = n.as_mut_ptr();
unsafe {
decnumber_sys::decNumberExp(n, n, &mut self.inner);
}
}
pub fn fma<const L: usize, const M: usize>(
&mut self,
x: &mut Decimal<N>,
y: &Decimal<L>,
z: &Decimal<M>,
) {
let x = x.as_mut_ptr();
unsafe {
decnumber_sys::decNumberFMA(x, x, y.as_ptr(), z.as_ptr(), &mut self.inner);
}
}
pub fn from_i32(&mut self, n: i32) -> Decimal<N> {
Decimal::<N>::from(n)
}
pub fn from_u32(&mut self, n: u32) -> Decimal<N> {
Decimal::<N>::from(n)
}
pub fn from_i64(&mut self, n: i64) -> Decimal<N> {
decimal_from_signed_int!(self, n)
}
pub fn from_u64(&mut self, n: u64) -> Decimal<N> {
decimal_from_unsigned_int!(self, n)
}
pub fn from_i128(&mut self, n: i128) -> Decimal<N> {
decimal_from_signed_int!(self, n)
}
pub fn from_u128(&mut self, n: u128) -> Decimal<N> {
decimal_from_unsigned_int!(self, n)
}
pub fn try_into_u8(&mut self, d: Decimal<N>) -> Result<u8, TryFromDecimalError> {
let i = self.try_into_u32(d)?;
u8::try_from(i).map_err(|_| TryFromDecimalError)
}
pub fn try_into_i8(&mut self, d: Decimal<N>) -> Result<i8, TryFromDecimalError> {
let i = self.try_into_i32(d)?;
i8::try_from(i).map_err(|_| TryFromDecimalError)
}
pub fn try_into_u16(&mut self, d: Decimal<N>) -> Result<u16, TryFromDecimalError> {
let i = self.try_into_u32(d)?;
u16::try_from(i).map_err(|_| TryFromDecimalError)
}
pub fn try_into_i16(&mut self, d: Decimal<N>) -> Result<i16, TryFromDecimalError> {
let i = self.try_into_i32(d)?;
i16::try_from(i).map_err(|_| TryFromDecimalError)
}
pub fn try_into_i32(&mut self, mut d: Decimal<N>) -> Result<i32, TryFromDecimalError> {
self.rescale(&mut d, &Decimal::<N>::zero());
let i = unsafe { decnumber_sys::decNumberToInt32(d.as_ptr(), &mut self.inner) };
if self.status().invalid_operation() || self.status().inexact() {
Err(TryFromDecimalError)
} else {
Ok(i)
}
}
pub fn try_into_u32(&mut self, mut d: Decimal<N>) -> Result<u32, TryFromDecimalError> {
self.rescale(&mut d, &Decimal::<N>::zero());
let i = unsafe { decnumber_sys::decNumberToUInt32(d.as_ptr(), &mut self.inner) };
if self.status().invalid_operation() || self.status().inexact() {
Err(TryFromDecimalError)
} else {
Ok(i)
}
}
#[cfg(target_pointer_width = "32")]
pub fn try_into_isize(&mut self, d: Decimal<N>) -> Result<isize, TryFromDecimalError> {
let d = self.try_into_i32(d)?;
Ok(d as isize)
}
#[cfg(target_pointer_width = "64")]
pub fn try_into_isize(&mut self, d: Decimal<N>) -> Result<isize, TryFromDecimalError> {
let d = self.try_into_i64(d)?;
Ok(d as isize)
}
pub fn try_into_i64(&mut self, mut d: Decimal<N>) -> Result<i64, TryFromDecimalError> {
decnum_tryinto_primitive_int!(i64, self, 19, d)
}
pub fn try_into_i128(&mut self, mut d: Decimal<N>) -> Result<i128, TryFromDecimalError> {
decnum_tryinto_primitive_int!(i128, self, 39, d)
}
#[cfg(target_pointer_width = "32")]
pub fn try_into_usize(&mut self, d: Decimal<N>) -> Result<usize, TryFromDecimalError> {
let d = self.try_into_u32(d)?;
Ok(d as usize)
}
#[cfg(target_pointer_width = "64")]
pub fn try_into_usize(&mut self, d: Decimal<N>) -> Result<usize, TryFromDecimalError> {
let d = self.try_into_u64(d)?;
Ok(d as usize)
}
pub fn try_into_u64(&mut self, mut d: Decimal<N>) -> Result<u64, TryFromDecimalError> {
decnum_tryinto_primitive_uint!(u64, self, 20, d)
}
pub fn try_into_u128(&mut self, mut d: Decimal<N>) -> Result<u128, TryFromDecimalError> {
decnum_tryinto_primitive_uint!(u128, self, 39, d)
}
pub fn try_into_f32(&mut self, d: Decimal<N>) -> Result<f32, TryFromDecimalError> {
decnum_tryinto_primitive_float!(f32, self, d)
}
pub fn try_into_f64(&mut self, d: Decimal<N>) -> Result<f64, TryFromDecimalError> {
decnum_tryinto_primitive_float!(f64, self, d)
}
pub fn from_f32(&mut self, n: f32) -> Decimal<N> {
self.from_float(n)
}
pub fn from_f64(&mut self, n: f64) -> Decimal<N> {
self.from_float(n)
}
pub fn from_float<T: LowerExp + Display>(&mut self, n: T) -> Decimal<N> {
const MAX_LEN: usize = 1024;
let mut buf = [0u8; MAX_LEN + 1];
let mut unwritten = &mut buf[..MAX_LEN];
write!(unwritten, "{}", n).unwrap();
let unwritten_len = unwritten.len();
let c_buf =
unsafe { CStr::from_bytes_with_nul_unchecked(&buf[..MAX_LEN - unwritten_len + 1]) };
self.parse_c_str(c_buf).unwrap()
}
pub fn invert(&mut self, n: &mut Decimal<N>) {
let n = n.as_mut_ptr();
unsafe {
decnumber_sys::decNumberInvert(n, n, &mut self.inner);
}
}
pub fn ln(&mut self, n: &mut Decimal<N>) {
let n = n.as_mut_ptr();
unsafe {
decnumber_sys::decNumberLn(n, n, &mut self.inner);
}
}
pub fn log10(&mut self, n: &mut Decimal<N>) {
let n = n.as_mut_ptr();
unsafe {
decnumber_sys::decNumberLog10(n, n, &mut self.inner);
}
}
pub fn logb(&mut self, n: &mut Decimal<N>) {
let n = n.as_mut_ptr();
unsafe {
decnumber_sys::decNumberLogB(n, n, &mut self.inner);
}
}
pub fn max<const M: usize>(&mut self, lhs: &mut Decimal<N>, rhs: &Decimal<M>) {
let lhs = lhs.as_mut_ptr();
unsafe {
decnumber_sys::decNumberMax(lhs, lhs, rhs.as_ptr(), &mut self.inner);
}
}
pub fn max_abs<const M: usize>(&mut self, lhs: &mut Decimal<N>, rhs: &Decimal<M>) {
let lhs = lhs.as_mut_ptr();
unsafe {
decnumber_sys::decNumberMaxMag(lhs, lhs, rhs.as_ptr(), &mut self.inner);
}
}
pub fn min<const M: usize>(&mut self, lhs: &mut Decimal<N>, rhs: &Decimal<M>) {
let lhs = lhs.as_mut_ptr();
unsafe {
decnumber_sys::decNumberMin(lhs, lhs, rhs.as_ptr(), &mut self.inner);
}
}
pub fn min_abs<const M: usize>(&mut self, lhs: &mut Decimal<N>, rhs: &Decimal<M>) {
let lhs = lhs.as_mut_ptr();
unsafe {
decnumber_sys::decNumberMinMag(lhs, lhs, rhs.as_ptr(), &mut self.inner);
}
}
pub fn minus(&mut self, n: &mut Decimal<N>) {
unsafe {
decnumber_sys::decNumberMinus(n.as_mut_ptr(), n.as_ptr(), &mut self.inner);
}
}
pub fn mul<const M: usize>(&mut self, lhs: &mut Decimal<N>, rhs: &Decimal<M>) {
let lhs = lhs.as_mut_ptr();
unsafe {
decnumber_sys::decNumberMultiply(lhs, lhs, rhs.as_ptr(), &mut self.inner);
}
}
pub fn neg(&mut self, n: &mut Decimal<N>) {
unsafe {
decnumber_sys::decNumberCopyNegate(n.as_mut_ptr(), n.as_ptr());
}
}
pub fn next_minus(&mut self, n: &mut Decimal<N>) {
unsafe {
decnumber_sys::decNumberNextMinus(n.as_mut_ptr(), n.as_ptr(), &mut self.inner);
}
}
pub fn next_plus(&mut self, n: &mut Decimal<N>) {
unsafe {
decnumber_sys::decNumberNextPlus(n.as_mut_ptr(), n.as_ptr(), &mut self.inner);
}
}
pub fn next_toward<const M: usize>(&mut self, x: &mut Decimal<N>, y: &Decimal<M>) {
unsafe {
decnumber_sys::decNumberNextToward(
x.as_mut_ptr(),
x.as_ptr(),
y.as_ptr(),
&mut self.inner,
);
}
}
pub fn or<const M: usize>(&mut self, lhs: &mut Decimal<N>, rhs: &Decimal<M>) {
let lhs = lhs.as_mut_ptr();
unsafe {
decnumber_sys::decNumberOr(lhs, lhs, rhs.as_ptr(), &mut self.inner);
}
}
pub fn partial_cmp<const L: usize, const M: usize>(
&mut self,
lhs: &Decimal<L>,
rhs: &Decimal<M>,
) -> Option<Ordering> {
validate_n(N);
let mut d = Decimal::<N>::zero();
unsafe {
decnumber_sys::decNumberCompare(
d.as_mut_ptr() as *mut decnumber_sys::decNumber,
lhs.as_ptr(),
rhs.as_ptr(),
&mut self.inner,
)
};
if d.is_nan() {
None
} else if d.is_negative() {
Some(Ordering::Less)
} else if d.is_zero() {
Some(Ordering::Equal)
} else {
debug_assert!(!d.is_special());
Some(Ordering::Greater)
}
}
pub fn plus(&mut self, n: &mut Decimal<N>) {
let n = n.as_mut_ptr();
unsafe {
decnumber_sys::decNumberPlus(n, n, &mut self.inner);
}
}
pub fn pow<const M: usize>(&mut self, x: &mut Decimal<N>, y: &Decimal<M>) {
let x = x.as_mut_ptr();
unsafe {
decnumber_sys::decNumberPower(x, x, y.as_ptr(), &mut self.inner);
}
}
pub fn product<'a, I, const M: usize>(&mut self, iter: I) -> Decimal<N>
where
I: Iterator<Item = &'a Decimal<M>>,
{
iter.fold(Decimal::<N>::from(1), |mut product, d| {
self.mul(&mut product, &d);
product
})
}
pub fn quantize<const M: usize>(&mut self, lhs: &mut Decimal<N>, rhs: &Decimal<M>) {
let lhs = lhs.as_mut_ptr();
unsafe {
decnumber_sys::decNumberQuantize(lhs, lhs, rhs.as_ptr(), &mut self.inner);
}
}
pub fn reduce(&mut self, n: &mut Decimal<N>) {
let n = n.as_mut_ptr();
unsafe {
decnumber_sys::decNumberReduce(n, n, &mut self.inner);
}
}
pub fn rem<const M: usize>(&mut self, lhs: &mut Decimal<N>, rhs: &Decimal<M>) {
let lhs = lhs.as_mut_ptr();
unsafe {
decnumber_sys::decNumberRemainder(lhs, lhs, rhs.as_ptr(), &mut self.inner);
}
}
pub fn rem_near<const M: usize>(&mut self, lhs: &mut Decimal<N>, rhs: &Decimal<M>) {
let lhs = lhs.as_mut_ptr();
unsafe {
decnumber_sys::decNumberRemainderNear(lhs, lhs, rhs.as_ptr(), &mut self.inner);
}
}
pub fn rescale<const M: usize>(&mut self, lhs: &mut Decimal<N>, rhs: &Decimal<M>) {
let lhs = lhs.as_mut_ptr();
unsafe {
decnumber_sys::decNumberRescale(lhs, lhs, rhs.as_ptr(), &mut self.inner);
}
}
pub fn round(&mut self, n: &mut Decimal<N>) {
let n = n.as_mut_ptr();
unsafe {
decnumber_sys::decNumberToIntegralExact(n, n, &mut self.inner);
}
}
pub fn round_to_place(
&mut self,
n: &mut Decimal<N>,
place: usize,
) -> Result<(), InvalidPrecisionError> {
let precision = self.precision();
self.set_precision(place)?;
self.plus(n);
self.set_precision(precision)
}
pub fn round_reduce_to_place(
&mut self,
n: &mut Decimal<N>,
place: usize,
) -> Result<(), InvalidPrecisionError> {
let precision = self.precision();
self.set_precision(place)?;
self.reduce(n);
self.set_precision(precision)
}
pub fn shift<const M: usize>(&mut self, lhs: &mut Decimal<N>, rhs: &Decimal<M>) {
let lhs = lhs.as_mut_ptr();
unsafe {
decnumber_sys::decNumberShift(lhs, lhs, rhs.as_ptr(), &mut self.inner);
}
}
pub fn rotate<const M: usize>(&mut self, lhs: &mut Decimal<N>, rhs: &Decimal<M>) {
let lhs = lhs.as_mut_ptr();
unsafe {
decnumber_sys::decNumberRotate(lhs, lhs, rhs.as_ptr(), &mut self.inner);
}
}
pub fn scaleb<const M: usize>(&mut self, x: &mut Decimal<N>, y: &Decimal<M>) {
unsafe {
decnumber_sys::decNumberScaleB(x.as_mut_ptr(), x.as_ptr(), y.as_ptr(), &mut self.inner);
}
}
pub fn sqrt<const M: usize>(&mut self, n: &mut Decimal<M>) {
let n = n.as_mut_ptr();
unsafe {
decnumber_sys::decNumberSquareRoot(n, n, &mut self.inner);
}
}
pub fn sub<const M: usize>(&mut self, lhs: &mut Decimal<N>, rhs: &Decimal<M>) {
let lhs = lhs.as_mut_ptr();
unsafe {
decnumber_sys::decNumberSubtract(lhs, lhs, rhs.as_ptr(), &mut self.inner);
}
}
pub fn sum<'a, I, const M: usize>(&mut self, iter: I) -> Decimal<N>
where
I: Iterator<Item = &'a Decimal<M>>,
{
iter.fold(Decimal::<N>::zero(), |mut sum, d| {
self.add(&mut sum, d);
sum
})
}
pub fn total_cmp<const L: usize, const M: usize>(
&mut self,
lhs: &Decimal<L>,
rhs: &Decimal<M>,
) -> Ordering {
validate_n(N);
let mut d = Decimal::<N>::zero();
unsafe {
decnumber_sys::decNumberCompareTotal(
d.as_mut_ptr() as *mut decnumber_sys::decNumber,
lhs.as_ptr(),
rhs.as_ptr(),
&mut self.inner,
)
};
debug_assert!(!d.is_special());
if d.is_negative() {
Ordering::Less
} else if d.is_zero() {
Ordering::Equal
} else {
Ordering::Greater
}
}
pub fn xor<const M: usize>(&mut self, lhs: &mut Decimal<N>, rhs: &Decimal<M>) {
let lhs = lhs.as_mut_ptr();
unsafe {
decnumber_sys::decNumberXor(lhs, lhs, rhs.as_ptr(), &mut self.inner);
}
}
pub fn to_width<const M: usize>(&mut self, m: Decimal<M>) -> Decimal<N> {
let mut n = Decimal::<N>::zero();
unsafe {
decnumber_sys::decNumberPlus(n.as_mut_ptr(), m.as_ptr(), &mut self.inner);
}
n
}
}
#[cfg(feature = "num-traits")]
impl<const N: usize> Zero for Decimal<N> {
#[inline]
fn zero() -> Self {
Decimal::<N>::zero()
}
#[inline]
fn is_zero(&self) -> bool {
self.is_zero()
}
}
#[cfg(feature = "num-traits")]
impl<const N: usize, const L: usize, const M: usize> MulAdd<Decimal<L>, Decimal<M>> for Decimal<N> {
type Output = Self;
#[inline]
fn mul_add(mut self, a: Decimal<L>, b: Decimal<M>) -> Self::Output {
self.mul_add_assign(a, b);
self
}
}
#[cfg(feature = "num-traits")]
impl<const N: usize, const L: usize, const M: usize> MulAddAssign<Decimal<L>, Decimal<M>>
for Decimal<N>
{
fn mul_add_assign(&mut self, a: Decimal<L>, b: Decimal<M>) {
Context::<Self>::default().fma(self, &a, &b);
}
}
#[cfg(feature = "num-traits")]
impl<const N: usize, const M: usize> Pow<Decimal<M>> for Decimal<N> {
type Output = Self;
fn pow(mut self, rhs: Decimal<M>) -> Self::Output {
Context::<Decimal<N>>::default().pow(&mut self, &rhs);
self
}
}