use crate::complex::arith::{AddMulIncomplete, SubMulFromIncomplete};
use crate::complex::{BorrowComplex, OrdComplex, Prec, Prec64};
use crate::ext::xmpc;
use crate::ext::xmpc::{NEAREST2, Ordering2, Round2};
use crate::ext::xmpfr;
use crate::float;
use crate::float::big::{
self as big_float, ExpFormat, Format as FloatFormat, ParseIncomplete as FloatParseIncomplete,
};
use crate::float::{BorrowFloat, ParseFloatError, Round, Special};
use crate::misc;
use crate::misc::StringLike;
use crate::ops::{
AddAssignRound, AssignRound, CompleteRound, NegAssign, SubAssignRound, SubFrom, SubFromRound,
};
#[cfg(feature = "rand")]
use crate::rand::MutRandState;
use crate::{Assign, Float};
use az::StrictCast;
use core::cmp::Ordering;
use core::error::Error;
use core::fmt::{Display, Formatter, Result as FmtResult};
use core::mem::{ManuallyDrop, MaybeUninit};
use core::ops::{Add, AddAssign, Sub, SubAssign};
use core::slice;
use gmp_mpfr_sys::mpc::mpc_t;
#[cfg(feature = "num-complex")]
use num_complex::Complex as NumComplex;
#[repr(transparent)]
pub struct Complex {
inner: mpc_t,
}
static_assert_same_layout!(Complex, mpc_t);
static_assert_same_layout!(BorrowComplex<'_>, mpc_t);
static_assert_same_size!(Complex, Option<Complex>);
macro_rules! ref_math_op0_complex {
($($rest:tt)*) => {
ref_math_op0_round! {
Complex, (u32, u32), Round2, NEAREST2, Ordering2;
$($rest)*
}
};
}
macro_rules! ref_math_op1_complex {
($($rest:tt)*) => {
ref_math_op1_round! {
Complex, (u32, u32), Round2, NEAREST2, Ordering2;
$($rest)*
}
};
}
macro_rules! ref_math_op1_2_complex {
($($rest:tt)*) => {
ref_math_op1_2_round! {
Complex, (u32, u32), Round2, NEAREST2, (Ordering2, Ordering2);
$($rest)*
}
};
}
macro_rules! ref_math_op2_complex {
($($rest:tt)*) => {
ref_math_op2_round! {
Complex, (u32, u32), Round2, NEAREST2, Ordering2;
$($rest)*
}
};
}
impl Complex {
#[inline]
pub(crate) fn new_nan<P: Prec>(prec: P) -> Self {
let p = prec.prec();
assert!(
(float::prec_min()..=float::prec_max()).contains(&p.0)
&& (float::prec_min()..=float::prec_max()).contains(&p.1),
"precision out of range"
);
let mut ret = MaybeUninit::uninit();
xmpc::write_new_nan(&mut ret, p.0.strict_cast(), p.1.strict_cast());
unsafe { ret.assume_init() }
}
#[inline]
pub fn new<P: Prec>(prec: P) -> Self {
Self::with_val(prec, (Special::Zero, Special::Zero))
}
#[inline]
pub fn with_val<P, T>(prec: P, val: T) -> Self
where
Self: Assign<T>,
P: Prec,
{
let mut ret = Complex::new_nan(prec);
ret.assign(val);
ret
}
#[inline]
pub fn with_val_round<P, T>(prec: P, val: T, round: Round2) -> (Self, Ordering2)
where
Self: AssignRound<T, Round = Round2, Ordering = Ordering2>,
P: Prec,
{
let mut ret = Complex::new_nan(prec);
let ord = ret.assign_round(val, round);
(ret, ord)
}
#[inline]
pub const fn prec(&self) -> (u32, u32) {
(self.real().prec(), self.imag().prec())
}
#[inline]
pub fn set_prec<P: Prec>(&mut self, prec: P) {
self.set_prec_round(prec, NEAREST2);
}
#[inline]
pub fn set_prec_round<P: Prec>(&mut self, prec: P, round: Round2) -> Ordering2 {
let p = prec.prec();
let (real, imag) = self.as_mut_real_imag();
(
real.set_prec_round(p.0, round.0),
imag.set_prec_round(p.1, round.1),
)
}
#[inline]
pub(crate) fn new_nan_64<P: Prec64>(prec: P) -> Self {
let p = prec.prec();
assert!(
(float::prec_min_64()..=float::prec_max_64()).contains(&p.0)
&& (float::prec_min_64()..=float::prec_max_64()).contains(&p.1),
"precision out of range"
);
let mut ret = MaybeUninit::uninit();
xmpc::write_new_nan(&mut ret, p.0.strict_cast(), p.1.strict_cast());
unsafe { ret.assume_init() }
}
#[inline]
pub fn new_64<P: Prec64>(prec: P) -> Self {
Self::with_val_64(prec, (Special::Zero, Special::Zero))
}
#[inline]
pub fn with_val_64<P, T>(prec: P, val: T) -> Self
where
Self: Assign<T>,
P: Prec64,
{
let mut ret = Complex::new_nan_64(prec);
ret.assign(val);
ret
}
#[inline]
pub fn with_val_round_64<P, T>(prec: P, val: T, round: Round2) -> (Self, Ordering2)
where
Self: AssignRound<T, Round = Round2, Ordering = Ordering2>,
P: Prec64,
{
let mut ret = Complex::new_nan_64(prec);
let ord = ret.assign_round(val, round);
(ret, ord)
}
#[inline]
pub const fn prec_64(&self) -> (u64, u64) {
(self.real().prec_64(), self.imag().prec_64())
}
#[inline]
pub fn set_prec_64<P: Prec64>(&mut self, prec: P) {
self.set_prec_round_64(prec, NEAREST2);
}
#[inline]
pub fn set_prec_round_64<P: Prec64>(&mut self, prec: P, round: Round2) -> Ordering2 {
let p = prec.prec();
let (real, imag) = self.as_mut_real_imag();
(
real.set_prec_round_64(p.0, round.0),
imag.set_prec_round_64(p.1, round.1),
)
}
#[inline]
pub const unsafe fn from_raw(raw: mpc_t) -> Self {
Complex { inner: raw }
}
#[inline]
pub const fn into_raw(self) -> mpc_t {
let ret = self.inner;
let _ = ManuallyDrop::new(self);
ret
}
#[inline]
pub const fn as_raw(&self) -> *const mpc_t {
&self.inner
}
#[inline]
pub fn as_raw_mut(&mut self) -> *mut mpc_t {
&mut self.inner
}
#[inline]
pub fn parse<S: AsRef<[u8]>>(src: S) -> Result<ParseIncomplete, ParseComplexError> {
parse(src.as_ref(), 10)
}
#[inline]
pub fn parse_radix<S: AsRef<[u8]>>(
src: S,
radix: i32,
) -> Result<ParseIncomplete, ParseComplexError> {
parse(src.as_ref(), radix)
}
#[cfg(feature = "num-complex")]
#[cfg(feature = "nightly-float")]
#[inline]
pub fn to_c16(&self) -> NumComplex<f16> {
self.to_c16_round(NEAREST2)
}
#[cfg(feature = "num-complex")]
#[cfg(feature = "nightly-float")]
#[inline]
pub fn to_c16_round(&self, round: Round2) -> NumComplex<f16> {
NumComplex::new(
self.real().to_f16_round(round.0),
self.imag().to_f16_round(round.1),
)
}
#[cfg(feature = "num-complex")]
#[inline]
pub fn to_c32(&self) -> NumComplex<f32> {
self.to_c32_round(NEAREST2)
}
#[cfg(feature = "num-complex")]
#[inline]
pub fn to_c32_round(&self, round: Round2) -> NumComplex<f32> {
NumComplex::new(
self.real().to_f32_round(round.0),
self.imag().to_f32_round(round.1),
)
}
#[cfg(feature = "num-complex")]
#[inline]
pub fn to_c64(&self) -> NumComplex<f64> {
self.to_c64_round(NEAREST2)
}
#[cfg(feature = "num-complex")]
#[inline]
pub fn to_c64_round(&self, round: Round2) -> NumComplex<f64> {
NumComplex::new(
self.real().to_f64_round(round.0),
self.imag().to_f64_round(round.1),
)
}
#[cfg(feature = "num-complex")]
#[cfg(feature = "nightly-float")]
#[inline]
pub fn to_c128(&self) -> NumComplex<f128> {
self.to_c128_round(NEAREST2)
}
#[cfg(feature = "num-complex")]
#[cfg(feature = "nightly-float")]
#[inline]
pub fn to_c128_round(&self, round: Round2) -> NumComplex<f128> {
NumComplex::new(
self.real().to_f128_round(round.0),
self.imag().to_f128_round(round.1),
)
}
#[cfg(feature = "std")]
#[inline]
pub fn to_string_radix(&self, radix: i32, num_digits: Option<usize>) -> String {
self.to_string_radix_round(radix, num_digits, NEAREST2)
}
#[cfg(feature = "std")]
pub fn to_string_radix_round(
&self,
radix: i32,
num_digits: Option<usize>,
round: Round2,
) -> String {
let format = Format {
radix,
precision: num_digits,
round,
to_upper: false,
sign_plus: false,
prefix: "",
exp: ExpFormat::Point,
};
let mut s = StringLike::new_string();
append_to_string(&mut s, self, format);
s.unwrap_string()
}
#[inline]
pub const fn real(&self) -> &Float {
xmpc::realref_const(self)
}
#[inline]
pub const fn imag(&self) -> &Float {
xmpc::imagref_const(self)
}
#[inline]
pub fn mut_real(&mut self) -> &mut Float {
xmpc::realref(self)
}
#[inline]
pub fn mut_imag(&mut self) -> &mut Float {
xmpc::imagref(self)
}
#[inline]
pub fn as_mut_real_imag(&mut self) -> (&mut Float, &mut Float) {
xmpc::realref_imagref(self)
}
#[inline]
pub const fn into_real_imag(self) -> (Float, Float) {
xmpc::split(self)
}
pub const fn borrow_real_imag<'a>(real: &'a Float, imag: &'a Float) -> BorrowComplex<'a> {
let raw = mpc_t {
re: *real.inner(),
im: *imag.inner(),
};
unsafe { BorrowComplex::from_raw(raw) }
}
#[inline]
pub fn mutate_real_imag<F>(real: &mut Float, imag: &mut Float, func: F)
where
F: FnOnce(&mut Complex),
{
struct SplitOnDrop<'a, 'b>(ManuallyDrop<Complex>, &'a mut Float, &'b mut Float);
impl Drop for SplitOnDrop<'_, '_> {
fn drop(&mut self) {
unsafe {
*self.1.inner_mut() = *self.0.real().inner();
*self.2.inner_mut() = *self.0.imag().inner();
}
}
}
let raw = mpc_t {
re: *real.inner(),
im: *imag.inner(),
};
let combined = ManuallyDrop::new(unsafe { Complex::from_raw(raw) });
let mut guard = SplitOnDrop(combined, real, imag);
func(&mut guard.0);
}
pub const fn as_neg(&self) -> BorrowComplex<'_> {
let mut raw = self.inner;
raw.re.sign = -raw.re.sign;
raw.im.sign = -raw.im.sign;
unsafe { BorrowComplex::from_raw(raw) }
}
pub const fn as_conj(&self) -> BorrowComplex<'_> {
let mut raw = self.inner;
raw.im.sign = -raw.im.sign;
unsafe { BorrowComplex::from_raw(raw) }
}
pub const fn as_mul_i(&self, negative: bool) -> BorrowComplex<'_> {
let mut raw = mpc_t {
re: self.inner.im,
im: self.inner.re,
};
if negative {
raw.im.sign = -raw.im.sign;
} else {
raw.re.sign = -raw.re.sign;
}
unsafe { BorrowComplex::from_raw(raw) }
}
pub fn as_shl(&self, shift: i32) -> BorrowComplex<'_> {
let raw = mpc_t {
re: BorrowFloat::into_raw(self.real().as_shl(shift)),
im: BorrowFloat::into_raw(self.imag().as_shl(shift)),
};
unsafe { BorrowComplex::from_raw(raw) }
}
pub fn as_shr(&self, shift: i32) -> BorrowComplex<'_> {
let raw = mpc_t {
re: BorrowFloat::into_raw(self.real().as_shr(shift)),
im: BorrowFloat::into_raw(self.imag().as_shr(shift)),
};
unsafe { BorrowComplex::from_raw(raw) }
}
#[inline]
pub const fn as_ord(&self) -> &OrdComplex {
unsafe { &*misc::cast_ptr(self) }
}
#[inline]
pub const fn is_zero(&self) -> bool {
self.real().is_zero() && self.imag().is_zero()
}
#[inline]
pub fn cmp_abs(&self, other: &Self) -> Option<Ordering> {
if self.real().is_nan()
|| self.imag().is_nan()
|| other.real().is_nan()
|| other.imag().is_nan()
{
None
} else {
Some(xmpc::cmp_abs(self, other))
}
}
#[inline]
pub fn total_cmp(&self, other: &Complex) -> Ordering {
self.real()
.total_cmp(other.real())
.then_with(|| self.imag().total_cmp(other.imag()))
}
#[inline]
pub fn sum<'a, I>(values: I) -> SumIncomplete<'a, I>
where
I: Iterator<Item = &'a Self>,
{
SumIncomplete { values }
}
#[inline]
pub fn dot<'a, I>(values: I) -> DotIncomplete<'a, I>
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
DotIncomplete { values }
}
#[inline]
#[must_use]
pub fn mul_add(mut self, mul: &Self, add: &Self) -> Self {
self.mul_add_round(mul, add, NEAREST2);
self
}
#[inline]
pub fn mul_add_mut(&mut self, mul: &Self, add: &Self) {
self.mul_add_round(mul, add, NEAREST2);
}
#[inline]
pub fn mul_add_round(&mut self, mul: &Self, add: &Self, round: Round2) -> Ordering2 {
xmpc::fma(self, (), mul, add, round)
}
#[inline]
pub fn mul_add_ref<'a>(&'a self, mul: &'a Self, add: &'a Self) -> AddMulIncomplete<'a> {
self * mul + add
}
#[inline]
#[must_use]
pub fn mul_sub(mut self, mul: &Self, sub: &Self) -> Self {
self.mul_sub_round(mul, sub, NEAREST2);
self
}
#[inline]
pub fn mul_sub_mut(&mut self, mul: &Self, sub: &Self) {
self.mul_sub_round(mul, sub, NEAREST2);
}
#[inline]
pub fn mul_sub_round(&mut self, mul: &Self, sub: &Self, round: Round2) -> Ordering2 {
xmpc::fma(self, (), mul, &*sub.as_neg(), round)
}
#[inline]
pub fn mul_sub_ref<'a>(&'a self, mul: &'a Self, sub: &'a Self) -> SubMulFromIncomplete<'a> {
self * mul - sub
}
#[inline]
#[must_use]
pub fn proj(mut self) -> Self {
self.proj_mut();
self
}
#[inline]
pub fn proj_mut(&mut self) {
xmpc::proj(self, (), NEAREST2);
}
#[inline]
pub fn proj_ref(&self) -> ProjIncomplete<'_> {
ProjIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn square(mut self) -> Self {
self.square_round(NEAREST2);
self
}
#[inline]
pub fn square_mut(&mut self) {
self.square_round(NEAREST2);
}
#[inline]
pub fn square_round(&mut self, round: Round2) -> Ordering2 {
xmpc::sqr(self, (), round)
}
#[inline]
pub fn square_ref(&self) -> SquareIncomplete<'_> {
SquareIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn sqrt(mut self) -> Self {
self.sqrt_round(NEAREST2);
self
}
#[inline]
pub fn sqrt_mut(&mut self) {
self.sqrt_round(NEAREST2);
}
#[inline]
pub fn sqrt_round(&mut self, round: Round2) -> Ordering2 {
xmpc::sqrt(self, (), round)
}
#[inline]
pub fn sqrt_ref(&self) -> SqrtIncomplete<'_> {
SqrtIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn conj(mut self) -> Self {
self.conj_mut();
self
}
#[inline]
pub fn conj_mut(&mut self) {
xmpc::conj(self, (), NEAREST2);
}
#[inline]
pub fn conj_ref(&self) -> ConjIncomplete<'_> {
ConjIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn abs(mut self) -> Self {
self.abs_mut();
self
}
#[inline]
pub fn abs_mut(&mut self) {
self.abs_round(NEAREST2);
}
#[inline]
pub fn abs_round(&mut self, round: Round2) -> Ordering2 {
let (real, imag) = self.as_mut_real_imag();
let dir_re = real.hypot_round(imag, round.0);
let dir_im = imag.assign_round(Special::Zero, round.1);
(dir_re, dir_im)
}
#[inline]
pub fn abs_ref(&self) -> AbsIncomplete<'_> {
AbsIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn arg(mut self) -> Self {
self.arg_round(NEAREST2);
self
}
#[inline]
pub fn arg_mut(&mut self) {
self.arg_round(NEAREST2);
}
#[inline]
pub fn arg_round(&mut self, round: Round2) -> Ordering2 {
let (re, im) = self.as_mut_real_imag();
let dir_re = xmpfr::atan2(re, &*im, (), round.0);
im.assign(Special::Zero);
(dir_re, Ordering::Equal)
}
#[inline]
pub fn arg_ref(&self) -> ArgIncomplete<'_> {
ArgIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn mul_i(mut self, negative: bool) -> Self {
self.mul_i_round(negative, NEAREST2);
self
}
#[inline]
pub fn mul_i_mut(&mut self, negative: bool) {
self.mul_i_round(negative, NEAREST2);
}
#[inline]
pub fn mul_i_round(&mut self, negative: bool, round: Round2) -> Ordering2 {
xmpc::mul_i(self, (), negative, round)
}
#[inline]
pub fn mul_i_ref(&self, negative: bool) -> MulIIncomplete<'_> {
MulIIncomplete {
ref_self: self,
negative,
}
}
#[inline]
#[must_use]
pub fn recip(mut self) -> Self {
self.recip_round(NEAREST2);
self
}
#[inline]
pub fn recip_mut(&mut self) {
self.recip_round(NEAREST2);
}
#[inline]
pub fn recip_round(&mut self, round: Round2) -> Ordering2 {
xmpc::recip(self, (), round)
}
#[inline]
pub fn recip_ref(&self) -> RecipIncomplete<'_> {
RecipIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn norm(mut self) -> Self {
self.norm_round(NEAREST2);
self
}
#[inline]
pub fn norm_mut(&mut self) {
self.norm_round(NEAREST2);
}
#[inline]
pub fn norm_round(&mut self, round: Round2) -> Ordering2 {
let (norm, dir_re) = Float::with_val_round(self.real().prec(), self.norm_ref(), round.0);
let (real, imag) = self.as_mut_real_imag();
*real = norm;
let dir_im = imag.assign_round(Special::Zero, round.1);
(dir_re, dir_im)
}
#[inline]
pub fn norm_ref(&self) -> NormIncomplete<'_> {
NormIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn ln(mut self) -> Self {
self.ln_round(NEAREST2);
self
}
#[inline]
pub fn ln_mut(&mut self) {
self.ln_round(NEAREST2);
}
#[inline]
pub fn ln_round(&mut self, round: Round2) -> Ordering2 {
xmpc::log(self, (), round)
}
#[inline]
pub fn ln_ref(&self) -> LnIncomplete<'_> {
LnIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn log2(mut self) -> Self {
self.log2_round(NEAREST2);
self
}
#[inline]
pub fn log2_mut(&mut self) {
self.log2_round(NEAREST2);
}
#[inline]
pub fn log2_round(&mut self, round: Round2) -> Ordering2 {
xmpc::log2(self, (), round)
}
#[inline]
pub fn log2_ref(&self) -> Log2Incomplete<'_> {
Log2Incomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn log10(mut self) -> Self {
self.log10_round(NEAREST2);
self
}
#[inline]
pub fn log10_mut(&mut self) {
self.log10_round(NEAREST2);
}
#[inline]
pub fn log10_round(&mut self, round: Round2) -> Ordering2 {
xmpc::log10(self, (), round)
}
#[inline]
pub fn log10_ref(&self) -> Log10Incomplete<'_> {
Log10Incomplete { ref_self: self }
}
#[inline]
pub fn root_of_unity(n: u32, k: u32) -> RootOfUnityIncomplete {
RootOfUnityIncomplete { n, k }
}
#[inline]
#[must_use]
pub fn exp(mut self) -> Self {
self.exp_round(NEAREST2);
self
}
#[inline]
pub fn exp_mut(&mut self) {
self.exp_round(NEAREST2);
}
#[inline]
pub fn exp_round(&mut self, round: Round2) -> Ordering2 {
xmpc::exp(self, (), round)
}
#[inline]
pub fn exp_ref(&self) -> ExpIncomplete<'_> {
ExpIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn exp2(mut self) -> Self {
self.exp2_round(NEAREST2);
self
}
#[inline]
pub fn exp2_mut(&mut self) {
self.exp2_round(NEAREST2);
}
#[inline]
pub fn exp2_round(&mut self, round: Round2) -> Ordering2 {
xmpc::exp2(self, (), round)
}
#[inline]
pub fn exp2_ref(&self) -> Exp2Incomplete<'_> {
Exp2Incomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn exp10(mut self) -> Self {
self.exp10_round(NEAREST2);
self
}
#[inline]
pub fn exp10_mut(&mut self) {
self.exp10_round(NEAREST2);
}
#[inline]
pub fn exp10_round(&mut self, round: Round2) -> Ordering2 {
xmpc::exp10(self, (), round)
}
#[inline]
pub fn exp10_ref(&self) -> Exp10Incomplete<'_> {
Exp10Incomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn sin(mut self) -> Self {
self.sin_round(NEAREST2);
self
}
#[inline]
pub fn sin_mut(&mut self) {
self.sin_round(NEAREST2);
}
#[inline]
pub fn sin_round(&mut self, round: Round2) -> Ordering2 {
xmpc::sin(self, (), round)
}
#[inline]
pub fn sin_ref(&self) -> SinIncomplete<'_> {
SinIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn cos(mut self) -> Self {
self.cos_round(NEAREST2);
self
}
#[inline]
pub fn cos_mut(&mut self) {
self.cos_round(NEAREST2);
}
#[inline]
pub fn cos_round(&mut self, round: Round2) -> Ordering2 {
xmpc::cos(self, (), round)
}
#[inline]
pub fn cos_ref(&self) -> CosIncomplete<'_> {
CosIncomplete { ref_self: self }
}
#[inline]
pub fn sin_cos(mut self, mut cos: Self) -> (Self, Self) {
self.sin_cos_round(&mut cos, NEAREST2);
(self, cos)
}
#[inline]
pub fn sin_cos_mut(&mut self, cos: &mut Self) {
self.sin_cos_round(cos, NEAREST2);
}
#[inline]
pub fn sin_cos_round(&mut self, cos: &mut Self, round: Round2) -> (Ordering2, Ordering2) {
xmpc::sin_cos(self, cos, (), round)
}
#[inline]
pub fn sin_cos_ref(&self) -> SinCosIncomplete<'_> {
SinCosIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn tan(mut self) -> Self {
self.tan_round(NEAREST2);
self
}
#[inline]
pub fn tan_mut(&mut self) {
self.tan_round(NEAREST2);
}
#[inline]
pub fn tan_round(&mut self, round: Round2) -> Ordering2 {
xmpc::tan(self, (), round)
}
#[inline]
pub fn tan_ref(&self) -> TanIncomplete<'_> {
TanIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn sinh(mut self) -> Self {
self.sinh_round(NEAREST2);
self
}
#[inline]
pub fn sinh_mut(&mut self) {
self.sinh_round(NEAREST2);
}
#[inline]
pub fn sinh_round(&mut self, round: Round2) -> Ordering2 {
xmpc::sinh(self, (), round)
}
#[inline]
pub fn sinh_ref(&self) -> SinhIncomplete<'_> {
SinhIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn cosh(mut self) -> Self {
self.cosh_round(NEAREST2);
self
}
#[inline]
pub fn cosh_mut(&mut self) {
self.cosh_round(NEAREST2);
}
#[inline]
pub fn cosh_round(&mut self, round: Round2) -> Ordering2 {
xmpc::cosh(self, (), round)
}
#[inline]
pub fn cosh_ref(&self) -> CoshIncomplete<'_> {
CoshIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn tanh(mut self) -> Self {
self.tanh_round(NEAREST2);
self
}
#[inline]
pub fn tanh_mut(&mut self) {
self.tanh_round(NEAREST2);
}
#[inline]
pub fn tanh_round(&mut self, round: Round2) -> Ordering2 {
xmpc::tanh(self, (), round)
}
#[inline]
pub fn tanh_ref(&self) -> TanhIncomplete<'_> {
TanhIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn asin(mut self) -> Self {
self.asin_round(NEAREST2);
self
}
#[inline]
pub fn asin_mut(&mut self) {
self.asin_round(NEAREST2);
}
#[inline]
pub fn asin_round(&mut self, round: Round2) -> Ordering2 {
xmpc::asin(self, (), round)
}
#[inline]
pub fn asin_ref(&self) -> AsinIncomplete<'_> {
AsinIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn acos(mut self) -> Self {
self.acos_round(NEAREST2);
self
}
#[inline]
pub fn acos_mut(&mut self) {
self.acos_round(NEAREST2);
}
#[inline]
pub fn acos_round(&mut self, round: Round2) -> Ordering2 {
xmpc::acos(self, (), round)
}
#[inline]
pub fn acos_ref(&self) -> AcosIncomplete<'_> {
AcosIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn atan(mut self) -> Self {
self.atan_round(NEAREST2);
self
}
#[inline]
pub fn atan_mut(&mut self) {
self.atan_round(NEAREST2);
}
#[inline]
pub fn atan_round(&mut self, round: Round2) -> Ordering2 {
xmpc::atan(self, (), round)
}
#[inline]
pub fn atan_ref(&self) -> AtanIncomplete<'_> {
AtanIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn asinh(mut self) -> Self {
self.asinh_round(NEAREST2);
self
}
#[inline]
pub fn asinh_mut(&mut self) {
self.asinh_round(NEAREST2);
}
#[inline]
pub fn asinh_round(&mut self, round: Round2) -> Ordering2 {
xmpc::asinh(self, (), round)
}
#[inline]
pub fn asinh_ref(&self) -> AsinhIncomplete<'_> {
AsinhIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn acosh(mut self) -> Self {
self.acosh_round(NEAREST2);
self
}
#[inline]
pub fn acosh_mut(&mut self) {
self.acosh_round(NEAREST2);
}
#[inline]
pub fn acosh_round(&mut self, round: Round2) -> Ordering2 {
xmpc::acosh(self, (), round)
}
#[inline]
pub fn acosh_ref(&self) -> AcoshIncomplete<'_> {
AcoshIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn atanh(mut self) -> Self {
self.atanh_round(NEAREST2);
self
}
#[inline]
pub fn atanh_mut(&mut self) {
self.atanh_round(NEAREST2);
}
#[inline]
pub fn atanh_round(&mut self, round: Round2) -> Ordering2 {
xmpc::atanh(self, (), round)
}
#[inline]
pub fn atanh_ref(&self) -> AtanhIncomplete<'_> {
AtanhIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn agm(mut self, other: &Self) -> Self {
self.agm_round(other, NEAREST2);
self
}
#[inline]
pub fn agm_mut(&mut self, other: &Self) {
self.agm_round(other, NEAREST2);
}
#[inline]
pub fn agm_round(&mut self, other: &Self, round: Round2) -> Ordering2 {
xmpc::agm(self, (), other, round)
}
#[inline]
pub fn agm_ref<'a>(&'a self, other: &'a Self) -> AgmIncomplete<'a> {
AgmIncomplete {
ref_self: self,
other,
}
}
#[cfg(feature = "rand")]
#[inline]
pub fn random_bits(rng: &mut dyn MutRandState) -> RandomBitsIncomplete<'_> {
RandomBitsIncomplete { rng }
}
#[cfg(feature = "rand")]
#[inline]
pub fn random_cont(rng: &mut dyn MutRandState) -> RandomContIncomplete<'_> {
RandomContIncomplete { rng }
}
#[deprecated(since = "1.22.0", note = "renamed to `is_zero`")]
#[inline]
pub const fn eq0(&self) -> bool {
self.is_zero()
}
}
#[derive(Debug)]
pub struct SumIncomplete<'a, I>
where
I: Iterator<Item = &'a Complex>,
{
values: I,
}
impl<'a, I> AssignRound<SumIncomplete<'a, I>> for Complex
where
I: Iterator<Item = &'a Self>,
{
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, src: SumIncomplete<'a, I>, round: Round2) -> Ordering2 {
xmpc::sum(self, src.values, round)
}
}
impl<'a, I> CompleteRound for SumIncomplete<'a, I>
where
I: Iterator<Item = &'a Complex>,
{
type Completed = Complex;
type Prec = (u32, u32);
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn complete_round(self, prec: (u32, u32), round: Round2) -> (Complex, Ordering2) {
Complex::with_val_round(prec, self, round)
}
}
impl<'a, I> Add<SumIncomplete<'a, I>> for Complex
where
I: Iterator<Item = &'a Self>,
{
type Output = Self;
#[inline]
fn add(mut self, rhs: SumIncomplete<'a, I>) -> Self {
self.add_assign_round(rhs, NEAREST2);
self
}
}
impl<'a, I> Add<Complex> for SumIncomplete<'a, I>
where
I: Iterator<Item = &'a Complex>,
{
type Output = Complex;
#[inline]
fn add(self, mut rhs: Complex) -> Complex {
rhs.add_assign_round(self, NEAREST2);
rhs
}
}
impl<'a, I> AddAssign<SumIncomplete<'a, I>> for Complex
where
I: Iterator<Item = &'a Self>,
{
#[inline]
fn add_assign(&mut self, rhs: SumIncomplete<'a, I>) {
self.add_assign_round(rhs, NEAREST2);
}
}
impl<'a, I> AddAssignRound<SumIncomplete<'a, I>> for Complex
where
I: Iterator<Item = &'a Self>,
{
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn add_assign_round(&mut self, src: SumIncomplete<'a, I>, round: Round2) -> Ordering2 {
xmpc::sum_including_old(self, src.values, round)
}
}
impl<'a, I> Sub<SumIncomplete<'a, I>> for Complex
where
I: Iterator<Item = &'a Self>,
{
type Output = Self;
#[inline]
fn sub(mut self, rhs: SumIncomplete<'a, I>) -> Self {
self.sub_assign_round(rhs, NEAREST2);
self
}
}
impl<'a, I> Sub<Complex> for SumIncomplete<'a, I>
where
I: Iterator<Item = &'a Complex>,
{
type Output = Complex;
#[inline]
fn sub(self, mut rhs: Complex) -> Complex {
rhs.sub_from_round(self, NEAREST2);
rhs
}
}
impl<'a, I> SubAssign<SumIncomplete<'a, I>> for Complex
where
I: Iterator<Item = &'a Self>,
{
#[inline]
fn sub_assign(&mut self, rhs: SumIncomplete<'a, I>) {
self.sub_assign_round(rhs, NEAREST2);
}
}
impl<'a, I> SubAssignRound<SumIncomplete<'a, I>> for Complex
where
I: Iterator<Item = &'a Self>,
{
type Round = Round2;
type Ordering = Ordering2;
fn sub_assign_round(&mut self, src: SumIncomplete<'a, I>, round: Round2) -> Ordering2 {
self.neg_assign();
let reverse_dir = self.add_assign_round(src, (round.0.reverse(), round.1.reverse()));
self.neg_assign();
(reverse_dir.0.reverse(), reverse_dir.1.reverse())
}
}
impl<'a, I> SubFrom<SumIncomplete<'a, I>> for Complex
where
I: Iterator<Item = &'a Self>,
{
#[inline]
fn sub_from(&mut self, rhs: SumIncomplete<'a, I>) {
self.sub_from_round(rhs, NEAREST2);
}
}
impl<'a, I> SubFromRound<SumIncomplete<'a, I>> for Complex
where
I: Iterator<Item = &'a Self>,
{
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn sub_from_round(&mut self, src: SumIncomplete<'a, I>, round: Round2) -> Ordering2 {
self.neg_assign();
self.add_assign_round(src, round)
}
}
#[derive(Debug)]
pub struct DotIncomplete<'a, I>
where
I: Iterator<Item = (&'a Complex, &'a Complex)>,
{
values: I,
}
impl<'a, I> AssignRound<DotIncomplete<'a, I>> for Complex
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
type Round = Round2;
type Ordering = Ordering2;
fn assign_round(&mut self, src: DotIncomplete<'a, I>, round: Round2) -> Ordering2 {
xmpc::dot(self, src.values, round)
}
}
impl<'a, I> CompleteRound for DotIncomplete<'a, I>
where
I: Iterator<Item = (&'a Complex, &'a Complex)>,
{
type Completed = Complex;
type Prec = (u32, u32);
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn complete_round(self, prec: (u32, u32), round: Round2) -> (Complex, Ordering2) {
Complex::with_val_round(prec, self, round)
}
}
impl<'a, I> Add<DotIncomplete<'a, I>> for Complex
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
type Output = Self;
#[inline]
fn add(mut self, rhs: DotIncomplete<'a, I>) -> Self {
self.add_assign_round(rhs, NEAREST2);
self
}
}
impl<'a, I> Add<Complex> for DotIncomplete<'a, I>
where
I: Iterator<Item = (&'a Complex, &'a Complex)>,
{
type Output = Complex;
#[inline]
fn add(self, mut rhs: Complex) -> Complex {
rhs.add_assign_round(self, NEAREST2);
rhs
}
}
impl<'a, I> AddAssign<DotIncomplete<'a, I>> for Complex
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
#[inline]
fn add_assign(&mut self, rhs: DotIncomplete<'a, I>) {
self.add_assign_round(rhs, NEAREST2);
}
}
impl<'a, I> AddAssignRound<DotIncomplete<'a, I>> for Complex
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
type Round = Round2;
type Ordering = Ordering2;
fn add_assign_round(&mut self, src: DotIncomplete<'a, I>, round: Round2) -> Ordering2 {
xmpc::dot_including_old(self, src.values, round)
}
}
impl<'a, I> Sub<DotIncomplete<'a, I>> for Complex
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
type Output = Self;
#[inline]
fn sub(mut self, rhs: DotIncomplete<'a, I>) -> Self {
self.sub_assign_round(rhs, NEAREST2);
self
}
}
impl<'a, I> Sub<Complex> for DotIncomplete<'a, I>
where
I: Iterator<Item = (&'a Complex, &'a Complex)>,
{
type Output = Complex;
#[inline]
fn sub(self, mut rhs: Complex) -> Complex {
rhs.sub_from_round(self, NEAREST2);
rhs
}
}
impl<'a, I> SubAssign<DotIncomplete<'a, I>> for Complex
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
#[inline]
fn sub_assign(&mut self, rhs: DotIncomplete<'a, I>) {
self.sub_assign_round(rhs, NEAREST2);
}
}
impl<'a, I> SubAssignRound<DotIncomplete<'a, I>> for Complex
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
type Round = Round2;
type Ordering = Ordering2;
fn sub_assign_round(&mut self, src: DotIncomplete<'a, I>, round: Round2) -> Ordering2 {
self.neg_assign();
let reverse_dir = self.add_assign_round(src, (round.0.reverse(), round.1.reverse()));
self.neg_assign();
(reverse_dir.0.reverse(), reverse_dir.1.reverse())
}
}
impl<'a, I> SubFrom<DotIncomplete<'a, I>> for Complex
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
#[inline]
fn sub_from(&mut self, rhs: DotIncomplete<'a, I>) {
self.sub_from_round(rhs, NEAREST2);
}
}
impl<'a, I> SubFromRound<DotIncomplete<'a, I>> for Complex
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn sub_from_round(&mut self, src: DotIncomplete<'a, I>, round: Round2) -> Ordering2 {
self.neg_assign();
self.add_assign_round(src, round)
}
}
ref_math_op1_complex! { xmpc::proj; struct ProjIncomplete {} }
ref_math_op1_complex! { xmpc::sqr; struct SquareIncomplete {} }
ref_math_op1_complex! { xmpc::sqrt; struct SqrtIncomplete {} }
ref_math_op1_complex! { xmpc::conj; struct ConjIncomplete {} }
#[derive(Debug)]
pub struct AbsIncomplete<'a> {
ref_self: &'a Complex,
}
impl AssignRound<AbsIncomplete<'_>> for Float {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(&mut self, src: AbsIncomplete<'_>, round: Round) -> Ordering {
xmpc::abs(self, src.ref_self, round)
}
}
impl CompleteRound for AbsIncomplete<'_> {
type Completed = Complex;
type Prec = (u32, u32);
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn complete_round(self, prec: (u32, u32), round: Round2) -> (Complex, Ordering2) {
Complex::with_val_round(prec, self, round)
}
}
#[derive(Debug)]
pub struct ArgIncomplete<'a> {
ref_self: &'a Complex,
}
impl AssignRound<ArgIncomplete<'_>> for Float {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(&mut self, src: ArgIncomplete<'_>, round: Round) -> Ordering {
xmpc::arg(self, src.ref_self, round)
}
}
impl CompleteRound for ArgIncomplete<'_> {
type Completed = Complex;
type Prec = (u32, u32);
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn complete_round(self, prec: (u32, u32), round: Round2) -> (Complex, Ordering2) {
Complex::with_val_round(prec, self, round)
}
}
ref_math_op1_complex! { xmpc::mul_i; struct MulIIncomplete { negative: bool } }
ref_math_op1_complex! { xmpc::recip; struct RecipIncomplete {} }
#[derive(Debug)]
pub struct NormIncomplete<'a> {
ref_self: &'a Complex,
}
impl AssignRound<NormIncomplete<'_>> for Float {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(&mut self, src: NormIncomplete<'_>, round: Round) -> Ordering {
xmpc::norm(self, src.ref_self, round)
}
}
impl CompleteRound for NormIncomplete<'_> {
type Completed = Complex;
type Prec = (u32, u32);
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn complete_round(self, prec: (u32, u32), round: Round2) -> (Complex, Ordering2) {
Complex::with_val_round(prec, self, round)
}
}
ref_math_op1_complex! { xmpc::log; struct LnIncomplete {} }
ref_math_op1_complex! { xmpc::log2; struct Log2Incomplete {} }
ref_math_op1_complex! { xmpc::log10; struct Log10Incomplete {} }
ref_math_op0_complex! { xmpc::rootofunity; struct RootOfUnityIncomplete { n: u32, k: u32 } }
ref_math_op1_complex! { xmpc::exp; struct ExpIncomplete {} }
ref_math_op1_complex! { xmpc::exp2; struct Exp2Incomplete {} }
ref_math_op1_complex! { xmpc::exp10; struct Exp10Incomplete {} }
ref_math_op1_complex! { xmpc::sin; struct SinIncomplete {} }
ref_math_op1_complex! { xmpc::cos; struct CosIncomplete {} }
ref_math_op1_2_complex! { xmpc::sin_cos; struct SinCosIncomplete {} }
ref_math_op1_complex! { xmpc::tan; struct TanIncomplete {} }
ref_math_op1_complex! { xmpc::sinh; struct SinhIncomplete {} }
ref_math_op1_complex! { xmpc::cosh; struct CoshIncomplete {} }
ref_math_op1_complex! { xmpc::tanh; struct TanhIncomplete {} }
ref_math_op1_complex! { xmpc::asin; struct AsinIncomplete {} }
ref_math_op1_complex! { xmpc::acos; struct AcosIncomplete {} }
ref_math_op1_complex! { xmpc::atan; struct AtanIncomplete {} }
ref_math_op1_complex! { xmpc::asinh; struct AsinhIncomplete {} }
ref_math_op1_complex! { xmpc::acosh; struct AcoshIncomplete {} }
ref_math_op1_complex! { xmpc::atanh; struct AtanhIncomplete {} }
ref_math_op2_complex! { xmpc::agm; struct AgmIncomplete { other } }
#[cfg(feature = "rand")]
pub struct RandomBitsIncomplete<'a> {
rng: &'a mut dyn MutRandState,
}
#[cfg(feature = "rand")]
impl AssignRound<RandomBitsIncomplete<'_>> for Complex {
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, src: RandomBitsIncomplete, round: Round2) -> Ordering2 {
let _ = round;
self.mut_real().assign(Float::random_bits(src.rng));
self.mut_imag().assign(Float::random_bits(src.rng));
(Ordering::Equal, Ordering::Equal)
}
}
#[cfg(feature = "rand")]
impl CompleteRound for RandomBitsIncomplete<'_> {
type Completed = Complex;
type Prec = (u32, u32);
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn complete_round(self, prec: (u32, u32), round: Round2) -> (Complex, Ordering2) {
Complex::with_val_round(prec, self, round)
}
}
#[cfg(feature = "rand")]
pub struct RandomContIncomplete<'a> {
rng: &'a mut dyn MutRandState,
}
#[cfg(feature = "rand")]
impl AssignRound<RandomContIncomplete<'_>> for Complex {
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, src: RandomContIncomplete, round: Round2) -> Ordering2 {
let real_dir = self
.mut_real()
.assign_round(Float::random_cont(src.rng), round.0);
let imag_dir = self
.mut_imag()
.assign_round(Float::random_cont(src.rng), round.1);
(real_dir, imag_dir)
}
}
#[cfg(feature = "rand")]
impl CompleteRound for RandomContIncomplete<'_> {
type Completed = Complex;
type Prec = (u32, u32);
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn complete_round(self, prec: (u32, u32), round: Round2) -> (Complex, Ordering2) {
Complex::with_val_round(prec, self, round)
}
}
#[derive(Clone, Copy)]
pub(crate) struct Format {
pub radix: i32,
pub precision: Option<usize>,
pub round: Round2,
pub to_upper: bool,
pub sign_plus: bool,
pub prefix: &'static str,
pub exp: ExpFormat,
}
impl Default for Format {
#[inline]
fn default() -> Format {
Format {
radix: 10,
precision: None,
round: Round2::default(),
to_upper: false,
sign_plus: false,
prefix: "",
exp: ExpFormat::Point,
}
}
}
pub(crate) fn append_to_string(s: &mut StringLike, c: &Complex, f: Format) {
let (re, im) = (c.real(), c.imag());
let re_plus = f.sign_plus && re.is_sign_positive();
let im_plus = f.sign_plus && im.is_sign_positive();
let re_prefix = !f.prefix.is_empty() && re.is_finite();
let im_prefix = !f.prefix.is_empty() && im.is_finite();
let extra = 3
+ usize::from(re_plus)
+ usize::from(im_plus)
+ if re_prefix { f.prefix.len() } else { 0 }
+ if im_prefix { f.prefix.len() } else { 0 };
let ff = FloatFormat {
radix: f.radix,
precision: f.precision,
round: f.round.0,
to_upper: f.to_upper,
exp: f.exp,
};
let cap = big_float::req_chars(re, ff, extra);
let cap = big_float::req_chars(im, ff, cap);
s.reserve(cap);
let reserved_ptr = s.as_str().as_ptr();
s.push_str("(");
if re_plus {
s.push_str("+");
}
let prefix_start = s.as_str().len();
if re_prefix {
s.push_str(f.prefix);
}
let prefix_end = s.as_str().len();
big_float::append_to_string(s, re, ff);
if re_prefix && s.as_str().as_bytes()[prefix_end] == b'-' {
unsafe {
let bytes = slice::from_raw_parts_mut(s.as_mut_str().as_mut_ptr(), s.as_str().len());
bytes[prefix_start] = b'-';
bytes[prefix_start + 1..=prefix_end].copy_from_slice(f.prefix.as_bytes());
}
}
s.push_str(" ");
if im_plus {
s.push_str("+");
}
let prefix_start = s.as_str().len();
if im_prefix {
s.push_str(f.prefix);
}
let prefix_end = s.as_str().len();
let ff = FloatFormat {
round: f.round.1,
..ff
};
big_float::append_to_string(s, im, ff);
if im_prefix && s.as_str().as_bytes()[prefix_end] == b'-' {
unsafe {
let bytes = slice::from_raw_parts_mut(s.as_mut_str().as_mut_ptr(), s.as_str().len());
bytes[prefix_start] = b'-';
bytes[prefix_start + 1..=prefix_end].copy_from_slice(f.prefix.as_bytes());
}
}
s.push_str(")");
debug_assert_eq!(reserved_ptr, s.as_str().as_ptr());
}
#[derive(Debug)]
pub enum ParseIncomplete {
Real(FloatParseIncomplete),
Complex(FloatParseIncomplete, FloatParseIncomplete),
}
impl AssignRound<ParseIncomplete> for Complex {
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, src: ParseIncomplete, round: Round2) -> Ordering2 {
match src {
ParseIncomplete::Real(re) => {
let real_ord = self.mut_real().assign_round(re, round.0);
self.mut_imag().assign(Special::Zero);
(real_ord, Ordering::Equal)
}
ParseIncomplete::Complex(re, im) => {
let real_ord = self.mut_real().assign_round(re, round.0);
let imag_ord = self.mut_imag().assign_round(im, round.1);
(real_ord, imag_ord)
}
}
}
}
impl CompleteRound for ParseIncomplete {
type Completed = Complex;
type Prec = (u32, u32);
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn complete_round(self, prec: (u32, u32), round: Round2) -> (Complex, Ordering2) {
Complex::with_val_round(prec, self, round)
}
}
macro_rules! parse_error {
($kind:expr) => {
Err(ParseComplexError { kind: $kind })
};
}
fn parse(mut bytes: &[u8], radix: i32) -> Result<ParseIncomplete, ParseComplexError> {
bytes = misc::trim_start(bytes);
bytes = misc::trim_end(bytes);
if bytes.is_empty() {
return parse_error!(ParseErrorKind::NoDigits);
}
if let Some((inside, remainder)) = misc::matched_brackets(bytes) {
if !misc::trim_start(remainder).is_empty() {
return parse_error!(ParseErrorKind::CloseNotLast);
}
bytes = misc::trim_start(inside);
bytes = misc::trim_end(bytes);
} else {
return match Float::parse_radix(bytes, radix) {
Ok(re) => Ok(ParseIncomplete::Real(re)),
Err(e) => parse_error!(ParseErrorKind::InvalidFloat(e)),
};
};
let (real, imag) = if let Some(comma) = misc::find_outside_brackets(bytes, b',') {
let real = misc::trim_end(&bytes[..comma]);
if real.is_empty() {
return parse_error!(ParseErrorKind::NoRealDigits);
}
let imag = misc::trim_start(&bytes[comma + 1..]);
if imag.is_empty() {
return parse_error!(ParseErrorKind::NoImagDigits);
}
if misc::find_outside_brackets(imag, b',').is_some() {
return parse_error!(ParseErrorKind::MultipleSeparators);
}
(real, imag)
} else if let Some(space) = misc::find_space_outside_brackets(bytes) {
let real = &bytes[..space];
assert!(!real.is_empty());
let imag = misc::trim_start(&bytes[space + 1..]);
assert!(!imag.is_empty());
if misc::find_space_outside_brackets(imag).is_some() {
return parse_error!(ParseErrorKind::MultipleSeparators);
}
(real, imag)
} else {
return parse_error!(ParseErrorKind::MissingSeparator);
};
let re = match Float::parse_radix(real, radix) {
Ok(re) => re,
Err(e) => return parse_error!(ParseErrorKind::InvalidRealFloat(e)),
};
let im = match Float::parse_radix(imag, radix) {
Ok(im) => im,
Err(e) => return parse_error!(ParseErrorKind::InvalidImagFloat(e)),
};
Ok(ParseIncomplete::Complex(re, im))
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ParseComplexError {
kind: ParseErrorKind,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum ParseErrorKind {
NoDigits,
NoRealDigits,
NoImagDigits,
InvalidFloat(ParseFloatError),
InvalidRealFloat(ParseFloatError),
InvalidImagFloat(ParseFloatError),
MissingSeparator,
MultipleSeparators,
CloseNotLast,
}
impl Display for ParseComplexError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
use self::ParseErrorKind::*;
match &self.kind {
NoDigits => Display::fmt("string has no digits", f),
NoRealDigits => Display::fmt("string has no real digits", f),
NoImagDigits => Display::fmt("string has no imaginary digits", f),
InvalidFloat(e) => {
Display::fmt("string is not a valid float: ", f)?;
Display::fmt(e, f)
}
InvalidRealFloat(e) => {
Display::fmt("real part of string is not a valid float: ", f)?;
Display::fmt(e, f)
}
InvalidImagFloat(e) => {
Display::fmt("imaginary part of string is not a valid float: ", f)?;
Display::fmt(e, f)
}
MissingSeparator => Display::fmt("string has no separator inside brackets", f),
MultipleSeparators => {
Display::fmt("string has more than one separator inside brackets", f)
}
CloseNotLast => Display::fmt("string has more characters after closing bracket", f),
}
}
}
impl Error for ParseComplexError {
#[allow(deprecated)]
fn description(&self) -> &str {
use self::ParseErrorKind::*;
match self.kind {
NoDigits => "string has no digits",
NoRealDigits => "string has no real digits",
NoImagDigits => "string has no imaginary digits",
InvalidFloat(_) => "string is not a valid float",
InvalidRealFloat(_) => "real part of string is not a valid float",
InvalidImagFloat(_) => "imaginary part of string is not a valid float",
MissingSeparator => "string has no separator inside brackets",
MultipleSeparators => "string has more than one separator inside brackets",
CloseNotLast => "string has more characters after closing bracket",
}
}
}