use core::fmt;
use serde::{Deserialize, Serialize};
#[cfg(feature = "typescript")]
use ts_rs::TS;
use crate::{Author, Collection, FileMeta, Platform, Post, Tag};
pub trait HasId {
type Id: std::hash::Hash + Eq + Clone;
fn id(&self) -> Self::Id;
}
macro_rules! define_id {
($(#[$meta:meta])*,$table:ty : $name:ident) => {
#[cfg_attr(feature = "typescript", derive(TS))]
#[cfg_attr(feature = "typescript", ts(export))]
#[derive(Deserialize, Serialize, Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct $name(pub u32);
impl core::ops::Deref for $name {
type Target = u32;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl core::ops::DerefMut for $name {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl From<u32> for $name {
fn from(f: u32) -> Self {
Self(f)
}
}
impl From<$name> for u32 {
fn from(t: $name) -> Self {
t.0
}
}
impl $name {
pub fn new(id: u32) -> Self {
Self(id)
}
pub fn raw(&self) -> u32 {
self.0
}
}
impl From<usize> for $name {
fn from(id: usize) -> Self {
Self(id as u32)
}
}
impl From<$name> for usize {
fn from(id: $name) -> usize {
id.0 as usize
}
}
impl AsRef<u32> for $name {
fn as_ref(&self) -> &u32 {
&self.0
}
}
impl fmt::Display for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[cfg(feature = "utils")]
impl rusqlite::types::FromSql for $name {
fn column_result(
value: rusqlite::types::ValueRef<'_>,
) -> rusqlite::types::FromSqlResult<Self> {
Ok(Self(value.as_i64()? as u32))
}
}
#[cfg(feature = "utils")]
impl rusqlite::types::ToSql for $name {
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
Ok(rusqlite::types::ToSqlOutput::Owned(
rusqlite::types::Value::Integer(self.0 as i64),
))
}
}
#[cfg(feature = "utils")]
impl crate::id::HasId for $table {
type Id = $name;
fn id(&self) -> $name {
self.id.clone()
}
}
};
}
define_id!(
,Author: AuthorId);
define_id!(
,Post: PostId);
define_id!(
,FileMeta: FileMetaId);
define_id!(
,Tag: TagId);
define_id!(
,Platform: PlatformId);
define_id!(
,Collection: CollectionId);