1use crate::{ID_STATE16, SemanticKey};
2use std::{
3 fmt::{Debug, Display, Formatter, LowerHex},
4 hash::{Hash, Hasher},
5 marker::PhantomData,
6 num::ParseIntError,
7 str::FromStr,
8};
9
10#[cfg(feature = "sea-orm")]
11mod for_orm;
12#[cfg(feature = "poem-openapi")]
13mod for_poem;
14#[cfg(feature = "serde")]
15mod for_serde;
16
17#[cfg(feature = "uuid")]
18mod for_uuid;
19
20#[cfg(feature = "sqlx")]
21mod for_sqlx_pgsql;
22
23pub struct Semantic64<K> {
31 id: u64,
32 kind: PhantomData<K>,
33}
34
35impl<K> Copy for Semantic64<K> {}
36
37impl<K> Clone for Semantic64<K> {
38 fn clone(&self) -> Self {
39 Self { id: self.id, kind: self.kind }
40 }
41}
42
43impl<K> Hash for Semantic64<K> {
44 fn hash<H: Hasher>(&self, state: &mut H) {
45 self.id.hash(state);
46 }
47}
48
49impl<K> PartialEq for Semantic64<K> {
50 fn eq(&self, other: &Self) -> bool {
51 self.id.eq(&other.id)
52 }
53}
54
55impl<K> Eq for Semantic64<K> {}
56
57impl<K: SemanticKey> Debug for Semantic64<K> {
58 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
59 match K::KEY {
60 "" => write!(f, "{}", self.id),
61 s => write!(f, "{}-{}", s, self.id),
62 }
63 }
64}
65
66impl<K: SemanticKey> Display for Semantic64<K> {
67 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
68 match K::KEY {
69 "" => write!(f, "{}", self.id),
70 s => write!(f, "{}-{}", s, base36(self.id)),
71 }
72 }
73}
74
75fn base36(mut n: u64) -> String {
76 if n == 0 {
77 return "0".to_string();
78 }
79 const BASE36_CHARS: &[u8] = b"0123456789abcdefghijklmnopqrstuvwxyz";
80 let mut result = Vec::with_capacity(11);
82 while n > 0 {
83 let remainder = n as usize % 36;
84 result.push(BASE36_CHARS[remainder]);
86 n /= 36;
87 }
88
89 unsafe {
90 result.reverse();
91 String::from_utf8_unchecked(result)
92 }
93}
94
95impl<K> LowerHex for Semantic64<K> {
96 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
97 LowerHex::fmt(&self.id, f)
98 }
99}
100
101impl<K> Default for Semantic64<K> {
102 fn default() -> Self {
103 Self { id: 0, kind: Default::default() }
104 }
105}
106
107impl<K> FromStr for Semantic64<K> {
108 type Err = ParseIntError;
109
110 fn from_str(s: &str) -> Result<Self, Self::Err> {
111 let mut parts = s.rsplit('-');
112 match parts.next() {
113 Some(s) => {
114 let id = u64::from_str_radix(&s, 36)?;
115 Ok(Self { id, kind: Default::default() })
116 }
117 None => Ok(Self::default()),
118 }
119 }
120}
121
122impl<K> From<i64> for Semantic64<K> {
123 fn from(value: i64) -> Self {
124 unsafe { std::mem::transmute(value) }
125 }
126}
127
128impl<K> From<u64> for Semantic64<K> {
129 fn from(value: u64) -> Self {
130 Self { id: value, kind: Default::default() }
131 }
132}
133
134impl<K> Semantic64<K> {
135 pub fn new(unix_ms: u64) -> Semantic64<K> {
136 Self { id: ID_STATE16.lock().unwrap().generate64_by(unix_ms), kind: Default::default() }
137 }
138 pub fn now() -> Self {
139 Self { id: ID_STATE16.lock().unwrap().generate64_now(), kind: Default::default() }
140 }
141 pub fn as_u64(&self) -> u64 {
142 self.id
143 }
144 pub fn as_i64(&self) -> i64 {
145 unsafe { std::mem::transmute(self.id) }
146 }
147}