use once_cell::sync::Lazy;
use rand::Rng;
use std::fmt::{Debug, Formatter};
use std::sync::atomic::{AtomicU32, Ordering};
use std::time::{SystemTime, UNIX_EPOCH};
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct ObjectId {
bytes: [u8; 12],
}
impl Default for ObjectId {
fn default() -> Self {
Self::new()
}
}
impl ObjectId {
pub fn new() -> ObjectId {
let timestamp = ObjectId::gen_timestamp();
let process_id = ObjectId::gen_process_id();
let counter = ObjectId::gen_count();
let mut buf: [u8; 12] = [0; 12];
buf[0..][..4].clone_from_slice(×tamp[..]);
buf[4..][..5].clone_from_slice(&process_id[..]);
buf[9..][..3].clone_from_slice(&counter[..]);
ObjectId::from_bytes(&buf)
}
fn gen_timestamp() -> [u8; 4] {
let timestamp: u32 = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs() as u32;
timestamp.to_be_bytes()
}
fn gen_process_id() -> [u8; 5] {
static BUF: Lazy<[u8; 5]> = Lazy::new(rand::random);
*BUF
}
fn gen_count() -> [u8; 3] {
static OID_COUNTER: Lazy<AtomicU32> =
Lazy::new(|| AtomicU32::new(rand::thread_rng().gen_range(0..=0xFF_FF_FF)));
let u_counter = OID_COUNTER.fetch_add(1, Ordering::SeqCst);
let u_int = u_counter % 0x1_00_00_00;
let buf = u_int.to_be_bytes();
let buf_u24: [u8; 3] = [buf[1], buf[2], buf[3]];
buf_u24
}
}
impl ObjectId {
pub fn from_bytes(bytes: &[u8; 12]) -> Self {
Self { bytes: *bytes }
}
}
impl Debug for ObjectId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut buffer = [0u8; b"ObjectId(012345678901234567890123)".len()];
buffer[0..b"ObjectId(".len()].copy_from_slice(b"ObjectId(");
hex::encode_to_slice(self.bytes, &mut buffer[b"ObjectId(".len()..][..24]).unwrap();
buffer[buffer.len() - 1] = b')';
f.write_str(unsafe { std::str::from_utf8_unchecked(&buffer) })
}
}
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct DateTime(u64);
impl DateTime {
pub fn now() -> DateTime {
let now = SystemTime::now();
let duration = now.duration_since(UNIX_EPOCH).unwrap();
Self(duration.as_millis() as u64)
}
}
impl DateTime {
pub fn from_millis_since_epoch(millis: u64) -> Self {
Self(millis)
}
pub fn as_millis_since_epoch(&self) -> u64 {
self.0
}
}
impl Debug for DateTime {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("DateTime({})", self.0))
}
}