// file: crates/knowledge-domain-lib/src/source.rs // version: 3 //! Source identities independent of repository and forge providers. /// Error returned when constructing an invalid source identifier. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum SourceIdError { /// The identifier is empty or contains only whitespace. Empty, } impl std::fmt::Display for crate::SourceIdError { fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { crate::SourceIdError::Empty => return formatter.write_str("source identifier must not be empty"), } } } impl std::error::Error for crate::SourceIdError {} /// Stable logical identifier of one configured content source. #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct SourceId(String); impl crate::SourceId { /// Build a source identifier without imposing a fixed repository count or provider syntax. pub fn new(value: &str) -> Result { if value.trim().is_empty() { return Err(crate::SourceIdError::Empty); } return Ok(Self(value.to_owned())); } /// Return the identifier as text. pub fn as_str(&self) -> &str { return self.0.as_str(); } } /// One logical content source associated with a semantic family. #[derive(Clone, Debug, Eq, PartialEq)] pub struct ContentSource { id: crate::SourceId, family: crate::ContentFamily, } impl crate::ContentSource { /// Build a content source from a textual source identifier. pub fn new(id: &str, family: crate::ContentFamily) -> Result { let source_id = match crate::SourceId::new(id) { Ok(value) => value, Err(error) => return Err(error), }; return Ok(crate::ContentSource { id: source_id, family }); } /// Return the logical source identifier. pub fn id(&self) -> &crate::SourceId { return &self.id; } /// Return the semantic content family. pub fn family(&self) -> crate::ContentFamily { return self.family; } } #[cfg(test)] #[path = "../unit_tests/source.rs"] mod tests;