sponge256sum/
common.rs

1// SPDX-License-Identifier: 0BSD
2// sponge256sum
3// Copyright (C) 2025-2026 by LoRd_MuldeR <mulder2@gmx.de>
4
5use num::traits::SaturatingAdd;
6use sponge_hash_aes256::DEFAULT_DIGEST_SIZE;
7use std::{
8    num::NonZeroUsize,
9    sync::atomic::{AtomicUsize, Ordering},
10};
11use tinyvec::{ArrayVec, TinyVec};
12
13// ---------------------------------------------------------------------------
14// Common definitions
15// ---------------------------------------------------------------------------
16
17/// Maximum allowable "snailyness" (throttling) level
18pub const MAX_SNAIL_LEVEL: u8 = 4u8;
19
20/// Maximum allowable digest size, specified in bytes
21pub const MAX_DIGEST_SIZE: usize = 8usize * DEFAULT_DIGEST_SIZE;
22
23/// Type for holding a digest
24pub type Digest = TinyVec<[u8; DEFAULT_DIGEST_SIZE]>;
25
26/// Error type to indicate that a process was aborted
27pub struct Aborted;
28
29// ---------------------------------------------------------------------------
30// Cancellation flag
31// ---------------------------------------------------------------------------
32
33/// A flag which can be used to signal a cancellation request
34pub struct Flag(AtomicUsize);
35
36/// An error type indicating that the cancellation flag could not be updated
37pub struct UpdateError;
38
39// Status constants
40const STATUS_RUNNING: usize = 0usize;
41const STATUS_STOPPED: usize = 1usize;
42const STATUS_ABORTED: usize = 2usize;
43
44impl Flag {
45    /// Check whether the process is still running
46    ///
47    /// This will return `true`, unless either `stop_process()` or `abort_process()` has been triggered.
48    #[inline(always)]
49    pub fn running(&self) -> bool {
50        self.0.load(Ordering::Relaxed) == STATUS_RUNNING
51    }
52
53    /// Request the process to be stopped normally
54    #[inline]
55    pub fn stop_process(&self) -> Result<(), UpdateError> {
56        self.try_update(STATUS_STOPPED)
57    }
58
59    /// Request the process to be aborted, e.g., after a `SIGINT` was received
60    #[inline]
61    pub fn abort_process(&self) -> Result<(), UpdateError> {
62        self.try_update(STATUS_ABORTED)
63    }
64
65    #[inline(always)]
66    fn try_update(&self, new_state: usize) -> Result<(), UpdateError> {
67        match self.0.compare_exchange(STATUS_RUNNING, new_state, Ordering::AcqRel, Ordering::Acquire) {
68            Ok(_) => Ok(()),
69            Err(previous_state) => match previous_state == new_state {
70                true => Ok(()),
71                false => Err(UpdateError),
72            },
73        }
74    }
75}
76
77impl Default for Flag {
78    #[inline]
79    fn default() -> Self {
80        Self(AtomicUsize::new(STATUS_RUNNING))
81    }
82}
83
84// ---------------------------------------------------------------------------
85// TinyVec extension
86// ---------------------------------------------------------------------------
87
88pub trait TinyVecEx {
89    fn with_length(length: usize) -> Self;
90}
91
92impl<const N: usize, T: Copy + Default> TinyVecEx for TinyVec<[T; N]> {
93    #[inline(always)]
94    fn with_length(length: usize) -> Self {
95        if length <= N {
96            TinyVec::Inline(ArrayVec::from_array_len([T::default(); N], length))
97        } else {
98            TinyVec::Heap(vec![T::default(); length])
99        }
100    }
101}
102
103// ---------------------------------------------------------------------------
104// Utility functions
105// ---------------------------------------------------------------------------
106
107/// Increments the referenced counter by one (saturating)
108#[inline(always)]
109pub fn increment<T: SaturatingAdd + From<u8>>(counter: &mut T) {
110    *counter = counter.saturating_add(&T::from(1u8));
111}
112
113/// Compute the thread-count-specific capacity for a bounded channel
114#[inline]
115pub fn get_capacity(thread_count: &NonZeroUsize) -> usize {
116    let capacity = thread_count.get().saturating_mul(2usize).saturating_add(1usize);
117    if capacity > isize::MAX as usize {
118        capacity
119    } else {
120        capacity.next_power_of_two()
121    }
122}
123
124// ---------------------------------------------------------------------------
125// Helper macros
126// ---------------------------------------------------------------------------
127
128/// Conditional printing of error message
129#[macro_export]
130macro_rules! print_error {
131    ($args:ident, $fmt:literal $(,$arg:expr)*$(,)?) => {
132        if !$args.quiet {
133            eprintln!(concat!("[sponge256sum] ", $fmt) $(, $arg)*);
134        }
135    };
136}