use core::{cell::Cell, fmt::Debug, marker::PhantomData, num::NonZeroU64};
#[cfg(feature = "std")]
use rand::{thread_rng, Rng};
use rapira::{Rapira, RapiraError};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "std")]
use time::{Instant, OffsetDateTime};
use super::{enc::IdHasher, ArmourError, IdStr};
use crate::{Cid, GetType, KeyScheme, KeyType, Typ};
const TS_DIFF: u64 = 0x0187_6300_0000;
const TS_BITS: u32 = 40;
const TS_SHIFT: u32 = u64::BITS - TS_BITS;
const APP_BITS: u32 = 4;
const APP_SHIFT: u32 = TS_SHIFT - APP_BITS;
const APP_ID_MAX: u64 = (1 << APP_BITS) - 1;
const THREAD_BITS: u32 = 5;
const THREAD_SHIFT: u32 = APP_SHIFT - THREAD_BITS;
const THREAD_ID_MAX: u64 = (1 << THREAD_BITS) - 1;
const SEQ_BITS: u32 = u64::BITS - TS_BITS - APP_BITS - THREAD_BITS;
const SEQ_MAX: u64 = (1 << SEQ_BITS) - 1;
#[derive(Debug, Clone, Copy, Default)]
struct SeqForMs {
ms: u16,
seq: u64,
count: u64,
}
impl SeqForMs {
#[cfg(feature = "std")]
#[inline]
fn new(ms: u16) -> Self {
let seq = thread_rng().gen_range(0..=SEQ_MAX);
SeqForMs { ms, seq, count: 0 }
}
}
thread_local! {
static SEQ_CHECK: Cell<SeqForMs> = Cell::new(SeqForMs::default());
}
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct Fuid<H>(NonZeroU64, PhantomData<H>);
impl<H> Fuid<H> {
#[cfg(feature = "std")]
pub fn new(instance_id: u64, thread_id: u64) -> Self {
debug_assert!(instance_id <= APP_ID_MAX);
debug_assert!(thread_id <= THREAD_ID_MAX);
let now = OffsetDateTime::now_utc();
let ts = (now.unix_timestamp() as u64) * 1000;
let nanos = now.nanosecond();
let ms = (nanos / 1_000_000) as u16;
let ts = ts + (ms as u64);
let ts = ts - TS_DIFF;
let ts = ts << TS_SHIFT;
let ts = ts | (instance_id << APP_SHIFT);
let ts = ts | (thread_id << THREAD_SHIFT);
let mut seq_check = SEQ_CHECK.get();
if seq_check.ms == ms {
if seq_check.count == SEQ_MAX {
let instant = Instant::now();
let nanos = now.nanosecond();
let nanos = nanos % 1_000_000;
let wait_nanos = (1_000_000 - nanos) as i128;
loop {
let duration = instant.elapsed();
let elapsed_nanos = duration.whole_nanoseconds();
if elapsed_nanos >= wait_nanos {
break;
}
core::hint::spin_loop();
}
seq_check = SeqForMs::new(ms);
SEQ_CHECK.set(seq_check);
} else {
seq_check.seq = seq_check.seq.wrapping_add(1);
seq_check.count += 1;
SEQ_CHECK.set(seq_check);
}
} else {
seq_check = SeqForMs::new(ms);
SEQ_CHECK.set(seq_check);
}
let ts = ts | seq_check.seq;
Self(NonZeroU64::new(ts).unwrap(), PhantomData)
}
pub fn date(&self) -> OffsetDateTime {
let ts = self.0.get() >> TS_SHIFT;
let ts = ts + TS_DIFF;
let ts = ts as i128;
let ts = ts * 1_000_000;
let dt = OffsetDateTime::from_unix_timestamp_nanos(ts);
dt.unwrap()
}
}
impl<H: IdHasher> Fuid<H> {
pub fn ser(&self) -> IdStr {
H::ser(self.0.get())
}
pub fn deser(id: &str) -> Result<Self, ArmourError> {
H::deser(id).and_then(|id| {
let id = NonZeroU64::new(id).ok_or(ArmourError::NonZeroError)?;
Ok(Self(id, PhantomData))
})
}
}
impl<H> Rapira for Fuid<H> {
const STATIC_SIZE: Option<usize> = Some(8);
fn size(&self) -> usize {
8
}
fn check_bytes(slice: &mut &[u8]) -> rapira::Result<()> {
let bytes: &[u8] = slice.get(..8).ok_or(RapiraError::SliceLenError)?;
if bytes == u64::MIN.to_le_bytes() {
return Err(RapiraError::NonZeroError);
}
*slice = unsafe { slice.get_unchecked(8..) };
Ok(())
}
fn from_slice(slice: &mut &[u8]) -> rapira::Result<Self>
where
Self: Sized,
{
let u = u64::from_slice(slice)?;
let id = NonZeroU64::new(u).ok_or(RapiraError::NonZeroError)?;
Ok(Self(id, PhantomData))
}
fn convert_to_bytes(&self, slice: &mut [u8], cursor: &mut usize) {
self.0.get().convert_to_bytes(slice, cursor);
}
}
impl<H> GetType for Fuid<H> {
const TYPE: Typ = Typ::U64;
}
impl<H: Ord> Cid for Fuid<H> {
type B = [u8; 8];
const TY: KeyScheme = KeyScheme::Typed(&[KeyType::U64]);
const GROUP_BITS: u32 = TS_BITS - 30;
fn encode(&self) -> Self::B {
self.0.get().to_be_bytes()
}
fn decode(bytes: &Self::B) -> super::Result<Self> {
let u = u64::from_be_bytes(*bytes);
let u = NonZeroU64::new(u).ok_or(ArmourError::NonZeroError)?;
let id = Self(u, PhantomData);
Ok(id)
}
fn group_id(&self) -> u32 {
(self.0.get() >> (u64::BITS - Self::GROUP_BITS)) as u32
}
}
impl<H: IdHasher> std::fmt::Display for Fuid<H> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.ser())
}
}
impl<H> Debug for Fuid<H> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let id = self.0.get();
let id = format!("{id:#X}");
f.debug_tuple("Fuid").field(&id).finish()
}
}
#[cfg(feature = "std")]
impl<T: IdHasher> Serialize for Fuid<T> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let s = self.ser();
serializer.serialize_str(&s)
}
}
#[cfg(feature = "std")]
impl<'de, T: IdHasher> Deserialize<'de> for Fuid<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::Error;
let s: &str = Deserialize::deserialize(deserializer)?;
let a = Fuid::<T>::deser(s).map_err(|_| D::Error::custom("id value error"))?;
Ok(a)
}
}