improve sequence counters
This commit is contained in:
@@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
- Added PUS A legacy support for telecommands inside the `ecss.tc_pus_a` module
|
- Added PUS A legacy support for telecommands inside the `ecss.tc_pus_a` module
|
||||||
- Added `SequenceCounter::increment_mut` and `SequenceCounter::get_and_increment_mut`
|
- Added `SequenceCounter::increment_mut` and `SequenceCounter::get_and_increment_mut`
|
||||||
|
- Implemented `SequenceCounter` for `Atomic` unsigned types and references of them
|
||||||
|
|
||||||
# [v0.15.0] 2025-07-18
|
# [v0.15.0] 2025-07-18
|
||||||
|
|
||||||
|
|||||||
147
src/seq_count.rs
147
src/seq_count.rs
@@ -1,8 +1,6 @@
|
|||||||
use crate::MAX_SEQ_COUNT;
|
use crate::MAX_SEQ_COUNT;
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
use paste::paste;
|
use paste::paste;
|
||||||
#[cfg(feature = "std")]
|
|
||||||
pub use stdmod::*;
|
|
||||||
|
|
||||||
/// Core trait for objects which can provide a sequence count.
|
/// Core trait for objects which can provide a sequence count.
|
||||||
///
|
///
|
||||||
@@ -120,45 +118,102 @@ impl SequenceCounter for SequenceCounterCcsdsSimple {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
impl SequenceCounter for core::sync::atomic::AtomicU8 {
|
||||||
pub mod stdmod {
|
type Raw = u8;
|
||||||
use super::*;
|
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
|
|
||||||
macro_rules! sync_clonable_seq_counter_impl {
|
const MAX_BIT_WIDTH: usize = 8;
|
||||||
|
|
||||||
|
fn get(&self) -> Self::Raw {
|
||||||
|
self.load(core::sync::atomic::Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn increment(&self) {
|
||||||
|
self.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SequenceCounter for core::sync::atomic::AtomicU16 {
|
||||||
|
type Raw = u16;
|
||||||
|
|
||||||
|
const MAX_BIT_WIDTH: usize = 16;
|
||||||
|
|
||||||
|
fn get(&self) -> Self::Raw {
|
||||||
|
self.load(core::sync::atomic::Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn increment(&self) {
|
||||||
|
self.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SequenceCounter for core::sync::atomic::AtomicU32 {
|
||||||
|
type Raw = u32;
|
||||||
|
|
||||||
|
const MAX_BIT_WIDTH: usize = 32;
|
||||||
|
|
||||||
|
fn get(&self) -> Self::Raw {
|
||||||
|
self.load(core::sync::atomic::Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn increment(&self) {
|
||||||
|
self.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SequenceCounter for core::sync::atomic::AtomicU64 {
|
||||||
|
type Raw = u64;
|
||||||
|
|
||||||
|
const MAX_BIT_WIDTH: usize = 64;
|
||||||
|
|
||||||
|
fn get(&self) -> Self::Raw {
|
||||||
|
self.load(core::sync::atomic::Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn increment(&self) {
|
||||||
|
self.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: SequenceCounter + ?Sized> SequenceCounter for &T {
|
||||||
|
type Raw = T::Raw;
|
||||||
|
const MAX_BIT_WIDTH: usize = T::MAX_BIT_WIDTH;
|
||||||
|
|
||||||
|
fn get(&self) -> Self::Raw {
|
||||||
|
(**self).get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn increment(&self) {
|
||||||
|
(**self).increment()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! sync_clonable_seq_counter_impl {
|
||||||
($($ty: ident,)+) => {
|
($($ty: ident,)+) => {
|
||||||
$(paste! {
|
$(paste! {
|
||||||
/// These sequence counters can be shared between threads and can also be
|
|
||||||
/// configured to wrap around at specified maximum values. Please note that
|
/// This can be used if a custom wrap value is required when using a thread-safe
|
||||||
/// that the API provided by this class will not panic und [Mutex] lock errors,
|
/// atomic based sequence counter.
|
||||||
/// but it will yield 0 for the getter functions.
|
#[derive(Debug)]
|
||||||
#[derive(Clone, Default)]
|
pub struct [<SequenceCounterSyncCustomWrap $ty:upper>] {
|
||||||
pub struct [<SequenceCounterSync $ty:upper>] {
|
seq_count: core::sync::atomic::[<Atomic $ty:upper>],
|
||||||
seq_count: Arc<Mutex<$ty>>,
|
max_val: $ty,
|
||||||
max_val: $ty
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl [<SequenceCounterSync $ty:upper>] {
|
impl [<SequenceCounterSyncCustomWrap $ty:upper>] {
|
||||||
pub fn new() -> Self {
|
pub fn new(max_val: $ty) -> Self {
|
||||||
Self::new_with_max_val($ty::MAX)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_with_max_val(max_val: $ty) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
seq_count: Arc::default(),
|
seq_count: core::sync::atomic::[<Atomic $ty:upper>]::new(0),
|
||||||
max_val
|
max_val,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl SequenceCounter for [<SequenceCounterSync $ty:upper>] {
|
|
||||||
|
impl SequenceCounter for [<SequenceCounterSyncCustomWrap $ty:upper>] {
|
||||||
type Raw = $ty;
|
type Raw = $ty;
|
||||||
const MAX_BIT_WIDTH: usize = core::mem::size_of::<Self::Raw>() * 8;
|
const MAX_BIT_WIDTH: usize = core::mem::size_of::<Self::Raw>() * 8;
|
||||||
|
|
||||||
fn get(&self) -> $ty {
|
fn get(&self) -> $ty {
|
||||||
match self.seq_count.lock() {
|
self.seq_count.load(core::sync::atomic::Ordering::Relaxed)
|
||||||
Ok(counter) => *counter,
|
|
||||||
Err(_) => 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn increment(&self) {
|
fn increment(&self) {
|
||||||
@@ -166,30 +221,30 @@ pub mod stdmod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_and_increment(&self) -> $ty {
|
fn get_and_increment(&self) -> $ty {
|
||||||
match self.seq_count.lock() {
|
self.seq_count.fetch_update(
|
||||||
Ok(mut counter) => {
|
core::sync::atomic::Ordering::Relaxed,
|
||||||
let val = *counter;
|
core::sync::atomic::Ordering::Relaxed,
|
||||||
if val == self.max_val {
|
|cur| {
|
||||||
*counter = 0;
|
// compute the next value, wrapping at MAX_VAL
|
||||||
} else {
|
let next = if cur == self.max_val { 0 } else { cur + 1 };
|
||||||
*counter += 1;
|
Some(next)
|
||||||
}
|
},
|
||||||
val
|
).unwrap()
|
||||||
}
|
|
||||||
Err(_) => 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})+
|
})+
|
||||||
}
|
}
|
||||||
}
|
|
||||||
sync_clonable_seq_counter_impl!(u8, u16, u32, u64,);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sync_clonable_seq_counter_impl!(u8, u16, u32, u64,);
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use core::sync::atomic::AtomicU8;
|
||||||
|
|
||||||
use crate::seq_count::{
|
use crate::seq_count::{
|
||||||
SequenceCounter, SequenceCounterCcsdsSimple, SequenceCounterSimple, SequenceCounterSyncU8,
|
SequenceCounter, SequenceCounterCcsdsSimple, SequenceCounterSimple,
|
||||||
|
SequenceCounterSyncCustomWrapU8,
|
||||||
};
|
};
|
||||||
use crate::MAX_SEQ_COUNT;
|
use crate::MAX_SEQ_COUNT;
|
||||||
|
|
||||||
@@ -231,7 +286,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_atomic_ref_counters() {
|
fn test_atomic_ref_counters() {
|
||||||
let sync_u8_counter = SequenceCounterSyncU8::new();
|
let sync_u8_counter = AtomicU8::new(0);
|
||||||
assert_eq!(sync_u8_counter.get(), 0);
|
assert_eq!(sync_u8_counter.get(), 0);
|
||||||
assert_eq!(sync_u8_counter.get_and_increment(), 0);
|
assert_eq!(sync_u8_counter.get_and_increment(), 0);
|
||||||
assert_eq!(sync_u8_counter.get_and_increment(), 1);
|
assert_eq!(sync_u8_counter.get_and_increment(), 1);
|
||||||
@@ -240,7 +295,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_atomic_ref_counters_overflow() {
|
fn test_atomic_ref_counters_overflow() {
|
||||||
let sync_u8_counter = SequenceCounterSyncU8::new();
|
let sync_u8_counter = AtomicU8::new(0);
|
||||||
for _ in 0..u8::MAX as u16 + 1 {
|
for _ in 0..u8::MAX as u16 + 1 {
|
||||||
sync_u8_counter.increment();
|
sync_u8_counter.increment();
|
||||||
}
|
}
|
||||||
@@ -249,7 +304,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_atomic_ref_counters_overflow_custom_max_val() {
|
fn test_atomic_ref_counters_overflow_custom_max_val() {
|
||||||
let sync_u8_counter = SequenceCounterSyncU8::new_with_max_val(128);
|
let sync_u8_counter = SequenceCounterSyncCustomWrapU8::new(128);
|
||||||
for _ in 0..129 {
|
for _ in 0..129 {
|
||||||
sync_u8_counter.increment();
|
sync_u8_counter.increment();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user