Skip to main content

rill_core/math/vector/
macros.rs

1//! Макросы для удобного построения векторных выражений.
2//!
3//! Этот модуль предоставляет макросы, которые упрощают работу с векторным eDSL,
4//! позволяя писать выражения в естественной математической нотации.
5//!
6//! ## Примеры
7//! ```
8//! use rill_core::vector::prelude::*;
9//! use rill_core::vector::macros::*;
10//!
11//! let a = ScalarVector4::splat(1.0);
12//! let b = ScalarVector4::splat(2.0);
13//! let c = a + b; // обычная векторная операция
14//! assert_eq!(c, ScalarVector4::splat(3.0));
15//!
16//! // Применение выражения ко всему слайсу
17//! let input = [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
18//! let mut output = [0.0f32; 8];
19//! vec_map!(&input, &mut output, |x| x * 2.0 + 1.0);
20//! // output = [3.0, 5.0, 7.0, 9.0, 11.0, 13.0, 15.0, 17.0]
21//! ```
22//!
23//! ## Доступные макросы
24//! - [`vec_map!`] – применяет векторное выражение ко всему слайсу.
25//! - [`vec_expr!`] – создаёт ленивое векторное выражение (заглушка, требует исправления модуля expr).
26//! - [`vec_eval!`] – немедленно вычисляет векторное выражение (заглушка).
27
28use crate::math::vector::scalar::ScalarVector4;
29use crate::math::vector::traits::Vector;
30
31#[macro_export]
32///
33macro_rules! vec_map {
34    ($input:expr, $output:expr, |$x:ident| $($body:tt)*) => {{
35        use $crate::math::vector::traits::Vector;
36        use $crate::math::vector::scalar::ScalarVector4;
37        const N: usize = 4;
38        let input: &[_] = $input;
39        let output: &mut [_] = $output;
40        assert_eq!(input.len(), output.len(), "input and output slices must have equal length");
41
42        if input.is_empty() {
43            return;
44        }
45
46        let closure = |$x: ScalarVector4<_>| -> ScalarVector4<_> { $($body)* };
47
48        let chunks = input.len() / N;
49        let remainder = input.len() % N;
50
51        for i in 0..chunks {
52            let start = i * N;
53            let x = <ScalarVector4<_>>::load(&input[start..start + N]);
54            let y = closure(x);
55            y.store(&mut output[start..start + N]);
56        }
57
58        if remainder > 0 {
59            let start = chunks * N;
60            let mut temp_input = [Default::default(); 4];
61            for i in 0..remainder {
62                temp_input[i] = input[start + i];
63            }
64            let x = <ScalarVector4<_>>::load(&temp_input[0..4]);
65            let y = closure(x);
66            for i in 0..remainder {
67                output[start + i] = y.extract(i);
68            }
69        }
70    }};
71}
72
73/// Создаёт ленивое векторное выражение (заглушка).
74///
75/// В текущей реализации модуль `expr` временно отключён из-за ошибок компиляции,
76/// поэтому этот макрос возвращает переданное значение без изменений.
77#[macro_export]
78macro_rules! vec_expr {
79    ($val:expr) => {
80        $val
81    };
82}
83
84/// Немедленно вычисляет векторное выражение (заглушка).
85///
86/// В текущей реализации просто возвращает переданное выражение.
87#[macro_export]
88macro_rules! vec_eval {
89    ($($t:tt)*) => {
90        $($t)*
91    };
92}
93
94pub use crate::vec_eval;
95pub use crate::vec_expr;
96pub use crate::vec_map;
97
98// -----------------------------------------------------------------------------
99// Тесты
100// -----------------------------------------------------------------------------
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105        use crate::math::vector::scalar::ScalarVector4;
106
107    #[test]
108    fn test_vec_map_f32() {
109        let input = [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
110        let mut output = [0.0f32; 8];
111
112        // Замыкание: x * 2.0 + 1.0
113        vec_map!(&input, &mut output, |x| x * 2.0 + 1.0);
114
115        assert_eq!(output[0], 3.0); // 1*2 + 1
116        assert_eq!(output[1], 5.0); // 2*2 + 1
117        assert_eq!(output[2], 7.0);
118        assert_eq!(output[3], 9.0);
119        assert_eq!(output[4], 11.0);
120        assert_eq!(output[5], 13.0);
121        assert_eq!(output[6], 15.0);
122        assert_eq!(output[7], 17.0);
123    }
124
125    #[test]
126    fn test_vec_map_f64() {
127        let input = [1.0f64, 2.0, 3.0, 4.0];
128        let mut output = [0.0f64; 4];
129
130        vec_map!(&input, &mut output, |x| x * 3.0 - 1.0);
131
132        assert_eq!(output[0], 2.0); // 1*3 - 1
133        assert_eq!(output[1], 5.0); // 2*3 - 1
134        assert_eq!(output[2], 8.0);
135        assert_eq!(output[3], 11.0);
136    }
137
138    #[test]
139    fn test_vec_map_empty() {
140        let input: [f32; 0] = [];
141        let mut output: [f32; 0] = [];
142        vec_map!(&input, &mut output, |x| x * 2.0); // не должно паниковать
143    }
144
145    #[test]
146    fn test_vec_map_remainder() {
147        let input = [1.0f32, 2.0, 3.0]; // три элемента
148        let mut output = [0.0f32; 3];
149
150        vec_map!(&input, &mut output, |x| x + 10.0);
151
152        assert_eq!(output[0], 11.0);
153        assert_eq!(output[1], 12.0);
154        assert_eq!(output[2], 13.0);
155    }
156
157    #[test]
158    fn test_vec_expr_stub() {
159        let vec = ScalarVector4::splat(5.0);
160        let result = vec_expr!(vec);
161        assert_eq!(result, vec);
162    }
163
164    #[test]
165    fn test_vec_eval_stub() {
166        let a = ScalarVector4::splat(2.0);
167        let b = ScalarVector4::splat(3.0);
168        let result = vec_eval!(a + b);
169        assert_eq!(result, ScalarVector4::splat(5.0));
170    }
171}