ocipkg/distribution/
name.rs1use anyhow::{bail, Result};
2use regex::Regex;
3use std::fmt;
4
5#[derive(Debug, Clone, PartialEq, Eq, Hash)]
13pub struct Name(String);
14
15impl std::ops::Deref for Name {
16 type Target = str;
17 fn deref(&self) -> &str {
18 &self.0
19 }
20}
21
22impl fmt::Display for Name {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 write!(f, "{}", self.0)
25 }
26}
27
28lazy_static::lazy_static! {
29 static ref NAME_RE: Regex = Regex::new(r"^[a-z0-9]+((\.|_|__|-+)[a-z0-9]+)*(\/[a-z0-9]+((\.|_|__|-+)[a-z0-9]+)*)*$").unwrap();
30}
31
32impl Name {
33 pub fn as_str(&self) -> &str {
34 &self.0
35 }
36
37 pub fn new(name: &str) -> Result<Self> {
38 if NAME_RE.is_match(name) {
39 Ok(Name(name.to_string()))
40 } else {
41 bail!("Invalid name: {name}");
42 }
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49
50 #[test]
51 fn name() {
52 assert_eq!(Name::new("ghcr.io").unwrap().as_str(), "ghcr.io");
53 assert!(Name::new("_ghcr.io").is_err());
55 assert!(Name::new("/ghcr.io").is_err());
56
57 assert!(Name::new("ghcr.io/Termoshtt").is_err());
59 }
60}