1use std::{
2 fmt,
3 num::{NonZeroU16, NonZeroU64, NonZeroU8},
4};
5
6use derive_more::Display;
7use idr_ebr::Key;
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
21#[derive(Display, Serialize, Deserialize)]
22pub struct NodeNo(NonZeroU16);
23
24impl NodeNo {
25 pub(crate) fn generate() -> Self {
26 Self::from_bits((random_u64() as u16).max(1)).unwrap()
27 }
28
29 #[instability::unstable]
30 #[inline]
31 pub const fn from_bits(bits: u16) -> Option<Self> {
32 match NonZeroU16::new(bits) {
33 Some(node_no) => Some(Self(node_no)),
34 None => None,
35 }
36 }
37
38 #[instability::unstable]
39 #[inline]
40 pub const fn into_bits(self) -> u16 {
41 self.0.get()
42 }
43}
44
45#[instability::stable(since = "v0.2.0")]
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Display)]
55pub struct NodeLaunchId(NonZeroU64);
56
57impl NodeLaunchId {
58 pub(crate) fn generate() -> Self {
59 Self::from_bits(random_u64().max(1)).unwrap()
60 }
61
62 #[instability::unstable]
63 #[inline]
64 pub fn from_bits(bits: u64) -> Option<Self> {
65 NonZeroU64::new(bits).map(Self)
66 }
67
68 #[instability::unstable]
69 #[inline]
70 pub fn into_bits(self) -> u64 {
71 self.0.get()
72 }
73}
74
75#[instability::stable(since = "v0.2.0")]
82#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
83#[derive(Display, Serialize, Deserialize)]
84pub struct GroupNo(NonZeroU8);
85
86impl GroupNo {
87 #[cfg(feature = "network-2")] pub(crate) fn new(no: u8, launch_id: NodeLaunchId) -> Option<Self> {
89 if no == 0 {
90 return None;
91 }
92
93 let xor = (launch_id.into_bits() >> GROUP_NO_SHIFT) as u8;
94
95 let group_no = if no != xor { no ^ xor } else { xor };
97
98 Some(Self(NonZeroU8::new(group_no).unwrap()))
99 }
100
101 #[cfg(not(feature = "network-2"))]
102 pub(crate) fn new(no: u8, _launch_id: NodeLaunchId) -> Option<Self> {
103 NonZeroU8::new(no).map(Self)
104 }
105
106 #[instability::unstable]
107 #[inline]
108 pub fn from_bits(bits: u8) -> Option<Self> {
109 NonZeroU8::new(bits).map(Self)
110 }
111
112 #[instability::unstable]
113 #[inline]
114 pub fn into_bits(self) -> u8 {
115 self.0.get()
116 }
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
175pub struct Addr(u64); const NODE_NO_SHIFT: u32 = 48;
178const GROUP_NO_SHIFT: u32 = 40;
179
180assert_not_impl_all!(Addr: Serialize, Deserialize<'static>);
182
183impl fmt::Display for Addr {
184 #[inline]
185 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186 if self.is_null() {
187 return f.write_str("null");
188 }
189
190 let group_no = self.group_no().expect("invalid addr");
191 let bottom = self.0 & ((1 << GROUP_NO_SHIFT) - 1);
192
193 if let Some(node_no) = self.node_no() {
194 write!(f, "{node_no}/{group_no}/{bottom}")
195 } else {
196 write!(f, "{group_no}/{bottom}")
197 }
198 }
199}
200
201impl Addr {
202 #[instability::unstable]
203 pub const NULL: Addr = Addr(0);
204
205 #[cfg(feature = "network")]
206 pub(crate) fn new_local(slot_key: Key, group_no: GroupNo, launch_id: NodeLaunchId) -> Self {
207 let slot_key = u64::from(slot_key);
208 debug_assert!(slot_key < (1 << GROUP_NO_SHIFT));
209 let slot_key = (slot_key ^ launch_id.into_bits()) & ((1 << GROUP_NO_SHIFT) - 1);
210 Self::new_local_inner(slot_key, group_no)
211 }
212
213 #[cfg(not(feature = "network"))]
214 pub(crate) fn new_local(slot_key: Key, group_no: GroupNo, _launch_id: NodeLaunchId) -> Self {
215 let slot_key = u64::from(slot_key);
216 debug_assert!(slot_key < (1 << GROUP_NO_SHIFT));
217 Self::new_local_inner(slot_key, group_no)
218 }
219
220 fn new_local_inner(slot_key: u64, group_no: GroupNo) -> Self {
221 Self((u64::from(group_no.into_bits()) << GROUP_NO_SHIFT) | slot_key)
222 }
223
224 #[instability::unstable]
225 #[inline]
226 pub fn from_bits(bits: u64) -> Option<Self> {
227 Some(Self(bits)).filter(|addr| addr.is_null() ^ addr.group_no().is_some())
228 }
229
230 #[instability::unstable]
231 #[inline]
232 pub fn into_bits(self) -> u64 {
233 self.0
234 }
235
236 #[inline]
237 pub fn is_null(self) -> bool {
238 self == Self::NULL
239 }
240
241 #[inline]
242 pub fn is_local(self) -> bool {
243 !self.is_null() && self.node_no().is_none()
244 }
245
246 #[cfg(feature = "network")]
247 #[inline]
248 pub fn is_remote(self) -> bool {
249 self.node_no().is_some()
250 }
251
252 #[instability::unstable]
253 #[inline]
254 pub fn node_no(self) -> Option<NodeNo> {
255 NodeNo::from_bits((self.0 >> NODE_NO_SHIFT) as u16)
256 }
257
258 #[instability::unstable]
259 #[inline]
260 pub fn group_no(self) -> Option<GroupNo> {
261 GroupNo::from_bits((self.0 >> GROUP_NO_SHIFT) as u8)
262 }
263
264 #[cfg(feature = "network")]
265 pub(crate) fn node_no_group_no(self) -> u32 {
266 (self.0 >> GROUP_NO_SHIFT) as u32
267 }
268
269 #[cfg(feature = "network")]
270 pub(crate) fn slot_key(self, launch_id: NodeLaunchId) -> Option<Key> {
271 (self.0 ^ launch_id.into_bits()).try_into().ok()
273 }
274
275 #[cfg(not(feature = "network"))]
276 pub(crate) fn slot_key(self, _launch_id: NodeLaunchId) -> Option<Key> {
277 self.0.try_into().ok()
278 }
279
280 #[cfg(feature = "network")]
281 #[instability::unstable]
282 #[inline]
283 pub fn into_remote(self, node_no: NodeNo) -> Self {
284 if self.is_local() {
285 Self(self.0 | (u64::from(node_no.into_bits()) << NODE_NO_SHIFT))
286 } else {
287 self
288 }
289 }
290
291 #[instability::unstable]
292 #[inline]
293 pub fn into_local(self) -> Self {
294 Self(self.0 & ((1 << NODE_NO_SHIFT) - 1))
295 }
296}
297
298pub(crate) struct IdrConfig;
301
302impl idr_ebr::Config for IdrConfig {
303 const INITIAL_PAGE_SIZE: u32 = 32;
304 const MAX_PAGES: u32 = 20;
305 const RESERVED_BITS: u32 = 24;
306}
307const_assert_eq!(
308 idr_ebr::Idr::<crate::object::Object, IdrConfig>::USED_BITS,
309 GROUP_NO_SHIFT
310);
311
312fn random_u64() -> u64 {
315 use std::{
316 collections::hash_map::RandomState,
317 hash::{BuildHasher, Hash, Hasher},
318 thread,
319 time::Instant,
320 };
321
322 let mut hasher = RandomState::new().build_hasher();
323 0xE1F0E1F0E1F0E1F0u64.hash(&mut hasher);
324 Instant::now().hash(&mut hasher);
325 thread::current().id().hash(&mut hasher);
326 hasher.finish()
327}
328
329#[cfg(test)]
330mod tests {
331 use std::collections::HashSet;
332
333 use proptest::prelude::*;
334
335 use super::*;
336
337 #[test]
338 fn node_no_generate() {
339 for _ in 0..1_000_000 {
340 NodeNo::generate();
341 }
342 }
343
344 #[test]
345 fn node_launch_id_generate() {
346 let count = 10;
347 let set: HashSet<_> = (0..count).map(|_| NodeLaunchId::generate()).collect();
348 assert_eq!(set.len(), count);
349 }
350
351 #[test]
352 fn group_no() {
353 let launch_ids = (0..5).map(|_| NodeLaunchId::generate()).collect::<Vec<_>>();
354
355 for launch_id in launch_ids {
356 assert_eq!(GroupNo::new(0, launch_id), None);
358
359 let set = (1..=u8::MAX)
361 .map(|no| GroupNo::new(no, launch_id).unwrap())
362 .collect::<HashSet<_>>();
363
364 assert_eq!(set.len(), usize::from(u8::MAX));
365 }
366 }
367
368 proptest! {
369 #[test]
370 fn addr(
371 slot_keys in prop::collection::hash_set(1u64..(1 << GROUP_NO_SHIFT), 10),
372 group_nos in prop::collection::hash_set(1..=u8::MAX, 10),
373 launch_ids in prop::collection::hash_set(1..=u64::MAX, 10),
374 ) {
375 #[cfg(feature = "network")]
376 let expected_count = slot_keys.len() * group_nos.len() * launch_ids.len();
377 #[cfg(not(feature = "network"))]
378 let expected_count = slot_keys.len() * group_nos.len();
379
380 let mut set = HashSet::with_capacity(expected_count);
381
382 for slot_key in &slot_keys {
383 for group_no in &group_nos {
384 for launch_id in &launch_ids {
385 let slot_key = Key::try_from(*slot_key).unwrap();
386 let launch_id = NodeLaunchId::from_bits(*launch_id).unwrap();
387 let group_no = GroupNo::new(*group_no, launch_id).unwrap();
388 let addr = Addr::new_local(slot_key, group_no, launch_id);
389 set.insert(addr);
390
391 prop_assert!(!addr.is_null());
392 prop_assert!(addr.is_local());
393 prop_assert_eq!(addr.group_no(), Some(group_no));
394 prop_assert_eq!(addr.node_no(), None);
395
396 let actual_slot_key = u64::from(addr.slot_key(launch_id).unwrap());
397 prop_assert_eq!(actual_slot_key & ((1 << GROUP_NO_SHIFT) - 1), u64::from(slot_key));
398 prop_assert_eq!(addr.into_local(), addr);
399 prop_assert_eq!(Addr::from_bits(addr.into_bits()), Some(addr));
400 prop_assert_eq!(addr.to_string().split('/').count(), 2);
401 prop_assert!(addr.to_string().starts_with(&group_no.to_string()));
402
403 #[cfg(feature = "network")]
404 {
405 prop_assert!(!addr.is_remote());
406 let node_no = NodeNo::from_bits(42).unwrap();
407 let remote = addr.into_remote(node_no);
408 prop_assert!(!remote.is_null());
409 prop_assert!(!remote.is_local());
410 prop_assert!(remote.is_remote());
411 prop_assert_eq!(remote.group_no(), Some(group_no));
412 prop_assert_eq!(remote.node_no(), Some(node_no));
413 prop_assert_eq!(addr.into_local(), addr);
414 prop_assert_eq!(remote.node_no_group_no() >> 8, u32::from(node_no.into_bits()));
415 prop_assert_eq!(remote.node_no_group_no() & 0xff, u32::from(group_no.into_bits()));
416 prop_assert_eq!(remote.to_string().split('/').count(), 3);
417 prop_assert!(remote.to_string().starts_with(&node_no.to_string()));
418 }
419 }
420 }
421 }
422
423 prop_assert_eq!(set.len(), expected_count);
425 }
426 }
427
428 #[test]
429 fn addr_null() {
430 let null = Addr::NULL;
431 assert_eq!(null.to_string(), "null");
432 assert!(null.is_null());
433 assert_eq!(null.into_local(), null);
434 assert_eq!(null.group_no(), None);
435 assert_eq!(null.node_no(), None);
436 #[cfg(feature = "network")]
437 {
438 assert!(!null.is_remote());
439 assert_eq!(null.into_remote(NodeNo::from_bits(42).unwrap()), null);
440 assert_eq!(null.node_no_group_no(), 0);
441 }
442 }
443
444 #[test]
445 fn addr_invalid() {
446 assert_eq!(Addr::from_bits(1), None);
447 }
448}