schema_registry_api/domain/subject/
name.rs1use std::fmt::Display;
2use std::ops::Deref;
3use std::str::FromStr;
4
5use crate::SubjectNameError;
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
26pub struct SubjectName(String);
27
28impl AsRef<str> for SubjectName {
29 fn as_ref(&self) -> &str {
30 self.0.as_str()
31 }
32}
33
34impl Deref for SubjectName {
35 type Target = String;
36
37 fn deref(&self) -> &Self::Target {
38 &self.0
39 }
40}
41
42impl FromStr for SubjectName {
43 type Err = SubjectNameError;
44
45 fn from_str(s: &str) -> Result<Self, Self::Err> {
46 if s.is_empty() {
47 return Err(Self::Err::EmptyName);
48 }
49 if s.chars().any(char::is_control) {
50 return Err(Self::Err::InvalidChar(s.to_string()));
51 }
52 Ok(Self(s.to_string()))
53 }
54}
55
56impl Display for SubjectName {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 write!(f, "{}", self.0)
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use assert2::{check, let_assert};
65
66 use super::*;
67
68 #[test]
69 fn should_parse_subject_name() {
70 let name = "plop";
71 let result = name.parse::<SubjectName>();
72 let_assert!(Ok(subject) = result);
73 check!(subject.as_ref() == name);
74 check!(subject.to_lowercase() == name);
75 }
76
77 #[test]
78 fn should_not_parse_empty_subject_name() {
79 let name = "";
80 let result = name.parse::<SubjectName>();
81 let_assert!(Err(SubjectNameError::EmptyName) = result);
82 }
83
84 #[test]
85 fn should_not_parse_bad_subject_name() {
86 let name = "\nasd";
87 let result = name.parse::<SubjectName>();
88 let_assert!(Err(SubjectNameError::InvalidChar(_)) = result);
89 }
90}