Skip to main content

kellnr_common/
original_name.rs

1use std::convert::TryFrom;
2use std::fmt;
3use std::ops::Deref;
4
5use regex::Regex;
6use sea_orm::Value;
7use thiserror::Error;
8use utoipa::ToSchema;
9
10use crate::normalized_name::NormalizedName;
11
12#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone, Hash, ToSchema)]
13#[schema(value_type = String)]
14pub struct OriginalName(String);
15
16#[derive(Debug, PartialEq, Eq, Error)]
17pub enum NameError {
18    #[error("Invalid character in name")]
19    InvalidCharacter,
20    #[error("Invalid length for name")]
21    InvalidLength,
22}
23
24impl OriginalName {
25    pub fn to_normalized(&self) -> NormalizedName {
26        NormalizedName::from(self)
27    }
28    pub fn from_unchecked(name: String) -> Self {
29        Self(name)
30    }
31    pub fn into_inner(self) -> String {
32        self.0
33    }
34}
35
36impl TryFrom<String> for OriginalName {
37    type Error = NameError;
38
39    fn try_from(package_name: String) -> Result<Self, Self::Error> {
40        let re = Regex::new(r"^[a-zA-Z][a-zA-Z0-9-_]*$").unwrap();
41
42        if !re.is_match(&package_name) {
43            Err(NameError::InvalidCharacter)
44        } else if package_name.len() > 64 {
45            Err(NameError::InvalidLength)
46        } else {
47            Ok(OriginalName(package_name))
48        }
49    }
50}
51
52impl From<&OriginalName> for String {
53    fn from(name: &OriginalName) -> Self {
54        name.to_string()
55    }
56}
57
58impl From<OriginalName> for String {
59    fn from(name: OriginalName) -> Self {
60        name.to_string()
61    }
62}
63
64impl From<OriginalName> for Value {
65    fn from(value: OriginalName) -> Self {
66        Value::String(Some(value.0))
67    }
68}
69
70impl From<&OriginalName> for Value {
71    fn from(value: &OriginalName) -> Self {
72        Value::String(Some(value.0.clone()))
73    }
74}
75
76impl TryFrom<&String> for OriginalName {
77    type Error = NameError;
78
79    fn try_from(package_name: &String) -> Result<Self, Self::Error> {
80        OriginalName::try_from(package_name.clone())
81    }
82}
83
84impl TryFrom<&str> for OriginalName {
85    type Error = NameError;
86
87    fn try_from(package_name: &str) -> Result<Self, Self::Error> {
88        OriginalName::try_from(package_name.to_string())
89    }
90}
91
92impl Deref for OriginalName {
93    type Target = String;
94
95    fn deref(&self) -> &Self::Target {
96        &self.0
97    }
98}
99
100impl fmt::Display for OriginalName {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        write!(f, "{}", self.0)
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109
110    #[test]
111    fn valid_package_names() {
112        assert_eq!(
113            OriginalName::try_from("test-lib").unwrap(),
114            OriginalName("test-lib".to_string())
115        );
116        assert_eq!(
117            OriginalName::try_from("Test_lib").unwrap(),
118            OriginalName("Test_lib".to_string())
119        );
120        assert_eq!(
121            OriginalName::try_from("test_lib_foo").unwrap(),
122            OriginalName("test_lib_foo".to_string())
123        );
124        assert_eq!(
125            OriginalName::try_from("test-lIB-foo").unwrap(),
126            OriginalName("test-lIB-foo".to_string())
127        );
128        assert_eq!(
129            OriginalName::try_from("test12_14f").unwrap(),
130            OriginalName("test12_14f".to_string())
131        );
132        assert_eq!(
133            OriginalName::try_from("tEs2-23_1f").unwrap(),
134            OriginalName("tEs2-23_1f".to_string())
135        );
136        assert_eq!(
137            OriginalName::try_from("testlib").unwrap(),
138            OriginalName("testlib".to_string())
139        );
140        assert_eq!(
141            OriginalName::try_from("Testlib23").unwrap(),
142            OriginalName("Testlib23".to_string())
143        );
144    }
145
146    #[test]
147    fn invalid_characters_in_package_name() {
148        assert_eq!(
149            OriginalName::try_from("_test").unwrap_err(),
150            NameError::InvalidCharacter
151        );
152        assert_eq!(
153            OriginalName::try_from("44Test").unwrap_err(),
154            NameError::InvalidCharacter
155        );
156        assert_eq!(
157            OriginalName::try_from("-Av").unwrap_err(),
158            NameError::InvalidCharacter
159        );
160        assert_eq!(
161            OriginalName::try_from("testÄ").unwrap_err(),
162            NameError::InvalidCharacter
163        );
164        assert_eq!(
165            OriginalName::try_from("test?").unwrap_err(),
166            NameError::InvalidCharacter
167        );
168        assert_eq!(
169            OriginalName::try_from(".45A").unwrap_err(),
170            NameError::InvalidCharacter
171        );
172        assert_eq!(
173            OriginalName::try_from("").unwrap_err(),
174            NameError::InvalidCharacter
175        );
176    }
177
178    #[test]
179    fn too_long_package_name() {
180        assert_eq!(
181            OriginalName::try_from(
182                "zbsfrofdgxekytxrporaocoieaviehlvjrroockxufdkzgtxudkmdkentyyhkmtpx"
183            )
184            .unwrap_err(),
185            NameError::InvalidLength
186        );
187    }
188}