post_archiver/
id.rs

1use core::fmt;
2use serde::{Deserialize, Serialize};
3#[cfg(feature = "typescript")]
4use ts_rs::TS;
5
6/// Defines a strongly-typed numeric identifier type
7///
8/// # Safety
9/// - The value must never be negative
10/// - The maximum value is constrained by u32::MAX
11///
12/// # Examples
13/// ```rust
14/// use post_archiver::{AuthorId, PostId};
15///
16/// // Create an author ID
17/// let author_id = AuthorId::new(1);
18/// assert_eq!(author_id.raw(), 1);
19///
20/// // Convert from usize
21/// let id_from_usize = AuthorId::from(2_usize);
22/// assert_eq!(id_from_usize.to_string(), "2");
23///
24/// // Type safety demonstration
25/// let post_id = PostId::new(1);
26///
27/// // This will not compile:
28/// // let _: PostId = author_id;
29/// ```
30macro_rules! define_id {
31    ($(#[$meta:meta])*,$name:ident) => {
32        #[cfg_attr(feature = "typescript", derive(TS))]
33        #[cfg_attr(feature = "typescript", ts(export))]
34        #[derive(Deserialize, Serialize, Debug, Clone, Copy, Hash, PartialEq, Eq)]
35        pub struct $name(pub u32);
36
37        impl core::ops::Deref for $name {
38            type Target = u32;
39            fn deref(&self) -> &Self::Target {
40                &self.0
41            }
42        }
43
44        impl core::ops::DerefMut for $name {
45            fn deref_mut(&mut self) -> &mut Self::Target {
46                &mut self.0
47            }
48        }
49
50        impl From<u32> for $name {
51            fn from(f: u32) -> Self {
52                Self(f)
53            }
54        }
55
56        impl From<$name> for u32 {
57            fn from(t: $name) -> Self {
58                t.0
59            }
60        }
61
62        impl $name {
63            pub fn new(id: u32) -> Self {
64                Self(id)
65            }
66            /// get the raw value of the id
67            pub fn raw(&self) -> u32 {
68                self.0
69            }
70        }
71
72        impl From<usize> for $name {
73            fn from(id: usize) -> Self {
74                Self(id as u32)
75            }
76        }
77
78        impl From<$name> for usize {
79            fn from(id: $name) -> usize {
80                id.0 as usize
81            }
82        }
83
84        impl AsRef<u32> for $name {
85            fn as_ref(&self) -> &u32 {
86                &self.0
87            }
88        }
89
90        impl fmt::Display for $name {
91            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92                write!(f, "{}", self.0)
93            }
94        }
95
96        #[cfg(feature = "utils")]
97        impl rusqlite::types::FromSql for $name {
98            fn column_result(
99                value: rusqlite::types::ValueRef<'_>,
100            ) -> rusqlite::types::FromSqlResult<Self> {
101                Ok(Self(value.as_i64()? as u32))
102            }
103        }
104
105        #[cfg(feature = "utils")]
106        impl rusqlite::types::ToSql for $name {
107            fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
108                Ok(rusqlite::types::ToSqlOutput::Owned(
109                    rusqlite::types::Value::Integer(self.0 as i64),
110                ))
111            }
112        }
113    };
114}
115
116define_id!(
117/// Unique identifier for an author in the system
118///
119/// # Safety
120/// - The wrapped value must be a valid u32
121/// - Must maintain referential integrity when used as a foreign key
122,AuthorId);
123
124define_id!(
125/// Unique identifier for a post in the system
126///
127/// # Safety
128/// - The wrapped value must be a valid u32
129/// - Must maintain referential integrity when used as a foreign key
130,PostId);
131
132define_id!(
133/// Unique identifier for a file metadata entry in the system
134///
135/// # Safety
136/// - The wrapped value must be a valid u32
137/// - Must maintain referential integrity when used as a foreign key
138,FileMetaId);
139
140define_id!(
141/// Unique identifier for a post tag in the system
142///
143/// # Safety
144/// - The wrapped value must be a valid u32
145/// - Must maintain referential integrity when used as a foreign key
146,TagId);
147
148define_id!(
149/// Unique identifier for a post tag that is platform-specific
150///
151/// # Safety
152/// - The wrapped value must be a valid u32
153/// - Must maintain referential integrity when used as a foreign key
154,PlatformTagId);
155
156define_id!(
157/// Unique identifier for a platform in the system
158///
159/// # Safety
160/// - The wrapped value must be a valid u32
161/// - Must maintain referential integrity when used as a foreign key
162,PlatformId);
163
164define_id!(
165/// Unique identifier for a collection in the system
166///
167/// # Safety
168/// - The wrapped value must be a valid u32
169/// - Must maintain referential integrity when used as a foreign key
170,CollectionId);