feagi_structures/genomic/brain_regions/
region_id.rs1use crate::FeagiDataError;
11use serde::{Deserialize, Deserializer, Serialize, Serializer};
12use std::fmt::{Display, Formatter};
13use std::str::FromStr;
14use uuid::Uuid;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
38pub struct RegionID {
39 uuid: Uuid,
40}
41
42impl RegionID {
43 pub fn new() -> Self {
57 Self {
58 uuid: Uuid::now_v7(),
59 }
60 }
61
62 pub fn from_uuid(uuid: Uuid) -> Self {
75 Self { uuid }
76 }
77
78 pub fn from_string(s: &str) -> Result<Self, FeagiDataError> {
91 Uuid::parse_str(s)
92 .map(RegionID::from_uuid)
93 .map_err(|e| FeagiDataError::BadParameters(format!("Invalid RegionID string: {}", e)))
94 }
95
96 pub fn as_uuid(&self) -> Uuid {
107 self.uuid
108 }
109
110 pub fn as_bytes(&self) -> &[u8; 16] {
122 self.uuid.as_bytes()
123 }
124}
125
126impl Default for RegionID {
127 fn default() -> Self {
128 Self::new()
129 }
130}
131
132impl Display for RegionID {
133 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
134 write!(f, "{}", self.uuid)
135 }
136}
137
138impl FromStr for RegionID {
139 type Err = FeagiDataError;
140
141 fn from_str(s: &str) -> Result<Self, Self::Err> {
142 Uuid::parse_str(s)
143 .map(RegionID::from_uuid)
144 .map_err(|e| FeagiDataError::BadParameters(format!("Invalid RegionID string: {}", e)))
145 }
146}
147
148impl From<Uuid> for RegionID {
150 fn from(uuid: Uuid) -> Self {
151 RegionID::from_uuid(uuid)
152 }
153}
154
155impl From<RegionID> for Uuid {
157 fn from(region_id: RegionID) -> Self {
158 region_id.uuid
159 }
160}
161
162impl Serialize for RegionID {
164 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
165 where
166 S: Serializer,
167 {
168 serializer.serialize_str(&self.uuid.to_string())
169 }
170}
171
172impl<'de> Deserialize<'de> for RegionID {
174 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
175 where
176 D: Deserializer<'de>,
177 {
178 let s = String::deserialize(deserializer)?;
179 RegionID::from_string(&s).map_err(serde::de::Error::custom)
180 }
181}
182
183#[cfg(test)]
184mod tests {
185 use super::*;
186
187 #[test]
188 fn test_region_id_new() {
189 let id1 = RegionID::new();
190 let id2 = RegionID::new();
191
192 assert_ne!(id1, id2);
194 }
195
196 #[test]
197 fn test_region_id_from_uuid() {
198 let uuid = Uuid::now_v7();
199 let region_id = RegionID::from_uuid(uuid);
200
201 assert_eq!(region_id.as_uuid(), uuid);
202 }
203
204 #[test]
205 fn test_region_id_from_string() {
206 let uuid_str = "550e8400-e29b-41d4-a716-446655440000";
207 let region_id = RegionID::from_string(uuid_str).unwrap();
208
209 assert_eq!(region_id.to_string(), uuid_str);
210 }
211
212 #[test]
213 fn test_region_id_from_string_invalid() {
214 let result = RegionID::from_string("not-a-uuid");
215 assert!(result.is_err());
216 }
217
218 #[test]
219 fn test_region_id_display() {
220 let region_id = RegionID::new();
221 let display_str = region_id.to_string();
222
223 assert_eq!(display_str.len(), 36);
225 assert!(display_str.contains('-'));
226 }
227
228 #[test]
229 fn test_region_id_from_str() {
230 let uuid_str = "550e8400-e29b-41d4-a716-446655440000";
231 let region_id: RegionID = uuid_str.parse().unwrap();
232
233 assert_eq!(region_id.to_string(), uuid_str);
234 }
235
236 #[test]
237 fn test_region_id_serialization() {
238 let region_id = RegionID::new();
239
240 let json = serde_json::to_string(®ion_id).unwrap();
242
243 assert!(json.starts_with('"'));
245 assert!(json.ends_with('"'));
246 assert_eq!(json.len(), 38); }
248
249 #[test]
250 fn test_region_id_deserialization() {
251 let uuid_str = "550e8400-e29b-41d4-a716-446655440000";
252 let json = format!("\"{}\"", uuid_str);
253
254 let region_id: RegionID = serde_json::from_str(&json).unwrap();
255
256 assert_eq!(region_id.to_string(), uuid_str);
257 }
258
259 #[test]
260 fn test_region_id_roundtrip() {
261 let original = RegionID::new();
262
263 let json = serde_json::to_string(&original).unwrap();
265
266 let deserialized: RegionID = serde_json::from_str(&json).unwrap();
268
269 assert_eq!(original, deserialized);
270 }
271
272 #[test]
273 fn test_region_id_as_bytes() {
274 let region_id = RegionID::new();
275 let bytes = region_id.as_bytes();
276
277 assert_eq!(bytes.len(), 16);
278 }
279
280 #[test]
281 fn test_region_id_default() {
282 let id1 = RegionID::default();
283 let id2 = RegionID::default();
284
285 assert_ne!(id1, id2);
287 }
288
289 #[test]
290 fn test_region_id_equality() {
291 let uuid = Uuid::now_v7();
292 let id1 = RegionID::from_uuid(uuid);
293 let id2 = RegionID::from_uuid(uuid);
294
295 assert_eq!(id1, id2);
296 }
297
298 #[test]
299 fn test_region_id_hash() {
300 use std::collections::HashSet;
301
302 let id1 = RegionID::new();
303 let id2 = RegionID::new();
304
305 let mut set = HashSet::new();
306 set.insert(id1);
307 set.insert(id2);
308
309 assert_eq!(set.len(), 2);
310 assert!(set.contains(&id1));
311 assert!(set.contains(&id2));
312 }
313}