use base64::Engine;
use base64::engine::general_purpose;
use core::fmt;
use core::ops::Deref;
use std::str::FromStr;
use crate::error::Error;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SnowflakeId(u64);
impl SnowflakeId {
#[must_use]
pub fn new(raw: u64) -> Self {
Self(raw)
}
#[must_use]
pub fn as_u64(&self) -> u64 {
self.0
}
#[must_use]
pub fn hex(&self) -> String {
format!("{:x}", self.0)
}
#[must_use]
pub fn base2(&self) -> String {
format!("{:b}", self.0)
}
#[must_use]
pub fn base32(&self) -> String {
const ENCODE_BASE32_MAP: &str = "ybndrfg8ejkmcpqxot1uwisza345h769";
let mut id = self.0;
if id < 32 {
return ENCODE_BASE32_MAP
.chars()
.nth(id as usize)
.unwrap()
.to_string();
}
let mut b = Vec::new();
while id >= 32 {
b.push(ENCODE_BASE32_MAP.chars().nth((id % 32) as usize).unwrap());
id /= 32;
}
b.push(ENCODE_BASE32_MAP.chars().nth(id as usize).unwrap());
b.reverse();
b.into_iter().collect()
}
#[must_use]
pub fn base36(&self) -> String {
const CHARSET: &[u8; 36] = b"0123456789abcdefghijklmnopqrstuvwxyz";
let mut id = self.0;
if id == 0 {
return "0".to_string();
}
let mut buf = Vec::new();
while id > 0 {
buf.push(CHARSET[(id % 36) as usize]);
id /= 36;
}
buf.reverse();
String::from_utf8(buf).expect("base36 charset is valid UTF-8")
}
#[must_use]
pub fn base58(&self) -> String {
const ENCODE_BASE58_MAP: &str =
"123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
let mut id = self.0;
if id < 58 {
return ENCODE_BASE58_MAP
.chars()
.nth(id as usize)
.unwrap()
.to_string();
}
let mut b = Vec::new();
while id >= 58 {
b.push(ENCODE_BASE58_MAP.chars().nth((id % 58) as usize).unwrap());
id /= 58;
}
b.push(ENCODE_BASE58_MAP.chars().nth(id as usize).unwrap());
b.reverse();
b.into_iter().collect()
}
#[must_use]
pub fn base64(&self) -> String {
general_purpose::STANDARD.encode(self.0.to_be_bytes())
}
#[must_use]
pub fn string(&self) -> String {
self.0.to_string()
}
#[must_use]
pub fn bytes(&self) -> Vec<u8> {
self.0.to_string().into_bytes()
}
#[must_use]
pub fn int_bytes(&self) -> [u8; 8] {
self.0.to_be_bytes()
}
#[must_use]
pub fn int64(&self) -> i64 {
self.0 as i64
}
}
impl fmt::Display for SnowflakeId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<u64> for SnowflakeId {
fn from(raw: u64) -> Self {
Self(raw)
}
}
impl From<SnowflakeId> for u64 {
fn from(id: SnowflakeId) -> u64 {
id.0
}
}
impl AsRef<u64> for SnowflakeId {
fn as_ref(&self) -> &u64 {
&self.0
}
}
impl Deref for SnowflakeId {
type Target = u64;
fn deref(&self) -> &u64 {
&self.0
}
}
impl Ord for SnowflakeId {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.cmp(&other.0)
}
}
impl PartialOrd for SnowflakeId {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl PartialOrd<u64> for SnowflakeId {
fn partial_cmp(&self, other: &u64) -> Option<std::cmp::Ordering> {
self.0.partial_cmp(other)
}
}
impl PartialEq<u64> for SnowflakeId {
fn eq(&self, other: &u64) -> bool {
self.0 == *other
}
}
impl FromStr for SnowflakeId {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Some(hex) = s.strip_prefix("0x").or_else(|| s.strip_prefix("0X")) {
u64::from_str_radix(hex, 16)
.map(SnowflakeId)
.map_err(|e| Error::ParseIdFailed(e.to_string()))
} else {
s.parse::<u64>()
.map(SnowflakeId)
.map_err(|e| Error::ParseIdFailed(e.to_string()))
}
}
}
impl TryFrom<String> for SnowflakeId {
type Error = Error;
fn try_from(s: String) -> Result<Self, Self::Error> {
s.parse()
}
}
impl TryFrom<&str> for SnowflakeId {
type Error = Error;
fn try_from(s: &str) -> Result<Self, Self::Error> {
s.parse()
}
}
impl TryFrom<i64> for SnowflakeId {
type Error = Error;
fn try_from(value: i64) -> Result<Self, Self::Error> {
if value < 0 {
Err(Error::ParseIdFailed(format!("negative value: {value}")))
} else {
Ok(SnowflakeId(value as u64))
}
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for SnowflakeId {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_u64(self.0)
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for SnowflakeId {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let raw = u64::deserialize(deserializer)?;
Ok(SnowflakeId(raw))
}
}
#[cfg(feature = "serde")]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SnowflakeIdString(pub SnowflakeId);
#[cfg(feature = "serde")]
impl serde::Serialize for SnowflakeIdString {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&self.0.to_string())
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for SnowflakeIdString {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let s = String::deserialize(deserializer)?;
let id: SnowflakeId = s.parse().map_err(serde::de::Error::custom)?;
Ok(SnowflakeIdString(id))
}
}
#[cfg(feature = "serde")]
impl fmt::Display for SnowflakeIdString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}