use alloc::format;
use alloc::string::{String, ToString};
use crate::errors::XmlError;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LibraryRef {
pub library: String,
pub name: String,
}
impl LibraryRef {
#[must_use]
pub fn is_qualified(&self) -> bool {
!self.library.is_empty()
}
}
pub fn parse_library_ref(s: &str) -> Result<LibraryRef, XmlError> {
let trimmed = s.trim();
if trimmed.is_empty() {
return Err(XmlError::UnresolvedReference("empty reference".into()));
}
if let Some((lib, rest)) = trimmed.split_once("::") {
if lib.is_empty() {
return Err(XmlError::UnresolvedReference(format!(
"empty library segment in `{trimmed}`"
)));
}
if rest.contains("::") {
return Err(XmlError::UnresolvedReference(format!(
"more than two segments in `{trimmed}`"
)));
}
if rest.is_empty() {
return Err(XmlError::UnresolvedReference(format!(
"empty name segment in `{trimmed}`"
)));
}
Ok(LibraryRef {
library: lib.to_string(),
name: rest.to_string(),
})
} else {
Ok(LibraryRef {
library: String::new(),
name: trimmed.to_string(),
})
}
}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
mod tests {
use super::*;
#[test]
fn qualified() {
let r = parse_library_ref("lib::name").expect("ok");
assert_eq!(r.library, "lib");
assert_eq!(r.name, "name");
assert!(r.is_qualified());
}
#[test]
fn unqualified() {
let r = parse_library_ref("name").expect("ok");
assert_eq!(r.library, "");
assert_eq!(r.name, "name");
assert!(!r.is_qualified());
}
#[test]
fn empty_rejected() {
assert!(matches!(
parse_library_ref(""),
Err(XmlError::UnresolvedReference(_))
));
assert!(matches!(
parse_library_ref(" "),
Err(XmlError::UnresolvedReference(_))
));
}
#[test]
fn empty_segment_rejected() {
assert!(matches!(
parse_library_ref("::name"),
Err(XmlError::UnresolvedReference(_))
));
assert!(matches!(
parse_library_ref("lib::"),
Err(XmlError::UnresolvedReference(_))
));
}
#[test]
fn three_segments_rejected() {
assert!(matches!(
parse_library_ref("a::b::c"),
Err(XmlError::UnresolvedReference(_))
));
}
}