use std::{
any,
fmt::{Debug, Display, Formatter, Result as FmtResult},
hash::{Hash, Hasher},
marker::PhantomData,
};
use serde::de::{Deserialize, Error as DeError, Visitor};
use serde::ser::Serialize;
use serde::{Deserializer, Serializer};
use uuid::Uuid;
pub mod marker;
#[derive(Clone)]
pub struct Id<M> {
phantom: PhantomData<M>,
value: IdValue,
}
impl<M> Id<M> {
pub fn value(&self) -> IdValue {
self.value.clone()
}
}
impl<M> Debug for Id<M> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.write_str("Id")?;
let marker_name = any::type_name::<M>();
if let Some(pos) = marker_name.rfind("::") {
if let Some(slice) = marker_name.get(pos + 2..) {
f.write_str("<")?;
f.write_str(slice)?;
f.write_str(">")?;
}
} else {
f.write_str("<")?;
f.write_str(marker_name)?;
f.write_str(">")?;
}
f.write_str("(")?;
Debug::fmt(&self.value, f)?;
f.write_str(")")
}
}
impl<'de, M> Deserialize<'de> for Id<M> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(IdDeserializerVisitor::new())
}
}
impl<M> Hash for Id<M> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.value.hash(state)
}
}
impl<M> Serialize for Id<M> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_str(&format_args!("{:?}", self.value))
}
}
pub(in crate::id) struct IdDeserializerVisitor<M> {
phantom: PhantomData<M>,
}
impl<M> IdDeserializerVisitor<M> {
const fn new() -> Self {
Self {
phantom: PhantomData,
}
}
}
impl<'de, M> Visitor<'de> for IdDeserializerVisitor<M> {
type Value = Id<M>;
fn expecting(&self, f: &mut Formatter) -> FmtResult {
f.write_str("a valid guilded id")
}
fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
where
E: DeError,
{
Ok(Id {
phantom: PhantomData,
value: IdValue::Int(v),
})
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: DeError,
{
if let Ok(int) = v.parse::<u32>() {
return self.visit_u32(int);
}
if let Ok(uuid) = v.parse::<Uuid>() {
return Ok(Id {
phantom: PhantomData,
value: IdValue::Uuid(uuid),
});
}
Ok(Id {
phantom: PhantomData,
value: IdValue::AlphanumericId(v.to_string()),
})
}
fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(IdDeserializerVisitor::new())
}
}
#[derive(Clone)]
pub enum IdValue {
AlphanumericId(String),
Int(u32),
Uuid(Uuid),
}
impl IdValue {
pub fn unwrap_alphanumeric(self) -> String {
if let Self::AlphanumericId(id) = self {
return id;
}
panic!("id not alphanumeric")
}
pub fn unwrap_uuid(self) -> String {
if let Self::Uuid(id) = self {
return id.hyphenated().to_string();
}
panic!("id not uuid")
}
}
impl Debug for IdValue {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
Self::AlphanumericId(id) => Display::fmt(id, f),
Self::Int(id) => Display::fmt(id, f),
Self::Uuid(uuid) => Display::fmt(uuid, f),
}
}
}
impl Hash for IdValue {
fn hash<H: Hasher>(&self, state: &mut H) {
match self {
Self::AlphanumericId(id) => state.write(id.as_bytes()),
Self::Int(id) => state.write_u32(*id),
Self::Uuid(id) => state.write(id.as_bytes().as_slice()),
}
}
}