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: u16 = (value & MASK_SUBID) as u16;
80 let version: u16 = ((value >> BITS_SUBID) & MASK_VERSION) as u16;
81 let id: u32 = (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}
113