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