Closed as duplicate of#138979
Description
Code
#![cfg_attr(not(test), no_std)]
#![cfg_attr(not(test), no_main)]
// Only dependency in Cargo.toml is: heapless = "0.9.0"
use core::{
cmp::PartialOrd,
fmt::Debug,
mem::size_of,
ops::{Add, Div, Mul, Sub},
};
use heapless::HistoryBuf;
pub struct MovingAverage<T, TCALC, const N: usize>
where
T: Sized + PartialEq + TryFrom<TCALC, Error: Debug> + Clone + Copy,
TCALC: Sized
+ Add<TCALC, Output = TCALC>
+ Sub<TCALC, Output = TCALC>
+ Div<Output = TCALC>
+ Mul<Output = TCALC>
+ PartialEq
+ PartialOrd
+ From<T>
+ TryFrom<usize, Error: Debug>
+ Clone
+ Copy,
{
num: TCALC,
sum: Option<TCALC>,
buffer: HistoryBuf<T, N>,
}
/// # Panics
/// Panics if TCALC not larger than T, allocation-time assert.
/// Panics if unable to convert from usize to TCALC.
/// This panic should never occur due to allocation-time assert checks.
#[expect(clippy::unwrap_used, reason = "Made safe by compile-time asserts")]
impl<T, TCALC, const N: usize> Default for MovingAverage<T, TCALC, N>
where
T: Sized + PartialEq + TryFrom<TCALC, Error: Debug> + Clone + Copy,
TCALC: Sized
+ Add<TCALC, Output = TCALC>
+ Sub<TCALC, Output = TCALC>
+ Div<Output = TCALC>
+ Mul<Output = TCALC>
+ PartialEq
+ PartialOrd
+ From<T>
+ TryFrom<usize, Error: Debug>
+ Clone
+ Copy,
{
fn default() -> Self {
const {
assert!(
size_of::<TCALC>() > size_of::<T>(),
"TCALC must be larger than T"
);
assert!(N > 0, "N must be non-zero");
}
Self {
num: TCALC::try_from(N).unwrap(),
sum: None,
buffer: HistoryBuf::new(),
}
}
}
impl<T, TCALC, const N: usize> MovingAverage<T, TCALC, N>
where
T: Sized + PartialEq + TryFrom<TCALC, Error: Debug> + Clone + Copy,
TCALC: Sized
+ Add<TCALC, Output = TCALC>
+ Sub<TCALC, Output = TCALC>
+ Div<Output = TCALC>
+ Mul<Output = TCALC>
+ PartialEq
+ PartialOrd
+ From<T>
+ TryFrom<usize, Error: Debug>
+ Clone
+ Copy,
{
#[must_use]
pub fn new() -> Self {
Self::default()
}
/// # Panics
/// Panics if unable to convert from TCALC to T.
/// This panic should never occur due to compile-time assert checks.
#[must_use]
pub fn average(&mut self, input: T) -> T {
let new_value = TCALC::from(input);
let prev_sum = self.get_or_init_and_get_sum(input);
let remove = self.insert_new_value_pop_oldest_value(input);
self.create_average(new_value, prev_sum, remove)
}
fn get_or_init_and_get_sum(&mut self, input: T) -> TCALC {
let new_value = TCALC::from(input);
if let Some(sum) = self.sum {
sum
} else {
for _ in 0..N {
self.buffer.write(input);
}
self.num * new_value
}
}
fn insert_new_value_pop_oldest_value(&mut self, input: T) -> TCALC {
let remove = self.get_remove_value();
self.buffer.write(input);
remove
}
#[expect(clippy::expect_used, reason = "Made safe by compile-time asserts")]
fn create_average(&mut self, new_value: TCALC, prev_sum: TCALC, remove: TCALC) -> T {
#[cfg(test)]
assert!(prev_sum >= remove, "Remove must not be bigger than sum.");
let new_sum = prev_sum + new_value - remove;
self.sum = Some(new_sum);
let average_as_tcalc = new_sum / self.num;
T::try_from(average_as_tcalc).expect("Converting from TCALC to T should be safe")
}
#[expect(clippy::expect_used, reason = "Made safe by compile-time asserts")]
fn get_remove_value(&self) -> TCALC {
#[cfg(test)]
assert!(
self.buffer.len() == N,
"Buffer len {} different than capacity {N}.",
self.buffer.len()
);
TCALC::from(*self.buffer.oldest().expect("Buffer should be full"))
}
}
Meta
rustc --version --verbose
:
rustc 1.86.0 (05f9846f8 2025-03-31)
binary: rustc
commit-hash: 05f9846f893b09a1be1fc8560e33fc3c815cfecb
commit-date: 2025-03-31
host: aarch64-apple-darwin
release: 1.86.0
LLVM version: 19.1.7
Error output
% cargo build --release
Compiling heapless v0.9.0
Compiling byteorder v1.5.0
Compiling stable_deref_trait v1.2.0
Compiling hash32 v0.3.1
Compiling no-std-moving-average v0.1.0 (/Users/shakencodes/Development/Kelvin/no-std-moving-average-rs)
thread 'rustc' panicked at compiler/rustc_errors/src/lib.rs:675:17:
`trimmed_def_paths` called, diagnostics were expected but none were emitted. Use `with_no_trimmed_paths` for debugging. Backtraces are currently disabled: set `RUST_BACKTRACE=1` and re-run to see where it happened.
stack backtrace:
0: 0x10d8e9c78 - <std::sys::backtrace::BacktraceLock::print::DisplayBacktrace as core::fmt::Display>::fmt::h217270392019d164
1: 0x10b0ec3f0 - core::fmt::write::he22fcab56bd3ec61
2: 0x10d8de3e8 - std::io::Write::write_fmt::hb32eaafcfd249a19
3: 0x10d8e9b38 - std::sys::backtrace::BacktraceLock::print::h115149c0b879e5c3
4: 0x10d8ebf9c - std::panicking::default_hook::{{closure}}::h5c3a234feebd11a5
5: 0x10d8ebdec - std::panicking::default_hook::ha0b223ccc4379930
6: 0x10bb5a5e8 - std[9558dde1fef45f95]::panicking::update_hook::<alloc[a353884198cecfbc]::boxed::Box<rustc_driver_impl[d422414f666c26d7]::install_ice_hook::{closure#1}>>::{closure#0}
7: 0x10d8ecc18 - std::panicking::rust_panic_with_hook::h203f96c93e7ac62d
8: 0x10d8ec7ac - std::panicking::begin_panic_handler::{{closure}}::hcc8f653f753c0254
9: 0x10d8ea108 - std::sys::backtrace::__rust_end_short_backtrace::h911de07218b69a6c
10: 0x10d8ec470 - _rust_begin_unwind
11: 0x1103a77a4 - core::panicking::panic_fmt::h6a4014bec58fba4f
12: 0x10bc09634 - <rustc_errors[ec173a575dd51043]::DiagCtxtInner as core[b495b0e88a16f434]::ops::drop::Drop>::drop
13: 0x10bb2b730 - core[b495b0e88a16f434]::ptr::drop_in_place::<rustc_errors[ec173a575dd51043]::DiagCtxt>
14: 0x10bb413d4 - core[b495b0e88a16f434]::ptr::drop_in_place::<rustc_session[ba2d81a866856cf8]::parse::ParseSess>
15: 0x10bb3b5d8 - core[b495b0e88a16f434]::ptr::drop_in_place::<rustc_interface[3ca3d7ac74064029]::interface::Compiler>
16: 0x10bb572b4 - rustc_interface[3ca3d7ac74064029]::interface::run_compiler::<(), rustc_driver_impl[d422414f666c26d7]::run_compiler::{closure#0}>::{closure#1}
17: 0x10bb49aa4 - std[9558dde1fef45f95]::sys::backtrace::__rust_begin_short_backtrace::<rustc_interface[3ca3d7ac74064029]::util::run_in_thread_with_globals<rustc_interface[3ca3d7ac74064029]::util::run_in_thread_pool_with_globals<rustc_interface[3ca3d7ac74064029]::interface::run_compiler<(), rustc_driver_impl[d422414f666c26d7]::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#0}, ()>::{closure#0}::{closure#0}, ()>
18: 0x10bb5e0fc - <<std[9558dde1fef45f95]::thread::Builder>::spawn_unchecked_<rustc_interface[3ca3d7ac74064029]::util::run_in_thread_with_globals<rustc_interface[3ca3d7ac74064029]::util::run_in_thread_pool_with_globals<rustc_interface[3ca3d7ac74064029]::interface::run_compiler<(), rustc_driver_impl[d422414f666c26d7]::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#0}, ()>::{closure#0}::{closure#0}, ()>::{closure#1} as core[b495b0e88a16f434]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0}
19: 0x10d8f76b4 - std::sys::pal::unix::thread::Thread::new::thread_start::h6d53b1b0c047a3b9
20: 0x185b85c0c - __pthread_cond_wait
error: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md
note: rustc 1.86.0 (05f9846f8 2025-03-31) running on aarch64-apple-darwin
note: compiler flags: --crate-type lib -C opt-level=3 -C embed-bitcode=no -C strip=debuginfo
note: some of the compiler flags provided by cargo are hidden
query stack during panic:
end of query stack
error: could not compile `heapless` (lib)
Caused by:
process didn't exit successfully: `/Users/shakencodes/.rustup/toolchains/stable-aarch64-apple-darwin/bin/rustc --crate-name heapless --edition=2021 /Users/shakencodes/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/heapless-0.9.0/src/lib.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --diagnostic-width=113 --crate-type lib --emit=dep-info,metadata,link -C opt-level=3 -C embed-bitcode=no --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values("alloc", "bytes", "defmt", "mpmc_large", "nightly", "portable-atomic", "portable-atomic-critical-section", "portable-atomic-unsafe-assume-single-core", "serde", "ufmt"))' -C metadata=e55147cee1a46efb -C extra-filename=-9d546ea6984ac991 --out-dir /Users/shakencodes/Development/Kelvin/no-std-moving-average-rs/target/release/deps -C strip=debuginfo -L dependency=/Users/shakencodes/Development/Kelvin/no-std-moving-average-rs/target/release/deps --extern hash32=/Users/shakencodes/Development/Kelvin/no-std-moving-average-rs/target/release/deps/libhash32-9bb5e7c30052cb43.rmeta --extern stable_deref_trait=/Users/shakencodes/Development/Kelvin/no-std-moving-average-rs/target/release/deps/libstable_deref_trait-ce896a0d5f65d597.rmeta --cap-lints allow --check-cfg 'cfg(arm_llsc)' --check-cfg 'cfg(has_atomic_load_store)'` (exit status: 101)
warning: build failed, waiting for other jobs to finish...
%
Backtrace
% RUST_BACKTRACE=1 cargo build
Compiling no-std-moving-average v0.1.0 (/Users/shakencodes/Development/Kelvin/no-std-moving-average-rs)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.11s
%