dtz_identifier/
context_id.rs

1use serde::{de::Visitor, Deserialize, Deserializer, Serialize};
2use std::fmt::Display;
3use uuid::Uuid;
4
5static PREFIX: &str = "context-";
6
7#[derive(Debug, Clone, PartialEq, Copy, Eq, Hash)]
8pub struct ContextId {
9    pub id: Uuid,
10}
11
12impl crate::ShortId for ContextId {
13    fn to_short_id(&self) -> String {
14        self.id.to_string()[0..8].to_string()
15    }
16}
17
18impl Default for ContextId {
19    fn default() -> Self {
20        Self { id: Uuid::new_v4() }
21    }
22}
23
24impl Display for ContextId {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        f.write_str(&format!("{PREFIX}{}", self.id))
27    }
28}
29
30impl<'de> Deserialize<'de> for ContextId {
31    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
32    where
33        D: Deserializer<'de>,
34    {
35        struct ContextIdVisitor;
36
37        impl<'de> Visitor<'de> for ContextIdVisitor {
38            type Value = ContextId;
39
40            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
41                formatter.write_str("a string starting with 'context-' followed by a UUID")
42            }
43
44            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
45            where
46                E: serde::de::Error,
47            {
48                if let Some(uuid_str) = value.strip_prefix(PREFIX) {
49                    let uuid = Uuid::parse_str(uuid_str).map_err(E::custom)?;
50                    Ok(ContextId { id: uuid })
51                } else {
52                    Err(E::custom("invalid format"))
53                }
54            }
55        }
56
57        deserializer.deserialize_str(ContextIdVisitor)
58    }
59}
60
61impl Serialize for ContextId {
62    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
63    where
64        S: serde::Serializer,
65    {
66        serializer.serialize_str(&self.to_string())
67    }
68}
69
70impl From<Uuid> for ContextId {
71    fn from(id: Uuid) -> Self {
72        ContextId { id }
73    }
74}
75
76#[test]
77fn test_from() {
78    let uuid = Uuid::new_v4();
79    let ctx = ContextId::from(uuid);
80    assert_eq!(ctx.id, uuid);
81}
82
83impl TryFrom<&str> for ContextId {
84    type Error = String;
85
86    fn try_from(value: &str) -> Result<Self, Self::Error> {
87        if let Some(uuid_str) = value.strip_prefix(PREFIX) {
88            let uuid =
89                uuid::Uuid::parse_str(uuid_str).map_err(|_e| "invalid format".to_string())?;
90            Ok(ContextId { id: uuid })
91        } else {
92            Err("invalid format".to_string())
93        }
94    }
95}
96
97impl TryFrom<String> for ContextId {
98    type Error = String;
99
100    fn try_from(value: String) -> Result<Self, Self::Error> {
101        if let Some(uuid_str) = value.strip_prefix(PREFIX) {
102            let uuid =
103                uuid::Uuid::parse_str(uuid_str).map_err(|_e| "invalid format".to_string())?;
104            Ok(ContextId { id: uuid })
105        } else {
106            Err("invalid format".to_string())
107        }
108    }
109}
110
111#[test]
112fn key_invalid_1() {
113    let k = "abc-dsfdg";
114    let apikey: Result<ContextId, String> = ContextId::try_from(k);
115    assert!(apikey.is_err())
116}
117
118#[test]
119fn key_invalid_2() {
120    let k = "context-dsfdg";
121    let apikey: Result<ContextId, String> = ContextId::try_from(k);
122    assert!(apikey.is_err())
123}
124
125#[test]
126fn key_valid_1() {
127    let k = "context-0190c589-eb70-7980-97cf-af67b3a84116";
128    let apikey: Result<ContextId, String> = ContextId::try_from(k);
129    assert!(apikey.is_ok())
130}
131
132#[test]
133fn key_invalid_3() {
134    let k = "abc-0190c589-eb70-7980-97cf-af67b3a84116";
135    let apikey: Result<ContextId, String> = ContextId::try_from(k);
136    assert!(apikey.is_err())
137}
138
139#[test]
140fn short_id() {
141    use crate::ShortId;
142    let k = "context-0190c589-eb70-7980-97cf-af67b3a84116";
143    let ctx = ContextId::try_from(k).unwrap();
144    assert_eq!(ctx.to_short_id(), "0190c589");
145}