use crate::beve;
use crate::beve::header;
use crate::beve::impls::NumericBytes;
use crate::error::{ErrorCode, PResult};
use crate::json;
use crate::options::Options;
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct Complex<T> {
pub re: T,
pub im: T,
}
impl<T> Complex<T> {
#[inline]
pub const fn new(re: T, im: T) -> Self {
Complex { re, im }
}
}
impl<T> From<(T, T)> for Complex<T> {
#[inline]
fn from((re, im): (T, T)) -> Self {
Complex { re, im }
}
}
impl<T> From<Complex<T>> for (T, T) {
#[inline]
fn from(z: Complex<T>) -> Self {
(z.re, z.im)
}
}
fn read_beve<'de, O: Options, T: beve::Read<'de>>(
z: &mut Complex<T>,
r: &mut beve::Reader<'de, O>,
) -> PResult<()> {
match r.complex_form()? {
Some(elem) => r.complex_pair(elem, &mut z.re, &mut z.im),
None => {
let n = r.read_seq(|r, i| match i {
0 => beve::Read::read(&mut z.re, r),
1 => beve::Read::read(&mut z.im, r),
_ => Err(ErrorCode::ExpectedComplex),
})?;
if n == 2 {
Ok(())
} else {
Err(ErrorCode::ExpectedComplex)
}
}
}
}
fn read_json<'de, O: Options, T: json::Read<'de>>(
z: &mut Complex<T>,
p: &mut json::Parser<'de, O>,
) -> PResult<()> {
let n = p.read_seq(|p, i| match i {
0 => json::Read::read(&mut z.re, p),
1 => json::Read::read(&mut z.im, p),
_ => Err(ErrorCode::ExpectedComplex),
})?;
if n == 2 {
Ok(())
} else {
Err(ErrorCode::ExpectedComplex)
}
}
fn write_json<O: Options, T: json::Write>(z: &Complex<T>, w: &mut json::Writer<'_, O>) {
w.open(b'[');
w.element(&z.re);
w.element(&z.im);
w.close(b']');
}
macro_rules! impl_complex {
($($t:ty, $cat:expr, $code:expr);* $(;)?) => {$(
const _: () = {
assert!(size_of::<Complex<$t>>() == 2 * size_of::<$t>());
assert!(align_of::<Complex<$t>>() == align_of::<$t>());
};
unsafe impl NumericBytes for Complex<$t> {
const ELEMENT: u8 = header::complex_element(<$t as NumericBytes>::ELEMENT);
}
impl<'de> beve::Read<'de> for Complex<$t> {
#[inline]
fn read<O: Options>(&mut self, r: &mut beve::Reader<'de, O>) -> PResult<()> {
read_beve(self, r)
}
fn read_bulk<O: Options>(
out: &mut Vec<Self>,
n: usize,
elem: u8,
r: &mut beve::Reader<'de, O>,
) -> PResult<bool> {
if elem != <Self as NumericBytes>::ELEMENT || cfg!(target_endian = "big") {
return Ok(false);
}
r.read_block(out, n)?;
Ok(true)
}
}
impl beve::Write for Complex<$t> {
const ARRAY: Option<&'static [u8]> = Some(&[
header::COMPLEX,
header::complex_class($cat, $code, header::COMPLEX_MANY),
]);
#[inline]
fn write<O: Options>(&self, w: &mut beve::Writer<'_, O>) {
const CLASS: u8 = header::complex_class($cat, $code, header::COMPLEX_ONE);
w.write_complex(CLASS, self.re.to_le_bytes(), self.im.to_le_bytes());
}
fn write_payload<O: Options>(items: &[Self], w: &mut beve::Writer<'_, O>) {
if cfg!(target_endian = "little") {
w.write_block(items)
} else {
for z in items {
w.raw(&z.re.to_le_bytes());
w.raw(&z.im.to_le_bytes());
}
}
}
}
impl<'de> json::Read<'de> for Complex<$t> {
#[inline]
fn read<O: Options>(&mut self, p: &mut json::Parser<'de, O>) -> PResult<()> {
read_json(self, p)
}
}
impl json::Write for Complex<$t> {
#[inline]
fn write<O: Options>(&self, w: &mut json::Writer<'_, O>) {
write_json(self, w);
}
}
)*}
}
impl_complex! {
f32, header::CAT_FLOAT, 2;
f64, header::CAT_FLOAT, 3;
i8, header::CAT_SIGNED, header::code_for(1);
i16, header::CAT_SIGNED, header::code_for(2);
i32, header::CAT_SIGNED, header::code_for(4);
i64, header::CAT_SIGNED, header::code_for(8);
i128, header::CAT_SIGNED, header::code_for(16);
u8, header::CAT_UNSIGNED, header::code_for(1);
u16, header::CAT_UNSIGNED, header::code_for(2);
u32, header::CAT_UNSIGNED, header::code_for(4);
u64, header::CAT_UNSIGNED, header::code_for(8);
u128, header::CAT_UNSIGNED, header::code_for(16);
}