1 | // Several implementations of the internals of `Token` depending on the size of `usize` |
2 | |
3 | use std::convert::TryInto; |
4 | |
5 | #[cfg (target_pointer_width = "64" )] |
6 | const BITS_VERSION: usize = 16; |
7 | #[cfg (target_pointer_width = "64" )] |
8 | const BITS_SUBID: usize = 16; |
9 | |
10 | #[cfg (target_pointer_width = "32" )] |
11 | const BITS_VERSION: usize = 8; |
12 | #[cfg (target_pointer_width = "32" )] |
13 | const BITS_SUBID: usize = 8; |
14 | |
15 | #[cfg (target_pointer_width = "16" )] |
16 | const BITS_VERSION: usize = 4; |
17 | #[cfg (target_pointer_width = "16" )] |
18 | const BITS_SUBID: usize = 4; |
19 | |
20 | const MASK_VERSION: usize = (1 << BITS_VERSION) - 1; |
21 | const MASK_SUBID: usize = (1 << BITS_SUBID) - 1; |
22 | |
23 | #[derive (Clone, Copy, PartialEq, Eq, Debug)] |
24 | pub(crate) struct TokenInner { |
25 | id: u32, |
26 | version: u16, |
27 | sub_id: u16, |
28 | } |
29 | |
30 | impl 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 | |
77 | impl 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 | |
90 | impl 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)] |
99 | mod 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 | |