extendr_api/scalar/
rcplx_full.rs
1use crate::scalar::macros::*;
2use crate::scalar::{Rfloat, Scalar};
3use crate::*;
4use extendr_ffi::{R_IsNA, R_NaReal, Rcomplex};
5use std::convert::TryFrom;
6use std::ops::{Add, Div, Mul, Neg, Sub};
7use std::ops::{AddAssign, DivAssign, MulAssign, SubAssign};
8
9#[allow(non_camel_case_types)]
10pub type c64 = num_complex::Complex<f64>;
11
12impl CanBeNA for c64 {
13 fn is_na(&self) -> bool {
14 unsafe { R_IsNA(self.re) != 0 }
15 }
16
17 fn na() -> c64 {
18 unsafe { c64::new(R_NaReal, R_NaReal) }
19 }
20}
21
22#[repr(transparent)]
28pub struct Rcplx(c64);
29
30impl Scalar<c64> for Rcplx {
31 fn inner(&self) -> c64 {
32 self.0
33 }
34
35 fn new(val: c64) -> Self {
36 Rcplx(val)
37 }
38}
39
40impl Rcplx {
41 pub fn new(re: f64, im: f64) -> Self {
42 Self(c64::new(re, im))
43 }
44
45 pub fn is_nan(&self) -> bool {
46 self.0.is_nan()
47 }
48
49 pub fn is_infinite(&self) -> bool {
50 self.0.is_infinite()
51 }
52
53 pub fn re(&self) -> Rfloat {
54 Rfloat::from(self.0.re)
55 }
56
57 pub fn im(&self) -> Rfloat {
58 Rfloat::from(self.0.im)
59 }
60}
61
62impl From<f64> for Rcplx {
63 fn from(val: f64) -> Self {
64 Rcplx(c64::from(val))
65 }
66}
67
68impl From<(f64, f64)> for Rcplx {
69 fn from(val: (f64, f64)) -> Self {
70 Rcplx(c64::new(val.0, val.1))
71 }
72}
73
74impl From<(Rfloat, Rfloat)> for Rcplx {
75 fn from(val: (Rfloat, Rfloat)) -> Self {
76 Rcplx(c64::new(val.0.inner(), val.1.inner()))
77 }
78}
79
80impl From<Rfloat> for Rcplx {
81 fn from(val: Rfloat) -> Self {
82 Rcplx(c64::from(val.inner()))
83 }
84}
85
86impl From<Rcomplex> for Rcplx {
87 fn from(val: Rcomplex) -> Self {
88 Rcplx(c64::new(val.r, val.i))
89 }
90}
91
92impl From<Rcplx> for Option<c64> {
93 fn from(val: Rcplx) -> Self {
94 if val.is_na() {
95 None
96 } else {
97 Some(c64::new(val.re().inner(), val.im().inner()))
98 }
99 }
100}
101
102gen_trait_impl!(Rcplx, c64, |x: &Rcplx| x.inner().re.is_na(), c64::na());
105gen_from_primitive!(Rcplx, c64);
106gen_sum_iter!(Rcplx);
108
109gen_binop!(
111 Rcplx,
112 c64,
113 Add,
114 |lhs: c64, rhs: c64| Some(lhs + rhs),
115 "Add two Rcplx values or an option of c64."
116);
117gen_binop!(
118 Rcplx,
119 c64,
120 Sub,
121 |lhs: c64, rhs: c64| Some(lhs - rhs),
122 "Subtract two Rcplx values or an option of c64."
123);
124gen_binop!(
125 Rcplx,
126 c64,
127 Mul,
128 |lhs: c64, rhs: c64| Some(lhs * rhs),
129 "Multiply two Rcplx values or an option of c64."
130);
131gen_binop!(
132 Rcplx,
133 c64,
134 Div,
135 |lhs: c64, rhs: c64| Some(lhs / rhs),
136 "Divide two Rcplx values or an option of c64."
137);
138gen_binopassign!(
139 Rcplx,
140 c64,
141 AddAssign,
142 |lhs: c64, rhs: c64| Some(lhs + rhs),
143 "Add two Rcplx values or an option of c64, modifying the left-hand side in place. Overflows to NA."
144);
145gen_binopassign!(
146 Rcplx,
147 c64,
148 SubAssign,
149 |lhs: c64, rhs: c64| Some(lhs - rhs),
150 "Subtract two Rcplx values or an option of c64, modifying the left-hand side in place. Overflows to NA."
151);
152gen_binopassign!(
153 Rcplx,
154 c64,
155 MulAssign,
156 |lhs: c64, rhs: c64| Some(lhs * rhs),
157 "Multiply two Rcplx values or an option of c64, modifying the left-hand side in place. Overflows to NA."
158);
159gen_binopassign!(
160 Rcplx,
161 c64,
162 DivAssign,
163 |lhs: c64, rhs: c64| Some(lhs / rhs),
164 "Divide two Rcplx values or an option of c64, modifying the left-hand side in place. Overflows to NA."
165);
166
167gen_unop!(Rcplx, Neg, |lhs: c64| Some(-lhs), "Negate a Rcplx value.");
169
170impl PartialEq<f64> for Rcplx {
171 fn eq(&self, other: &f64) -> bool {
172 self.re().inner() == *other && self.im() == 0.0
173 }
174}
175
176impl std::fmt::Debug for Rcplx {
177 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
178 if self.is_na() {
179 write!(f, "NA_COMPLEX")
180 } else {
181 write!(
182 f,
183 "{:?} {} {:?}i",
184 self.re(),
185 if self.im().is_sign_negative() {
186 '-'
187 } else {
188 '+'
189 },
190 self.im().abs()
191 )
192 }
193 }
194}