1use candid::CandidType;
2use derive_more::{Deref, DerefMut, Display, FromStr};
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4use ulid::Ulid as WrappedUlid;
5
6#[derive(
12 Clone, Copy, Debug, Deref, DerefMut, Display, Eq, FromStr, Hash, Ord, PartialEq, PartialOrd,
13)]
14#[repr(transparent)]
15pub struct Ulid(WrappedUlid);
16
17impl Ulid {
18 #[must_use]
19 pub const fn nil() -> Self {
20 Self(WrappedUlid::nil())
21 }
22
23 #[must_use]
24 pub const fn from_bytes(bytes: [u8; 16]) -> Self {
25 Self(WrappedUlid::from_bytes(bytes))
26 }
27
28 #[must_use]
29 pub const fn from_parts(timestamp_ms: u64, random: u128) -> Self {
30 Self(WrappedUlid::from_parts(timestamp_ms, random))
31 }
32
33 pub fn from_string(s: &str) -> Result<Self, ulid::DecodeError> {
34 Ok(Self(WrappedUlid::from_string(s)?))
35 }
36
37 #[must_use]
38 pub fn increment(&self) -> Option<Self> {
39 self.0.increment().map(Self::from)
40 }
41}
42
43impl CandidType for Ulid {
44 fn _ty() -> candid::types::Type {
45 candid::types::TypeInner::Text.into()
46 }
47
48 fn idl_serialize<S>(&self, serializer: S) -> Result<(), S::Error>
49 where
50 S: candid::types::Serializer,
51 {
52 serializer.serialize_text(&self.0.to_string())
53 }
54}
55
56impl From<WrappedUlid> for Ulid {
57 fn from(u: WrappedUlid) -> Self {
58 Self(u)
59 }
60}
61
62impl From<Ulid> for WrappedUlid {
63 fn from(u: Ulid) -> Self {
64 u.0
65 }
66}
67
68impl Serialize for Ulid {
72 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
73 where
74 S: Serializer,
75 {
76 let mut buffer = [0; ::ulid::ULID_LEN];
77 let text = self.array_to_str(&mut buffer);
78 text.serialize(serializer)
79 }
80}
81
82impl<'de> Deserialize<'de> for Ulid {
83 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
84 where
85 D: Deserializer<'de>,
86 {
87 let deserialized_str = String::deserialize(deserializer)?;
88 match WrappedUlid::from_string(&deserialized_str) {
89 Ok(u) => Ok(Self(u)),
90 Err(_) => Err(serde::de::Error::custom("invalid ulid string")),
91 }
92 }
93}