objectiveai_sdk/
prefixed_uuid.rs1use schemars::JsonSchema;
8use std::str::FromStr;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, JsonSchema)]
37#[schemars(rename = "PrefixedUuid")]
38pub struct PrefixedUuid<const PFX_1: char, const PFX_2: char, const PFX_3: char>
39{
40 uuid: uuid::Uuid,
41}
42
43impl<const PFX_1: char, const PFX_2: char, const PFX_3: char> From<uuid::Uuid>
44 for PrefixedUuid<PFX_1, PFX_2, PFX_3>
45{
46 fn from(uuid: uuid::Uuid) -> Self {
47 PrefixedUuid { uuid }
48 }
49}
50
51#[derive(Debug, Clone, thiserror::Error)]
56pub enum ParseError<const PFX_1: char, const PFX_2: char, const PFX_3: char> {
57 #[error(
59 "invalid prefix: expected {}{}{} but got {}",
60 PFX_1,
61 PFX_2,
62 PFX_3,
63 _0
64 )]
65 InvalidPrefix(String),
66 #[error("invalid UUID: {0}")]
68 InvalidUuid(uuid::Error),
69}
70
71impl<const PFX_1: char, const PFX_2: char, const PFX_3: char> FromStr
72 for PrefixedUuid<PFX_1, PFX_2, PFX_3>
73{
74 type Err = ParseError<PFX_1, PFX_2, PFX_3>;
75 fn from_str(s: &str) -> Result<Self, Self::Err> {
76 if s.len() >= 3 + uuid::fmt::Simple::LENGTH && {
77 let s_bytes = s.as_bytes();
78 s_bytes[0] == (PFX_1 as u8)
79 && s_bytes[1] == (PFX_2 as u8)
80 && s_bytes[2] == (PFX_3 as u8)
81 } {
82 match uuid::Uuid::parse_str(&s[3..]) {
83 Ok(uuid) => Ok(PrefixedUuid { uuid }),
84 Err(e) => Err(ParseError::InvalidUuid(e)),
85 }
86 } else {
87 Err(ParseError::InvalidPrefix(s.to_string()))
88 }
89 }
90}
91
92impl<const PFX_1: char, const PFX_2: char, const PFX_3: char>
93 PrefixedUuid<PFX_1, PFX_2, PFX_3>
94{
95 pub fn new() -> Self {
106 PrefixedUuid {
107 uuid: uuid::Uuid::new_v4(),
108 }
109 }
110
111 pub fn uuid(&self) -> uuid::Uuid {
123 self.uuid
124 }
125}
126
127impl<const PFX_1: char, const PFX_2: char, const PFX_3: char> std::fmt::Display
128 for PrefixedUuid<PFX_1, PFX_2, PFX_3>
129{
130 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131 write!(
132 f,
133 "{}{}{}{}",
134 PFX_1,
135 PFX_2,
136 PFX_3,
137 self.uuid
138 .simple()
139 .encode_lower(&mut [0; uuid::fmt::Simple::LENGTH])
140 )
141 }
142}
143
144impl<const PFX_1: char, const PFX_2: char, const PFX_3: char> serde::Serialize
145 for PrefixedUuid<PFX_1, PFX_2, PFX_3>
146{
147 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
148 where
149 S: serde::Serializer,
150 {
151 serializer.serialize_str(&self.to_string())
152 }
153}
154
155impl<'de, const PFX_1: char, const PFX_2: char, const PFX_3: char>
156 serde::Deserialize<'de> for PrefixedUuid<PFX_1, PFX_2, PFX_3>
157{
158 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
159 where
160 D: serde::Deserializer<'de>,
161 {
162 let s = String::deserialize(deserializer)?;
163 PrefixedUuid::from_str(&s).map_err(serde::de::Error::custom)
164 }
165}