use std::borrow::Cow;
use crate::id::{NameId, NamespaceId, PrefixId};
use crate::xotdata::Xot;
use crate::{Error, Node};
use super::owned::OwnedName;
pub trait NameStrInfo {
fn local_name(&self) -> &str;
fn namespace(&self) -> &str;
fn prefix(&self) -> &str;
fn full_name(&self) -> Cow<str> {
let prefix = self.prefix();
if !prefix.is_empty() {
Cow::Owned(format!("{}:{}", prefix, self.local_name()))
} else {
Cow::Borrowed(self.local_name())
}
}
}
#[derive(Debug, Clone)]
pub struct RefName<'a> {
xot: &'a Xot,
name_id: NameId,
prefix_id: PrefixId,
}
impl std::hash::Hash for RefName<'_> {
#[inline]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.name_id.hash(state);
}
}
impl PartialEq for RefName<'_> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.name_id == other.name_id
}
}
impl Eq for RefName<'_> {}
impl<'a> NameStrInfo for RefName<'a> {
#[inline]
fn local_name(&self) -> &'a str {
self.xot.local_name_str(self.name_id)
}
#[inline]
fn namespace(&self) -> &'a str {
self.xot.namespace_str(self.namespace_id())
}
#[inline]
fn prefix(&self) -> &'a str {
let prefix_id = self.prefix_id();
self.xot.prefix_str(prefix_id)
}
}
impl<'a> RefName<'a> {
pub(crate) fn new(xot: &'a Xot, name_id: NameId, prefix_id: PrefixId) -> Self {
Self {
xot,
name_id,
prefix_id,
}
}
#[inline]
pub fn name_id(&self) -> NameId {
self.name_id
}
#[inline]
pub fn namespace_id(&self) -> NamespaceId {
self.xot.namespace_for_name(self.name_id)
}
#[inline]
pub fn prefix_id(&self) -> PrefixId {
self.prefix_id
}
pub(crate) fn from_node(xot: &'a Xot, node: Node, name_id: NameId) -> Result<Self, Error> {
let namespace_id = xot.namespace_for_name(name_id);
let prefix_id = if namespace_id != xot.no_namespace() {
xot.prefix_for_namespace(node, namespace_id)
.ok_or_else(|| Error::MissingPrefix(xot.namespace_str(namespace_id).to_string()))?
} else {
xot.empty_prefix()
};
Ok(Self::new(xot, name_id, prefix_id))
}
pub fn to_owned(&self) -> OwnedName {
OwnedName::new(
self.local_name().to_string(),
self.namespace().to_string(),
self.prefix().to_string(),
)
}
pub fn has_unprefixed_namespace(&self) -> bool {
self.namespace_id() != self.xot.no_namespace()
&& self.xot.empty_prefix() == self.prefix_id()
}
}
impl<'a> From<RefName<'a>> for NameId {
#[inline]
fn from(name: RefName<'a>) -> Self {
name.name_id
}
}