1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
use std::sync::{
atomic::{Ordering, AtomicUsize},
};
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum ResourceType {
Local,
Remote,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct ResourceId {
id: usize,
}
impl ResourceId {
const RESOURCE_TYPE_BIT: usize = 1 << (Self::ADAPTER_ID_POS + 7);
const ADAPTER_ID_POS: usize = 8 * 7;
const ADAPTER_ID_MASK: u8 = 0b01111111;
const ADAPTER_ID_MASK_OVER_ID: usize = (Self::ADAPTER_ID_MASK as usize) << Self::ADAPTER_ID_POS;
const BASE_VALUE_MASK_OVER_ID: usize = 0x0FFFFFFF;
pub const ADAPTER_ID_MAX: usize = Self::ADAPTER_ID_MASK as usize + 1;
fn new(adapter_id: u8, resource_type: ResourceType, base_value: usize) -> Self {
assert_eq!(
adapter_id & Self::ADAPTER_ID_MASK,
adapter_id,
"The adapter_id value uses bits outside of the mask"
);
assert_eq!(
base_value & Self::BASE_VALUE_MASK_OVER_ID,
base_value,
"The base_value value uses bits outside of the mask"
);
let resource_type = match resource_type {
ResourceType::Local => Self::RESOURCE_TYPE_BIT,
ResourceType::Remote => 0,
};
Self { id: base_value | resource_type | (adapter_id as usize) << Self::ADAPTER_ID_POS }
}
pub fn from(raw: usize) -> Self {
Self { id: raw }
}
pub fn raw(&self) -> usize {
self.id
}
pub fn resource_type(&self) -> ResourceType {
if self.id & Self::RESOURCE_TYPE_BIT != 0 {
ResourceType::Local
}
else {
ResourceType::Remote
}
}
pub fn adapter_id(&self) -> u8 {
((self.id & Self::ADAPTER_ID_MASK_OVER_ID) >> Self::ADAPTER_ID_POS) as u8
}
pub fn base_value(&self) -> usize {
self.id & Self::BASE_VALUE_MASK_OVER_ID
}
}
impl std::fmt::Display for ResourceId {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let resource_type = match self.resource_type() {
ResourceType::Local => "L",
ResourceType::Remote => "R",
};
write!(f, "{}.{}.{}", self.adapter_id(), resource_type, self.base_value())
}
}
impl std::fmt::Debug for ResourceId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
pub struct ResourceIdGenerator {
last: AtomicUsize,
adapter_id: u8,
resource_type: ResourceType,
}
impl ResourceIdGenerator {
pub fn new(adapter_id: u8, resource_type: ResourceType) -> Self {
Self { last: AtomicUsize::new(0), adapter_id, resource_type }
}
pub fn generate(&self) -> ResourceId {
let last = self.last.fetch_add(1, Ordering::SeqCst);
ResourceId::new(self.adapter_id, self.resource_type, last)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn base_value() {
let low_base_value = 0;
let resource_id = ResourceId::new(1, ResourceType::Local, low_base_value);
assert_eq!(resource_id.base_value(), low_base_value);
let high_base_value = ResourceId::BASE_VALUE_MASK_OVER_ID;
let resource_id = ResourceId::new(1, ResourceType::Local, high_base_value);
assert_eq!(resource_id.base_value(), high_base_value);
}
#[test]
fn resource_type() {
let resource_id = ResourceId::new(0, ResourceType::Local, 0);
assert_eq!(resource_id.resource_type(), ResourceType::Local);
assert_eq!(resource_id.adapter_id(), 0);
let resource_id = ResourceId::new(0, ResourceType::Remote, 0);
assert_eq!(resource_id.resource_type(), ResourceType::Remote);
assert_eq!(resource_id.adapter_id(), 0);
}
#[test]
fn adapter_id() {
let adapter_id = ResourceId::ADAPTER_ID_MASK;
let resource_id = ResourceId::new(adapter_id, ResourceType::Local, 0);
assert_eq!(resource_id.adapter_id(), adapter_id);
assert_eq!(resource_id.resource_type(), ResourceType::Local);
let resource_id = ResourceId::new(adapter_id, ResourceType::Remote, 0);
assert_eq!(resource_id.adapter_id(), adapter_id);
assert_eq!(resource_id.resource_type(), ResourceType::Remote);
}
}