use serde::{Deserialize, Serialize};
use std::{
fmt::{Display, Formatter},
num::ParseIntError,
str::FromStr,
};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Deserialize, Serialize)]
#[serde(untagged)]
pub enum Id {
Number(u64),
String(String),
Null,
}
impl Id {
pub const ZERO: Id = Id::Number(0);
pub fn is_null(&self) -> bool {
matches!(self, Self::Null)
}
}
impl<T: Into<u64>> From<T> for Id {
fn from(value: T) -> Self {
Id::Number(value.into())
}
}
impl Display for Id {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Id::Number(id) => Display::fmt(id, f),
Id::String(id) => Display::fmt(id, f),
Id::Null => f.write_str("null"),
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
pub struct ConstantSizeId(u64);
impl<T: Into<u64>> From<T> for ConstantSizeId {
fn from(value: T) -> Self {
Self(value.into())
}
}
impl Display for ConstantSizeId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.to_constant_size_string(), f)
}
}
impl ConstantSizeId {
pub const ZERO: ConstantSizeId = ConstantSizeId(0);
pub const MAX: ConstantSizeId = ConstantSizeId(u64::MAX);
pub fn get_and_increment(&mut self) -> ConstantSizeId {
let previous = self.0;
self.0 = self.0.wrapping_add(1);
ConstantSizeId::from(previous)
}
fn to_constant_size_string(&self) -> String {
format!("{:0>20}", self.0)
}
}
impl From<ConstantSizeId> for Id {
fn from(value: ConstantSizeId) -> Self {
Id::String(value.to_string())
}
}
impl FromStr for ConstantSizeId {
type Err = ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let num = match s.find(|c| c != '0') {
Some(non_zero_index) => s[non_zero_index..].parse::<u64>(),
None => s.parse::<u64>(),
};
num.map(ConstantSizeId::from)
}
}