use std::{fmt::Display, str::FromStr}; use error::Error; use oci_spec::image::Digest; use regex::Regex; use relative_path::RelativePath; pub mod address; pub mod error; pub mod oci_interface; pub mod storage; #[cfg(feature = "axum")] pub mod axum; #[cfg(feature = "storage-fs")] pub mod storage_fs; const NAME_REGEXP_MATCH: &str = r"[a-z0-9]+((\.|_|__|-+)[a-z0-9]+)*(\/[a-z0-9]+((\.|_|__|-+)[a-z0-9]+)*)*"; #[derive(Clone, Debug)] pub enum TagOrDigest { Tag(String), Digest(Digest) } // TODO: Consider 255 char namespace limit - hostname length per spec docs #[derive(Clone)] pub struct Namespace(String); impl Namespace { pub fn path(&self) -> &RelativePath { RelativePath::new(&self.0) } } impl FromStr for Namespace { type Err = Error; fn from_str(s: &str) -> Result { let regexp = Regex::new(NAME_REGEXP_MATCH).unwrap(); if regexp.is_match(s) { Ok(Namespace(s.to_string())) } else { Err(Error::Namespace(s.to_string())) } } } impl Display for Namespace { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } impl AsRef for Namespace { fn as_ref(&self) -> &str { &self.0 } } #[cfg(test)] mod test { use super::*; #[test] fn namespace() { Namespace::from_str("fuu").unwrap(); Namespace::from_str("fuu/bar").unwrap(); Namespace::from_str("fuu/bar/baz/").unwrap(); Namespace::from_str("fuu/bar/baz/qux").unwrap(); } }