1#![cfg_attr(not(feature = "std"), no_std)]
48
49#[cfg(all(feature = "alloc", not(feature = "std")))]
50extern crate alloc;
51
52#[cfg(all(feature = "alloc", not(feature = "std")))]
53use alloc::vec::Vec;
54
55use crate::error::{CoreError, CoreResult};
56use core::marker::PhantomData;
57use num_traits::{Float, NumAssignOps, Zero};
58
59pub use error_handling::{EmbeddedError, EmbeddedResult};
61pub use memory_estimation::{estimate_stack_usage, MemoryRequirement};
62pub use stack_array::{BufferFullError, FixedSizeBuffer, StackArray};
63
64#[inline]
78pub fn stack_add<T, const N: usize>(a: &StackArray<T, N>, b: &StackArray<T, N>) -> StackArray<T, N>
79where
80 T: Float + NumAssignOps + Copy + Default,
81{
82 let mut result = StackArray::new();
83 for i in 0..N {
84 result.data[i] = a.data[i] + b.data[i];
85 }
86 result
87}
88
89#[inline]
91pub fn stack_mul<T, const N: usize>(a: &StackArray<T, N>, b: &StackArray<T, N>) -> StackArray<T, N>
92where
93 T: Float + NumAssignOps + Copy + Default,
94{
95 let mut result = StackArray::new();
96 for i in 0..N {
97 result.data[i] = a.data[i] * b.data[i];
98 }
99 result
100}
101
102#[inline]
104pub fn stack_sum<T, const N: usize>(arr: &StackArray<T, N>) -> T
105where
106 T: Float + NumAssignOps + Copy + Default + Zero,
107{
108 let mut sum = T::zero();
109 for i in 0..N {
110 sum += arr.data[i];
111 }
112 sum
113}
114
115#[inline]
117pub fn stack_mean<T, const N: usize>(arr: &StackArray<T, N>) -> T
118where
119 T: Float + NumAssignOps + Copy + Default + Zero,
120{
121 if N == 0 {
122 return T::zero();
123 }
124 stack_sum(arr) / T::from(N).expect("Failed to convert N to T")
125}
126
127pub mod memory_estimation {
129 use core::mem;
130
131 #[derive(Debug, Copy, Clone)]
133 pub struct MemoryRequirement {
134 pub stack_bytes: usize,
136 pub heap_bytes: usize,
138 pub flash_bytes: usize,
140 }
141
142 impl MemoryRequirement {
143 pub const fn new(stack_bytes: usize, heap_bytes: usize, flash_bytes: usize) -> Self {
145 Self {
146 stack_bytes,
147 heap_bytes,
148 flash_bytes,
149 }
150 }
151
152 pub const fn basic() -> Self {
154 Self::new(1024, 0, 4096)
155 }
156
157 pub const fn signal_processing() -> Self {
159 Self::new(4096, 0, 16384)
160 }
161
162 pub const fn linalg() -> Self {
164 Self::new(8192, 0, 32768)
165 }
166 }
167
168 pub const fn estimate_stack_usage<T>(count: usize) -> usize {
170 mem::size_of::<T>() * count
171 }
172}
173
174pub mod error_handling {
176 use core::fmt;
177
178 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
180 pub enum EmbeddedError {
181 BufferOverflow,
183 BufferUnderflow,
185 InvalidSize,
187 OutOfMemory,
189 NumericalError,
191 NotSupported,
193 }
194
195 impl fmt::Display for EmbeddedError {
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 match self {
198 EmbeddedError::BufferOverflow => write!(f, "Buffer overflow"),
199 EmbeddedError::BufferUnderflow => write!(f, "Buffer underflow"),
200 EmbeddedError::InvalidSize => write!(f, "Invalid size"),
201 EmbeddedError::OutOfMemory => write!(f, "Out of memory"),
202 EmbeddedError::NumericalError => write!(f, "Numerical error"),
203 EmbeddedError::NotSupported => write!(f, "Not supported in no_std mode"),
204 }
205 }
206 }
207
208 pub type EmbeddedResult<T> = Result<T, EmbeddedError>;
210}
211
212pub mod stack_array {
214 use core::marker::PhantomData;
215
216 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
218 pub struct BufferFullError;
219
220 impl core::fmt::Display for BufferFullError {
221 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
222 write!(f, "buffer is full")
223 }
224 }
225
226 #[derive(Debug, Clone)]
242 pub struct StackArray<T, const N: usize> {
243 pub(super) data: [T; N],
244 _marker: PhantomData<T>,
245 }
246
247 impl<T: Copy + Default, const N: usize> StackArray<T, N> {
248 #[inline]
250 pub fn new() -> Self {
251 Self {
252 data: [T::default(); N],
253 _marker: PhantomData,
254 }
255 }
256
257 #[inline]
259 pub fn from_slice(slice: &[T]) -> Option<Self> {
260 if slice.len() != N {
261 return None;
262 }
263 let mut result = Self::new();
264 result.data.copy_from_slice(slice);
265 Some(result)
266 }
267
268 #[inline]
270 pub const fn len(&self) -> usize {
271 N
272 }
273
274 #[inline]
276 pub const fn is_empty(&self) -> bool {
277 N == 0
278 }
279
280 #[inline]
282 pub fn as_slice(&self) -> &[T] {
283 &self.data
284 }
285
286 #[inline]
288 pub fn as_mut_slice(&mut self) -> &mut [T] {
289 &mut self.data
290 }
291 }
292
293 impl<T: Copy + Default, const N: usize> Default for StackArray<T, N> {
294 fn default() -> Self {
295 Self::new()
296 }
297 }
298
299 impl<T, const N: usize> core::ops::Index<usize> for StackArray<T, N> {
300 type Output = T;
301
302 #[inline]
303 fn index(&self, index: usize) -> &Self::Output {
304 &self.data[index]
305 }
306 }
307
308 impl<T, const N: usize> core::ops::IndexMut<usize> for StackArray<T, N> {
309 #[inline]
310 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
311 &mut self.data[index]
312 }
313 }
314
315 #[derive(Debug, Clone)]
330 pub struct FixedSizeBuffer<T, const N: usize> {
331 pub(super) data: [T; N],
332 len: usize,
333 _marker: PhantomData<T>,
334 }
335
336 impl<T: Copy + Default, const N: usize> FixedSizeBuffer<T, N> {
337 #[inline]
339 pub fn new() -> Self {
340 Self {
341 data: [T::default(); N],
342 len: 0,
343 _marker: PhantomData,
344 }
345 }
346
347 #[inline]
349 pub fn push(&mut self, value: T) -> Result<(), BufferFullError> {
350 if self.len >= N {
351 return Err(BufferFullError);
352 }
353 self.data[self.len] = value;
354 self.len += 1;
355 Ok(())
356 }
357
358 #[inline]
360 pub fn pop(&mut self) -> Option<T> {
361 if self.len == 0 {
362 return None;
363 }
364 self.len -= 1;
365 Some(self.data[self.len])
366 }
367
368 #[inline]
370 pub const fn len(&self) -> usize {
371 self.len
372 }
373
374 #[inline]
376 pub const fn is_empty(&self) -> bool {
377 self.len == 0
378 }
379
380 #[inline]
382 pub const fn is_full(&self) -> bool {
383 self.len == N
384 }
385
386 #[inline]
388 pub const fn capacity(&self) -> usize {
389 N
390 }
391
392 #[inline]
394 pub fn clear(&mut self) {
395 self.len = 0;
396 }
397
398 #[inline]
400 pub fn as_slice(&self) -> &[T] {
401 &self.data[..self.len]
402 }
403 }
404
405 impl<T: Copy + Default, const N: usize> Default for FixedSizeBuffer<T, N> {
406 fn default() -> Self {
407 Self::new()
408 }
409 }
410}
411
412#[cfg(test)]
413mod tests {
414 use super::*;
415
416 #[test]
417 fn test_stack_array_basic() {
418 let mut arr = StackArray::<f32, 8>::new();
419 arr[0] = 1.0;
420 arr[1] = 2.0;
421 assert_eq!(arr.len(), 8);
422 assert_eq!(arr[0], 1.0);
423 assert_eq!(arr[1], 2.0);
424 }
425
426 #[test]
427 fn test_fixed_size_buffer() {
428 let mut buffer = FixedSizeBuffer::<f32, 4>::new();
429 assert!(buffer.is_empty());
430
431 buffer.push(1.0).expect("Failed to push");
432 buffer.push(2.0).expect("Failed to push");
433 assert_eq!(buffer.len(), 2);
434
435 assert_eq!(buffer.pop(), Some(2.0));
436 assert_eq!(buffer.len(), 1);
437 }
438
439 #[test]
440 fn test_stack_operations() {
441 let mut a = StackArray::<f32, 4>::new();
442 let mut b = StackArray::<f32, 4>::new();
443
444 for i in 0..4 {
445 a[i] = i as f32;
446 b[i] = (i + 1) as f32;
447 }
448
449 let sum = stack_add(&a, &b);
450 assert_eq!(sum[0], 1.0);
451 assert_eq!(sum[1], 3.0);
452
453 let product = stack_mul(&a, &b);
454 assert_eq!(product[0], 0.0);
455 assert_eq!(product[1], 2.0);
456 }
457
458 #[test]
459 fn test_stack_statistics() {
460 let mut arr = StackArray::<f32, 4>::new();
461 arr[0] = 1.0;
462 arr[1] = 2.0;
463 arr[2] = 3.0;
464 arr[3] = 4.0;
465
466 let total = stack_sum(&arr);
467 assert_eq!(total, 10.0);
468
469 let avg = stack_mean(&arr);
470 assert_eq!(avg, 2.5);
471 }
472}