1use serde::{Deserialize, Serialize};
2use std::fmt::{self, Display};
3use std::ops::Deref;
4use uuid::Uuid;
5
6macro_rules! newtype_string {
8 ($(#[$attr:meta])* $vis:vis $name:ident) => {
9 $(#[$attr])*
10 #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
11 #[serde(transparent)]
12 $vis struct $name(String);
13
14 impl $name {
15 pub fn new<T: Into<String>>(value: T) -> Self {
17 Self(value.into())
18 }
19
20 pub fn as_str(&self) -> &str {
22 &self.0
23 }
24 }
25
26 impl Deref for $name {
27 type Target = str;
28 fn deref(&self) -> &Self::Target {
29 &self.0
30 }
31 }
32
33 impl Display for $name {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 write!(f, "{}", self.0)
36 }
37 }
38
39 impl AsRef<str> for $name {
40 fn as_ref(&self) -> &str {
41 &self.0
42 }
43 }
44 };
45}
46
47macro_rules! newtype_uuid {
49 ($(#[$attr:meta])* $vis:vis $name:ident) => {
50 $(#[$attr])*
51 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
52 #[serde(transparent)]
53 $vis struct $name(Uuid);
54
55 impl $name {
56 pub const fn new(value: Uuid) -> Self {
58 Self(value)
59 }
60
61 pub fn parse(value: &str) -> Result<Self, uuid::Error> {
63 Ok(Self(Uuid::parse_str(value)?))
64 }
65
66 pub const fn as_uuid(&self) -> &Uuid {
68 &self.0
69 }
70 }
71
72 impl Display for $name {
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 write!(f, "{}", self.0)
75 }
76 }
77
78 impl From<Uuid> for $name {
79 fn from(uuid: Uuid) -> Self {
80 Self(uuid)
81 }
82 }
83 };
84}
85
86newtype_string!(
87 pub BearerToken
89);
90
91newtype_string!(
92 pub ApiKey
94);
95
96#[derive(Debug, Clone, PartialEq, Eq)]
102pub enum Auth {
103 Bearer(BearerToken),
105 ApiKey(ApiKey),
107}
108
109impl Auth {
110 pub fn bearer<T: Into<String>>(token: T) -> Self {
112 Self::Bearer(BearerToken::new(token))
113 }
114
115 pub fn api_key<T: Into<String>>(key: T) -> Self {
117 Self::ApiKey(ApiKey::new(key))
118 }
119}
120
121impl From<BearerToken> for Auth {
122 fn from(token: BearerToken) -> Self {
123 Self::Bearer(token)
124 }
125}
126
127impl From<ApiKey> for Auth {
128 fn from(key: ApiKey) -> Self {
129 Self::ApiKey(key)
130 }
131}
132
133newtype_uuid!(
134 pub AccountId
136);
137
138newtype_uuid!(
139 pub CategoryId
141);
142
143newtype_uuid!(
144 pub MerchantId
146);
147
148newtype_uuid!(
149 pub TagId
151);
152
153newtype_uuid!(
154 pub TransactionId
156);
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161
162 #[test]
163 fn test_bearer_token() {
164 let token = BearerToken::new("test_token");
165 assert_eq!(token.as_str(), "test_token");
166 assert_eq!(&*token, "test_token");
167 assert_eq!(token.to_string(), "test_token");
168 }
169
170 #[test]
171 fn test_uuid_types() {
172 let uuid = Uuid::new_v4();
173 let account_id = AccountId::new(uuid);
174 assert_eq!(account_id.as_uuid(), &uuid);
175 assert_eq!(account_id.to_string(), uuid.to_string());
176
177 let parsed = AccountId::parse(&uuid.to_string())
178 .expect("UUID parsing should succeed for valid UUID string");
179 assert_eq!(parsed, account_id);
180 }
181}