1
//! Helper for unique identifiers for channels.
2

            
3
use std::fmt::{Display, Formatter};
4
use std::sync::atomic::{AtomicUsize, Ordering};
5

            
6
/// Counter for allocating unique-ish identifiers for channels.
7
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
8

            
9
/// 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
1
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16
pub struct UniqId(usize);
17

            
18
impl UniqId {
19
    /// Construct a new UniqId.
20
125
    pub(crate) fn new() -> Self {
21
125
        // Relaxed ordering is fine; we don't care about how this
22
125
        // is instantiated with respect to other channels.
23
125
        let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
24
125
        assert!(id != std::usize::MAX, "Exhausted the channel ID namespace");
25
125
        UniqId(id)
26
125
    }
27
}
28

            
29
impl Display for UniqId {
30
1
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
31
1
        write!(f, "Chan {}", self.0)
32
1
    }
33
}
34

            
35
/// 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)]
40
pub(crate) struct CircUniqIdContext {
41
    /// Next value to be handed out for this channel's circuits.
42
    next_circ_id: usize,
43
}
44

            
45
impl CircUniqIdContext {
46
    /// Create a new CircUniqIdContext
47
87
    pub(super) fn new() -> Self {
48
87
        CircUniqIdContext { next_circ_id: 0 }
49
87
    }
50
    /// Construct a new, unique-ish circuit UniqId
51
7
    pub(super) fn next(&mut self, unique_id: UniqId) -> crate::circuit::UniqId {
52
7
        let circ_unique_id = self.next_circ_id;
53
7
        self.next_circ_id += 1;
54
7
        assert!(
55
7
            self.next_circ_id != 0,
56
7
            "Exhausted the unique circuit ID namespace on a channel"
57
7
        );
58
7
        crate::circuit::UniqId::new(unique_id.0, circ_unique_id)
59
7
    }
60
}
61

            
62
#[cfg(test)]
63
mod test {
64
    use super::*;
65
    #[test]
66
    fn chan_unique_id() {
67
        let ids: Vec<UniqId> = (0..10).map(|_| UniqId::new()).collect();
68

            
69
        // Make sure we got distinct numbers
70
        let mut all_nums: Vec<_> = ids.iter().map(|x| x.0).collect();
71
        all_nums.sort_unstable();
72
        all_nums.dedup();
73
        assert_eq!(all_nums.len(), ids.len());
74

            
75
        assert_eq!(format!("{}", ids[3]), format!("Chan {}", ids[3].0));
76
    }
77

            
78
    #[test]
79
    fn chan_circid() {
80
        let chan_id99 = UniqId(99);
81
        let mut ctx = CircUniqIdContext::new();
82

            
83
        let _id0 = ctx.next(chan_id99);
84
        let _id1 = ctx.next(chan_id99);
85
        let id2 = ctx.next(chan_id99);
86
        assert_eq!(format!("{}", id2), "Circ 99.2");
87
    }
88
}