mod convert;
mod tosql;
pub use self::convert::Integer;
pub(crate) use self::convert::{Real, from_number, to_string, to_real};
use super::{Ctx, interval::Interval};
use crate::{Result, oci::{self, *}};
use std::{cmp::Ordering, mem, ops::{Deref, DerefMut}};
pub(crate) fn new() -> OCINumber {
let mut num = mem::MaybeUninit::<OCINumber>::uninit();
let ptr = num.as_mut_ptr();
unsafe {
(*ptr).bytes[0] = 0;
num.assume_init()
}
}
fn compare(num1: &OCINumber, num2: &OCINumber, err: &OCIError) -> Result<Ordering> {
let mut cmp = 0i32;
oci::number_cmp(err, num1, num2, &mut cmp)?;
let ordering = if cmp < 0 {
Ordering::Less
} else if cmp == 0 {
Ordering::Equal
} else {
Ordering::Greater
};
Ok(ordering)
}
macro_rules! impl_query {
($this:ident => $f:path) => {{
let mut res: i32 = 0;
$f($this.ctx.as_ref(), &$this.num, &mut res)?;
Ok(res != 0)
}};
}
macro_rules! impl_fn {
($this:ident => $f:path) => {{
let ctx = $this.ctx;
let mut num = mem::MaybeUninit::<OCINumber>::uninit();
$f(ctx.as_ref(), &$this.num, num.as_mut_ptr())?;
let num = unsafe { num.assume_init() };
Ok(Number { num, ctx })
}};
}
macro_rules! impl_op {
($this:ident, $other:ident => $f:path) => {{
let ctx = $this.ctx;
let mut num = mem::MaybeUninit::<OCINumber>::uninit();
$f(ctx.as_ref(), &$this.num, &$other.num, num.as_mut_ptr())?;
let num = unsafe { num.assume_init() };
Ok(Number { num, ctx })
}};
}
macro_rules! impl_opi {
($this:ident, $int:ident => $f:path) => {{
let ctx = $this.ctx;
let mut num = mem::MaybeUninit::<OCINumber>::uninit();
$f(ctx.as_ref(), &$this.num, $int, num.as_mut_ptr())?;
let num = unsafe { num.assume_init() };
Ok(Number { num, ctx })
}};
}
pub struct Number<'a> {
ctx: &'a dyn Ctx,
num: OCINumber,
}
impl AsRef<OCINumber> for Number<'_> {
fn as_ref(&self) -> &OCINumber {
&self.num
}
}
impl AsMut<OCINumber> for Number<'_> {
fn as_mut(&mut self) -> &mut OCINumber {
&mut self.num
}
}
impl Deref for Number<'_> {
type Target = OCINumber;
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
impl DerefMut for Number<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut()
}
}
impl<'a> Number<'a> {
pub(crate) fn to_interval<T: DescriptorType<OCIType=OCIInterval>>(&self) -> Result<Interval<'a, T>> {
let mut interval = Descriptor::<T>::new(&self.ctx)?;
oci::interval_from_number(self.ctx.as_context(), self.ctx.as_ref(), &mut interval, &self.num)?;
Ok(Interval::from(interval, self.ctx))
}
pub(crate) fn from(src: &OCINumber, ctx: &'a dyn Ctx) -> Result<Self> {
let num = from_number(src, ctx.as_ref())?;
Ok(Self {num, ctx})
}
pub(crate) fn make(num: OCINumber, ctx: &'a dyn Ctx) -> Self {
Self {num, ctx}
}
pub fn new(ctx: &'a dyn Ctx) -> Self {
Self { ctx, num: new() }
}
pub fn zero(ctx: &'a dyn Ctx) -> Self {
let mut num = mem::MaybeUninit::<OCINumber>::uninit();
unsafe {
OCINumberSetZero(ctx.as_ref(), num.as_mut_ptr());
}
let num = unsafe { num.assume_init() };
Self { ctx, num }
}
pub fn pi(ctx: &'a dyn Ctx) -> Self {
let mut num = mem::MaybeUninit::<OCINumber>::uninit();
unsafe {
OCINumberSetPi(ctx.as_ref(), num.as_mut_ptr());
}
let num = unsafe { num.assume_init() };
Self { ctx, num }
}
pub fn from_string(txt: &str, fmt: &str, ctx: &'a dyn Ctx) -> Result<Self> {
let mut num = mem::MaybeUninit::<OCINumber>::uninit();
oci::number_from_text(
ctx.as_ref(),
txt.as_ptr(),
txt.len() as u32,
fmt.as_ptr(),
fmt.len() as u32,
num.as_mut_ptr(),
)?;
Ok(Self {
ctx,
num: unsafe { num.assume_init() },
})
}
pub fn from_int<T: Integer>(val: T, ctx: &'a dyn Ctx) -> Result<Self> {
let num = val.into_number(ctx.as_ref())?;
Ok(Self { ctx, num })
}
pub fn from_real<T: Real>(val: T, ctx: &'a dyn Ctx) -> Result<Self> {
let num = val.into_number(ctx.as_ref())?;
Ok(Self { ctx, num })
}
pub fn from_number(other: &'a Number) -> Result<Self> {
let num = from_number(&other.num, other.ctx.as_ref())?;
Ok(Self {num, ..*other})
}
pub fn assign(&mut self, src: &Number) -> Result<()> {
oci::number_assign(self.ctx.as_ref(), &src.num, &mut self.num)
}
pub fn to_string(&self, fmt: &str) -> Result<String> {
to_string(fmt, &self.num, self.ctx.as_ref())
}
pub fn to_int<T: Integer>(&self) -> Result<T> {
<T>::from_number(&self.num, self.ctx.as_ref())
}
pub fn to_real<T: Real>(&self) -> Result<T> {
to_real(&self.num, self.ctx.as_ref())
}
pub fn is_zero(&self) -> Result<bool> {
impl_query!(self => oci::number_is_zero)
}
pub fn is_int(&self) -> Result<bool> {
impl_query!(self => oci::number_is_int)
}
pub fn inc(&mut self) -> Result<()> {
oci::number_inc(self.ctx.as_ref(), &mut self.num)
}
pub fn dec(&mut self) -> Result<()> {
oci::number_dec(self.ctx.as_ref(), &mut self.num)
}
pub fn sign(&self) -> Result<Ordering> {
let mut res = 0i32;
oci::number_sign(self.ctx.as_ref(), &self.num, &mut res)?;
let ordering = if res == 0 {
Ordering::Equal
} else if res < 0 {
Ordering::Less
} else {
Ordering::Greater
};
Ok(ordering)
}
pub fn compare(&self, other: &Self) -> Result<Ordering> {
compare(&self.num, &other.num, self.ctx.as_ref())
}
pub fn add(&self, num: &Number) -> Result<Self> {
impl_op!(self, num => oci::number_add)
}
pub fn sub(&self, num: &Number) -> Result<Self> {
impl_op!(self, num => oci::number_sub)
}
pub fn mul(&self, num: &Number) -> Result<Self> {
impl_op!(self, num => oci::number_mul)
}
pub fn div(&self, num: &Number) -> Result<Self> {
impl_op!(self, num => oci::number_div)
}
pub fn rem(&self, num: &Number) -> Result<Self> {
impl_op!(self, num => oci::number_mod)
}
pub fn pow(&self, num: &Number) -> Result<Self> {
impl_op!(self, num => oci::number_power)
}
pub fn powi(&self, num: i32) -> Result<Self> {
impl_opi!(self, num => oci::number_int_power)
}
pub fn pow10(&self, num: i32) -> Result<Self> {
impl_opi!(self, num => oci::number_shift)
}
pub fn trunc(&self, num: i32) -> Result<Self> {
impl_opi!(self, num => oci::number_trunc)
}
pub fn round(&self, num: i32) -> Result<Self> {
impl_opi!(self, num => oci::number_round)
}
pub fn prec(&self, num: i32) -> Result<Self> {
impl_opi!(self, num => oci::number_prec)
}
pub fn neg(&self) -> Result<Self> {
impl_fn!(self => oci::number_neg)
}
pub fn abs(&self) -> Result<Self> {
impl_fn!(self => oci::number_abs)
}
pub fn ceil(&self) -> Result<Self> {
impl_fn!(self => oci::number_ceil)
}
pub fn floor(&self) -> Result<Self> {
impl_fn!(self => oci::number_floor)
}
pub fn sqrt(&self) -> Result<Self> {
impl_fn!(self => oci::number_sqrt)
}
pub fn sin(&self) -> Result<Self> {
impl_fn!(self => oci::number_sin)
}
pub fn asin(&self) -> Result<Self> {
impl_fn!(self => oci::number_arc_sin)
}
pub fn sinh(&self) -> Result<Self> {
impl_fn!(self => oci::number_hyp_sin)
}
pub fn cos(&self) -> Result<Self> {
impl_fn!(self => oci::number_cos)
}
pub fn acos(&self) -> Result<Self> {
impl_fn!(self => oci::number_arc_cos)
}
pub fn cosh(&self) -> Result<Self> {
impl_fn!(self => oci::number_hyp_cos)
}
pub fn tan(&self) -> Result<Self> {
impl_fn!(self => oci::number_tan)
}
pub fn atan(&self) -> Result<Self> {
impl_fn!(self => oci::number_arc_tan)
}
pub fn atan2(&self, num: &Number) -> Result<Self> {
impl_op!(self, num => oci::number_arc_tan2)
}
pub fn tanh(&self) -> Result<Self> {
impl_fn!(self => oci::number_hyp_tan)
}
pub fn exp(&self) -> Result<Self> {
impl_fn!(self => oci::number_exp)
}
pub fn ln(&self) -> Result<Self> {
impl_fn!(self => oci::number_ln)
}
pub fn log(&self, num: &Number) -> Result<Self> {
let ctx = self.ctx;
let mut res = mem::MaybeUninit::<OCINumber>::uninit();
oci::number_log(ctx.as_ref(), &num.num, &self.num, res.as_mut_ptr())?;
let num = unsafe { res.assume_init() };
Ok(Number {num, ctx})
}
pub fn size(&self) -> usize {
mem::size_of::<OCINumber>()
}
}
impl std::fmt::Debug for Number<'_> {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.to_string("TM") {
Ok(txt) => fmt.write_fmt(format_args!("Number({})", txt)),
Err(err) => fmt.write_fmt(format_args!("Number({})", err)),
}
}
}