dtz_identifier/
context_id.rs

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