use std::fmt;
use std::marker::PhantomData;
use libc::c_uint;
#[derive(Clone)]
pub struct Context<D> {
pub(crate) inner: decnumber_sys::decContext,
pub(crate) _phantom: PhantomData<D>,
}
impl<D> fmt::Debug for Context<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Context")
.field("clamp", &self.inner.clamp)
.field("digits", &self.inner.digits)
.field("emax", &self.inner.emax)
.field("emin", &self.inner.emin)
.field("rounding", &self.rounding())
.field("traps", &self.inner.traps)
.finish()
}
}
impl<D> Context<D> {
pub fn rounding(&self) -> Rounding {
Rounding::from_c(self.inner.round)
}
pub fn set_rounding(&mut self, rounding: Rounding) {
self.inner.round = rounding.to_c();
}
pub fn status(&self) -> Status {
Status {
inner: self.inner.status,
}
}
pub fn clear_status(&mut self) {
self.inner.status = 0;
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum Rounding {
Ceiling,
Down,
Floor,
HalfDown,
HalfEven,
HalfUp,
Up,
ZeroFiveUp,
}
impl Default for Rounding {
fn default() -> Rounding {
Rounding::HalfEven
}
}
impl Rounding {
fn from_c(c: c_uint) -> Rounding {
match c {
decnumber_sys::DEC_ROUND_CEILING => Rounding::Ceiling,
decnumber_sys::DEC_ROUND_DOWN => Rounding::Down,
decnumber_sys::DEC_ROUND_FLOOR => Rounding::Floor,
decnumber_sys::DEC_ROUND_HALF_DOWN => Rounding::HalfDown,
decnumber_sys::DEC_ROUND_HALF_EVEN => Rounding::HalfEven,
decnumber_sys::DEC_ROUND_HALF_UP => Rounding::HalfUp,
decnumber_sys::DEC_ROUND_UP => Rounding::Up,
decnumber_sys::DEC_ROUND_05UP => Rounding::ZeroFiveUp,
_ => unreachable!("invalid C rounding value"),
}
}
fn to_c(&self) -> c_uint {
match self {
Rounding::Ceiling => decnumber_sys::DEC_ROUND_CEILING,
Rounding::Down => decnumber_sys::DEC_ROUND_DOWN,
Rounding::Floor => decnumber_sys::DEC_ROUND_FLOOR,
Rounding::HalfDown => decnumber_sys::DEC_ROUND_HALF_DOWN,
Rounding::HalfEven => decnumber_sys::DEC_ROUND_HALF_EVEN,
Rounding::HalfUp => decnumber_sys::DEC_ROUND_HALF_UP,
Rounding::Up => decnumber_sys::DEC_ROUND_UP,
Rounding::ZeroFiveUp => decnumber_sys::DEC_ROUND_05UP,
}
}
}
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
pub struct Status {
inner: u32,
}
impl fmt::Debug for Status {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Status")
.field("conversion_syntax", &self.conversion_syntax())
.field("division_by_zero", &self.division_by_zero())
.field("division_impossible", &self.division_impossible())
.field("division_undefined", &self.division_undefined())
.field("insufficient_storage", &self.insufficient_storage())
.field("inexact", &self.inexact())
.field("invalid_context", &self.invalid_context())
.field("invalid_operation", &self.invalid_operation())
.field("overflow", &self.overflow())
.field("clamped", &self.clamped())
.field("rounded", &self.rounded())
.field("subnormal", &self.subnormal())
.field("underflow", &self.underflow())
.field("raw", &self.inner)
.finish()
}
}
impl Status {
pub fn any(&self) -> bool {
self.inner != 0
}
pub fn conversion_syntax(&self) -> bool {
self.inner & decnumber_sys::DEC_Conversion_syntax != 0
}
pub fn division_by_zero(&self) -> bool {
self.inner & decnumber_sys::DEC_Division_by_zero != 0
}
pub fn division_impossible(&self) -> bool {
self.inner & decnumber_sys::DEC_Division_impossible != 0
}
pub fn division_undefined(&self) -> bool {
self.inner & decnumber_sys::DEC_Division_undefined != 0
}
pub fn insufficient_storage(&self) -> bool {
self.inner & decnumber_sys::DEC_Insufficient_storage != 0
}
pub fn inexact(&self) -> bool {
self.inner & decnumber_sys::DEC_Inexact != 0
}
pub fn invalid_context(&self) -> bool {
self.inner & decnumber_sys::DEC_Invalid_context != 0
}
pub fn invalid_operation(&self) -> bool {
self.inner & decnumber_sys::DEC_Invalid_operation != 0
}
pub fn overflow(&self) -> bool {
self.inner & decnumber_sys::DEC_Overflow != 0
}
pub fn clamped(&self) -> bool {
self.inner & decnumber_sys::DEC_Clamped != 0
}
pub fn rounded(&self) -> bool {
self.inner & decnumber_sys::DEC_Rounded != 0
}
pub fn subnormal(&self) -> bool {
self.inner & decnumber_sys::DEC_Subnormal != 0
}
pub fn underflow(&self) -> bool {
self.inner & decnumber_sys::DEC_Underflow != 0
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum Class {
SignalingNan,
QuietNan,
NegInfinity,
NegNormal,
NegSubnormal,
NegZero,
PosZero,
PosSubnormal,
PosNormal,
PosInfinity,
}
impl Class {
pub(crate) fn from_c(c: c_uint) -> Class {
match c {
decnumber_sys::DEC_CLASS_SNAN => Class::SignalingNan,
decnumber_sys::DEC_CLASS_QNAN => Class::QuietNan,
decnumber_sys::DEC_CLASS_NEG_INF => Class::NegInfinity,
decnumber_sys::DEC_CLASS_NEG_NORMAL => Class::NegNormal,
decnumber_sys::DEC_CLASS_NEG_SUBNORMAL => Class::NegSubnormal,
decnumber_sys::DEC_CLASS_NEG_ZERO => Class::NegZero,
decnumber_sys::DEC_CLASS_POS_ZERO => Class::PosZero,
decnumber_sys::DEC_CLASS_POS_SUBNORMAL => Class::PosSubnormal,
decnumber_sys::DEC_CLASS_POS_NORMAL => Class::PosNormal,
decnumber_sys::DEC_CLASS_POS_INF => Class::PosInfinity,
_ => unreachable!("invalid C class value"),
}
}
}
impl fmt::Display for Class {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Class::SignalingNan => f.write_str("sNaN"),
Class::QuietNan => f.write_str("NaN"),
Class::NegInfinity => f.write_str("-Infinity"),
Class::NegNormal => f.write_str("-Normal"),
Class::NegSubnormal => f.write_str("-Subnormal"),
Class::NegZero => f.write_str("-Zero"),
Class::PosZero => f.write_str("+Zero"),
Class::PosSubnormal => f.write_str("+Subnormal"),
Class::PosNormal => f.write_str("+Normal"),
Class::PosInfinity => f.write_str("+Infinity"),
}
}
}