1//! Helper for unique identifiers for channels.
23use std::fmt::{Display, Formatter};
4use std::sync::atomic::{AtomicUsize, Ordering};
56/// Counter for allocating unique-ish identifiers for channels.
7static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
89/// Unique identifier for a channel.
10///
11/// These identifiers are unique per process. On 32-bit architectures
12/// it's possible to exhaust them if you do nothing but create channels
13/// for a very long time; if you do, we detect that and exit with an
14/// assertion failure.
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16pub struct UniqId(usize);
1718impl UniqId {
19/// Construct a new UniqId.
20pub(crate) fn new() -> Self {
21// Relaxed ordering is fine; we don't care about how this
22 // is instantiated with respect to other channels.
23let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
24assert!(id != usize::MAX, "Exhausted the channel ID namespace");
25 UniqId(id)
26 }
27}
2829impl Display for UniqId {
30fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
31write!(f, "Chan {}", self.0)
32 }
33}
3435/// Counter for allocating circuit unique ids.
36///
37/// We don't use circuit IDs here, because they can be huge, and they're
38/// random, and can get reused.
39#[derive(Debug)]
40pub(crate) struct CircUniqIdContext {
41/// Next value to be handed out for this channel's circuits.
42next_circ_id: usize,
43}
4445impl CircUniqIdContext {
46/// Create a new CircUniqIdContext
47pub(super) fn new() -> Self {
48 CircUniqIdContext { next_circ_id: 0 }
49 }
50/// Construct a new, unique-ish circuit UniqId
51pub(super) fn next(&mut self, unique_id: UniqId) -> crate::tunnel::circuit::UniqId {
52let circ_unique_id = self.next_circ_id;
53self.next_circ_id += 1;
54assert!(
55self.next_circ_id != 0,
56"Exhausted the unique circuit ID namespace on a channel"
57);
58crate::tunnel::circuit::UniqId::new(unique_id.0, circ_unique_id)
59 }
60}
6162#[cfg(test)]
63mod test {
64// @@ begin test lint list maintained by maint/add_warning @@
65#![allow(clippy::bool_assert_comparison)]
66 #![allow(clippy::clone_on_copy)]
67 #![allow(clippy::dbg_macro)]
68 #![allow(clippy::mixed_attributes_style)]
69 #![allow(clippy::print_stderr)]
70 #![allow(clippy::print_stdout)]
71 #![allow(clippy::single_char_pattern)]
72 #![allow(clippy::unwrap_used)]
73 #![allow(clippy::unchecked_duration_subtraction)]
74 #![allow(clippy::useless_vec)]
75 #![allow(clippy::needless_pass_by_value)]
76//! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
77use super::*;
78#[test]
79fn chan_unique_id() {
80let ids: Vec<UniqId> = (0..10).map(|_| UniqId::new()).collect();
8182// Make sure we got distinct numbers
83let mut all_nums: Vec<_> = ids.iter().map(|x| x.0).collect();
84 all_nums.sort_unstable();
85 all_nums.dedup();
86assert_eq!(all_nums.len(), ids.len());
8788assert_eq!(format!("{}", ids[3]), format!("Chan {}", ids[3].0));
89 }
9091#[test]
92fn chan_circid() {
93let chan_id99 = UniqId(99);
94let mut ctx = CircUniqIdContext::new();
9596let _id0 = ctx.next(chan_id99);
97let _id1 = ctx.next(chan_id99);
98let id2 = ctx.next(chan_id99);
99assert_eq!(format!("{}", id2), "Circ 99.2");
100 }
101}