use crate::*;
use std::{
time::{SystemTime, Instant, Duration},
hash::{BuildHasher, Hasher, Hash},
};
use portable_atomic::AtomicU64;
pub trait Id {
fn namespace(self) -> u64;
fn count(self) -> u64;
}
impl Id for u128 {
fn namespace(self) -> u64 {
(self >> 64) as u64
}
fn count(self) -> u64 {
self as u64
}
}
impl Id for (u64, u64) {
fn namespace(self) -> u64 {
self.0
}
fn count(self) -> u64 {
self.1
}
}
pub struct ID {
prefix: u128,
counter: AtomicU64,
}
impl ID {
#[inline(always)]
pub const fn is_special_ns(ns: u64) -> bool {
const STARTS_WITH_BIT_1: u64 = 1 << 63;
ns < STARTS_WITH_BIT_1
}
#[inline(always)]
pub const fn from_bytes(bytes: &[u8]) -> Option<Self> {
if let Some(this) = Self::_from_bytes(bytes) {
if ! this.is_special() {
return Some(this);
}
}
None
}
#[inline(always)]
const fn _from_bytes(bytes: &[u8]) -> Option<Self> {
match bytes.len() {
8 => {
let ns = u64::from_be_bytes(option_try!(slice_to_array(bytes, 0)));
Some(Self::_new(ns))
},
16 => {
let ns = u64::from_be_bytes(option_try!(slice_to_array(bytes, 0)));
let count = u64::from_be_bytes(option_try!(slice_to_array(bytes, 8)));
Some(Self::_init(ns, count))
},
_ => None
}
}
#[inline(always)]
pub const fn new(ns: u64) -> Option<Self> {
if Self::is_special_ns(ns) {
return None;
}
Some(Self::_new(ns))
}
#[inline(always)]
const fn _new(ns: u64) -> Self {
Self::_init(ns, 1)
}
#[inline(always)]
pub const fn init(ns: u64, count: u64) -> Option<Self> {
let this = Self::_init(ns, count);
if this.is_special() {
return None;
}
Some(this)
}
#[inline(always)]
const fn _init(ns: u64, count: u64) -> Self {
Self {
prefix: (ns as u128) << 64,
counter: AtomicU64::new(count),
}
}
#[inline(always)]
pub const fn is_special(&self) -> bool {
const STARTS_WITH_BIT_1: u128 = 1 << 127;
self.prefix < STARTS_WITH_BIT_1
}
#[inline(always)]
pub fn auto_ns() -> Self {
#[allow(dead_code)]
struct NonClone(u8);
static SEED: u128 = 36737317109501180927066999484774518054;
const ZERO_DUR: Duration = Duration::new(0, 0);
let mut t;
let mut ns;
let mut h = ahash::RandomState::new().build_hasher();
std::process::id().hash(&mut h);
std::thread::current().id().hash(&mut h);
SEED.hash(&mut h); core::ptr::addr_of!(SEED).hash(&mut h); core::ptr::addr_of!(h).hash(&mut h); loop {
#[allow(unused_allocation)]
(Box::new(NonClone(123)).as_ref() as *const NonClone).hash(&mut h);
SystemTime::now().hash(&mut h);
t = Instant::now();
t.hash(&mut h);
std::thread::sleep(ZERO_DUR);
std::thread::park_timeout(ZERO_DUR);
t.elapsed().hash(&mut h);
ns = h.finish();
if Self::is_special_ns(ns) {
continue;
}
return Self::_new(ns);
}
}
#[inline(always)]
pub fn generate(&self) -> Option<u128> {
let count = self.counter.checked_add(1)?;
Some(
self.prefix | (count as u128)
)
}
}
pub static GLOBAL_ID: ID = option_unwrap!(ID::_from_bytes(b"__GLOBAL"));
pub(crate) static EXECUTOR_ID: ID = option_unwrap!(ID::_from_bytes(b"EXECUTOR"));
pub(crate) static TASK_ID: ID = option_unwrap!(ID::_from_bytes(b"TASK ID."));
#[inline(always)]
pub fn gen_global_id() -> Option<u128> {
GLOBAL_ID.generate()
}
#[inline(always)]
pub(crate) fn gen_executor_id() -> Option<u128> {
EXECUTOR_ID.generate()
}
#[inline(always)]
pub(crate) fn gen_task_id() -> Option<u128> {
TASK_ID.generate()
}