use std::fmt;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::generator::{MAX_TIMESTAMP, SEQUENCE_BITS, WORKER_BITS};
const WORKER_MASK: u64 = (1_u64 << WORKER_BITS) - 1;
const SEQUENCE_MASK: u64 = (1_u64 << SEQUENCE_BITS) - 1;
const SEQUENCE_SHIFT: u32 = WORKER_BITS;
const TIMESTAMP_SHIFT: u32 = WORKER_BITS + SEQUENCE_BITS;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct BeakId(i64);
impl BeakId {
#[must_use]
pub const fn new(value: i64) -> Self {
Self(value)
}
#[must_use]
pub const fn as_i64(self) -> i64 {
self.0
}
#[must_use]
pub const fn timestamp_window(self) -> u64 {
((self.0 as u64) >> TIMESTAMP_SHIFT) & MAX_TIMESTAMP
}
#[must_use]
pub const fn sequence(self) -> u64 {
((self.0 as u64) >> SEQUENCE_SHIFT) & SEQUENCE_MASK
}
#[must_use]
pub const fn worker_id(self) -> u16 {
(self.0 as u64 & WORKER_MASK) as u16
}
#[must_use]
pub const fn parts(self) -> (u64, u64, u16) {
(self.timestamp_window(), self.sequence(), self.worker_id())
}
pub fn from_base62(s: &str) -> Result<Self, crate::BeakIdError> {
const LEN: usize = 11;
if s.len() != LEN {
return Err(crate::BeakIdError::InvalidBase62);
}
let mut n = 0i64;
for &byte in s.as_bytes() {
let digit = match byte {
b'0'..=b'9' => (byte - b'0') as i64,
b'A'..=b'Z' => (byte - b'A' + 10) as i64,
b'a'..=b'z' => (byte - b'a' + 36) as i64,
_ => return Err(crate::BeakIdError::InvalidBase62),
};
n = n
.checked_mul(62)
.and_then(|n| n.checked_add(digit))
.ok_or(crate::BeakIdError::InvalidBase62)?;
}
Ok(BeakId(n))
}
pub fn base62(&self) -> String {
const ALPHABET: &[u8; 62] =
b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
const LEN: usize = 11;
let mut buf = [b'0'; LEN];
let mut n = self.0;
for i in (0..LEN).rev() {
buf[i] = ALPHABET[(n % 62) as usize];
n /= 62;
}
unsafe { String::from_utf8_unchecked(buf.to_vec()) }
}
}
impl From<i64> for BeakId {
fn from(value: i64) -> Self {
Self::new(value)
}
}
impl From<BeakId> for i64 {
fn from(id: BeakId) -> Self {
id.as_i64()
}
}
impl fmt::Display for BeakId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(formatter)
}
}
impl Serialize for BeakId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if serializer.is_human_readable() {
let encoded = self.base62();
serializer.serialize_str(&encoded)
} else {
serializer.serialize_i64(self.0)
}
}
}
impl<'de> Deserialize<'de> for BeakId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
if deserializer.is_human_readable() {
let s = String::deserialize(deserializer)?;
Self::from_base62(&s).map_err(serde::de::Error::custom)
} else {
let val = i64::deserialize(deserializer)?;
Ok(BeakId(val))
}
}
}