Skip to main content

wolfram_serialize/
complex.rs

1//! Complex number primitives suitable as element types of [`NumericArray`] and
2//! [`PackedArray`][crate::PackedArray].
3//!
4//! [`Complex64`] is byte-layout-compatible with the C ABI's `_Complex double`
5//! (and thus `wolfram_library_link_sys::mcomplex`, which re-exports this same
6//! type via `pub use`). [`Complex32`] is the `_Complex float` analog.
7//!
8//! Both types are `#[repr(C)]` with two interleaved real/imaginary scalar fields,
9//! matching WXF's wire layout for `ComplexReal{32,64}` array elements.
10//!
11//! [`NumericArray`]: crate::NumericArray
12
13/// Generic complex number — pair of identical scalars `(re, im)` with
14/// C-compatible interleaved layout. Use the [`Complex64`] / [`Complex32`]
15/// aliases in code; this generic exists so the impl block and layout
16/// invariants are written once.
17#[repr(C)]
18#[derive(Debug, Copy, Clone, PartialEq, Default)]
19pub struct Complex<F> {
20    /// Real part.
21    pub re: F,
22    /// Imaginary part.
23    pub im: F,
24}
25
26impl<F> Complex<F> {
27    /// Construct from `(real, imaginary)` parts.
28    pub const fn new(re: F, im: F) -> Self {
29        Complex { re, im }
30    }
31}
32
33impl<F: Copy> Complex<F> {
34    /// Real part.
35    pub const fn re(self) -> F {
36        self.re
37    }
38    /// Imaginary part.
39    pub const fn im(self) -> F {
40        self.im
41    }
42}
43
44/// Single 64-bit complex number — pair of `f64` (real, imaginary).
45///
46/// Layout matches the C ABI `_Complex double` and the WXF `ComplexReal64`
47/// element wire format. `wolfram-library-link-sys::mcomplex` is `pub use`'d as
48/// an alias for this type, so `wll::NumericArray<sys::mcomplex>` and
49/// `wll::NumericArray<wolfram_expr::Complex64>` are the same instantiation.
50pub type Complex64 = Complex<f64>;
51
52/// Single 32-bit complex number — pair of `f32` (real, imaginary). Layout matches
53/// the WXF `ComplexReal32` element wire format. No `_Complex float` typedef
54/// exists in `WolframLibrary.h`, so this type is wolfram-expr-only.
55pub type Complex32 = Complex<f32>;
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60    use std::convert::TryInto;
61
62    #[test]
63    fn layout_matches_c_complex_double() {
64        // C `_Complex double` is two contiguous doubles, 16 bytes, aligned to f64.
65        assert_eq!(std::mem::size_of::<Complex64>(), 16);
66        assert_eq!(
67            std::mem::align_of::<Complex64>(),
68            std::mem::align_of::<f64>()
69        );
70        // Field offsets: re at byte 0, im at byte 8.
71        let z = Complex64::new(1.0, 2.0);
72        let bytes: [u8; 16] = unsafe { std::mem::transmute(z) };
73        let re_back = f64::from_le_bytes(bytes[..8].try_into().unwrap());
74        let im_back = f64::from_le_bytes(bytes[8..].try_into().unwrap());
75        assert_eq!(re_back, 1.0);
76        assert_eq!(im_back, 2.0);
77    }
78
79    #[test]
80    fn layout_matches_c_complex_float() {
81        assert_eq!(std::mem::size_of::<Complex32>(), 8);
82        assert_eq!(
83            std::mem::align_of::<Complex32>(),
84            std::mem::align_of::<f32>()
85        );
86    }
87}