calloop/
token.rs

1// Several implementations of the internals of `Token` depending on the size of `usize`
2
3use std::convert::TryInto;
4
5#[cfg(target_pointer_width = "64")]
6const BITS_VERSION: usize = 16;
7#[cfg(target_pointer_width = "64")]
8const BITS_SUBID: usize = 16;
9
10#[cfg(target_pointer_width = "32")]
11const BITS_VERSION: usize = 8;
12#[cfg(target_pointer_width = "32")]
13const BITS_SUBID: usize = 8;
14
15#[cfg(target_pointer_width = "16")]
16const BITS_VERSION: usize = 4;
17#[cfg(target_pointer_width = "16")]
18const BITS_SUBID: usize = 4;
19
20const MASK_VERSION: usize = (1 << BITS_VERSION) - 1;
21const MASK_SUBID: usize = (1 << BITS_SUBID) - 1;
22
23#[derive(Clone, Copy, PartialEq, Eq, Debug)]
24pub(crate) struct TokenInner {
25    id: u32,
26    version: u16,
27    sub_id: u16,
28}
29
30impl TokenInner {
31    pub(crate) fn new(id: usize) -> Result<TokenInner, ()> {
32        Ok(TokenInner {
33            id: id.try_into().map_err(|_| ())?,
34            version: 0,
35            sub_id: 0,
36        })
37    }
38
39    pub(crate) fn get_id(self) -> usize {
40        self.id as usize
41    }
42
43    pub(crate) fn same_source_as(self, other: TokenInner) -> bool {
44        self.id == other.id && self.version == other.version
45    }
46
47    pub(crate) fn increment_version(self) -> TokenInner {
48        TokenInner {
49            id: self.id,
50            version: self.version.wrapping_add(1) & (MASK_VERSION as u16),
51            sub_id: 0,
52        }
53    }
54
55    pub(crate) fn increment_sub_id(self) -> TokenInner {
56        let sub_id = match self.sub_id.checked_add(1) {
57            Some(sid) if sid <= (MASK_SUBID as u16) => sid,
58            _ => panic!("Maximum number of sub-ids reached for source #{}", self.id),
59        };
60
61        TokenInner {
62            id: self.id,
63            version: self.version,
64            sub_id,
65        }
66    }
67
68    pub(crate) fn forget_sub_id(self) -> TokenInner {
69        TokenInner {
70            id: self.id,
71            version: self.version,
72            sub_id: 0,
73        }
74    }
75}
76
77impl From<usize> for TokenInner {
78    fn from(value: usize) -> Self {
79        let sub_id = (value & MASK_SUBID) as u16;
80        let version = ((value >> BITS_SUBID) & MASK_VERSION) as u16;
81        let id = (value >> (BITS_SUBID + BITS_VERSION)) as u32;
82        TokenInner {
83            id,
84            version,
85            sub_id,
86        }
87    }
88}
89
90impl From<TokenInner> for usize {
91    fn from(token: TokenInner) -> Self {
92        ((token.id as usize) << (BITS_SUBID + BITS_VERSION))
93            + ((token.version as usize) << BITS_SUBID)
94            + (token.sub_id as usize)
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use super::*;
101
102    #[should_panic]
103    #[test]
104    fn overflow_subid() {
105        let token = TokenInner {
106            id: 0,
107            version: 0,
108            sub_id: MASK_SUBID as u16,
109        };
110        token.increment_sub_id();
111    }
112}