| 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 | |