use std::fmt;
use std::marker::PhantomData;
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign};
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 set_status(&mut self, status: Status) {
self.inner.status = status.inner;
}
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 set_conversion_syntax(&mut self) {
self.inner |= decnumber_sys::DEC_Conversion_syntax;
}
pub fn division_by_zero(&self) -> bool {
self.inner & decnumber_sys::DEC_Division_by_zero != 0
}
pub fn set_division_by_zero(&mut self) {
self.inner |= decnumber_sys::DEC_Division_by_zero;
}
pub fn division_impossible(&self) -> bool {
self.inner & decnumber_sys::DEC_Division_impossible != 0
}
pub fn set_division_impossible(&mut self) {
self.inner |= decnumber_sys::DEC_Division_impossible;
}
pub fn division_undefined(&self) -> bool {
self.inner & decnumber_sys::DEC_Division_undefined != 0
}
pub fn set_division_undefined(&mut self) {
self.inner |= decnumber_sys::DEC_Division_undefined;
}
pub fn insufficient_storage(&self) -> bool {
self.inner & decnumber_sys::DEC_Insufficient_storage != 0
}
pub fn set_insufficient_storage(&mut self) {
self.inner |= decnumber_sys::DEC_Insufficient_storage;
}
pub fn inexact(&self) -> bool {
self.inner & decnumber_sys::DEC_Inexact != 0
}
pub fn set_inexact(&mut self) {
self.inner |= decnumber_sys::DEC_Inexact;
}
pub fn invalid_context(&self) -> bool {
self.inner & decnumber_sys::DEC_Invalid_context != 0
}
pub fn set_invalid_context(&mut self) {
self.inner |= decnumber_sys::DEC_Invalid_context;
}
pub fn invalid_operation(&self) -> bool {
self.inner & decnumber_sys::DEC_Invalid_operation != 0
}
pub fn set_invalid_operation(&mut self) {
self.inner |= decnumber_sys::DEC_Invalid_operation;
}
pub fn overflow(&self) -> bool {
self.inner & decnumber_sys::DEC_Overflow != 0
}
pub fn set_overflow(&mut self) {
self.inner |= decnumber_sys::DEC_Overflow;
}
pub fn clamped(&self) -> bool {
self.inner & decnumber_sys::DEC_Clamped != 0
}
pub fn set_clamped(&mut self) {
self.inner |= decnumber_sys::DEC_Clamped;
}
pub fn rounded(&self) -> bool {
self.inner & decnumber_sys::DEC_Rounded != 0
}
pub fn set_rounded(&mut self) {
self.inner |= decnumber_sys::DEC_Rounded;
}
pub fn subnormal(&self) -> bool {
self.inner & decnumber_sys::DEC_Subnormal != 0
}
pub fn set_subnormal(&mut self) {
self.inner |= decnumber_sys::DEC_Subnormal;
}
pub fn underflow(&self) -> bool {
self.inner & decnumber_sys::DEC_Underflow != 0
}
pub fn set_underflow(&mut self) {
self.inner |= decnumber_sys::DEC_Underflow;
}
}
impl Default for Status {
fn default() -> Self {
Status { inner: 0 }
}
}
impl BitAnd for Status {
type Output = Status;
fn bitand(self, rhs: Status) -> Status {
Status {
inner: self.inner & rhs.inner,
}
}
}
impl BitAndAssign for Status {
fn bitand_assign(&mut self, rhs: Status) {
self.inner &= rhs.inner;
}
}
impl BitOr for Status {
type Output = Status;
fn bitor(self, rhs: Status) -> Status {
Status {
inner: self.inner | rhs.inner,
}
}
}
impl BitOrAssign for Status {
fn bitor_assign(&mut self, rhs: Status) {
self.inner |= rhs.inner;
}
}
#[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"),
}
}
}