1use crossbeam_utils::CachePadded;
2use std::sync::atomic::{AtomicU64, Ordering};
3
4pub const DEFAULT_NONCE_CHUNK_SIZE: u64 = 64;
5
6pub struct ChunkedNonceDispenser {
9 next_nonce: CachePadded<AtomicU64>,
10 chunk_size: u64,
11}
12
13impl ChunkedNonceDispenser {
14 pub fn new(chunk_size: u64) -> Self {
15 Self {
16 next_nonce: CachePadded::new(AtomicU64::new(0)),
17 chunk_size: chunk_size.max(1),
18 }
19 }
20
21 pub fn claim_chunk(&self) -> LocalNonceWindow {
22 let base = self
23 .next_nonce
24 .fetch_add(self.chunk_size, Ordering::Relaxed);
25 LocalNonceWindow {
26 current: base,
27 limit: base.saturating_add(self.chunk_size),
28 }
29 }
30}
31
32#[derive(Debug, Clone, Copy)]
34pub struct LocalNonceWindow {
35 current: u64,
36 limit: u64,
37}
38
39impl LocalNonceWindow {
40 pub fn empty() -> Self {
41 Self {
42 current: 0,
43 limit: 0,
44 }
45 }
46
47 #[inline]
50 pub fn next_nonce(&mut self, dispenser: &ChunkedNonceDispenser) -> Option<u64> {
51 if self.current < self.limit {
52 let n = self.current;
53 self.current += 1;
54 Some(n)
55 } else {
56 *self = dispenser.claim_chunk();
57 if self.current < self.limit {
58 let n = self.current;
59 self.current += 1;
60 Some(n)
61 } else {
62 None
63 }
64 }
65 }
66}