use crate::errors::{Error, Result};
use crate::events::attributes::Attribute;
use crate::events::BytesStart;
use crate::utils::write_byte_string;
use memchr::memchr;
use std::fmt::{self, Debug, Formatter};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))]
pub struct QName<'a>(pub &'a [u8]);
impl<'a> QName<'a> {
#[inline(always)]
pub const fn into_inner(self) -> &'a [u8] {
self.0
}
pub fn local_name(&self) -> LocalName<'a> {
LocalName(self.index().map_or(self.0, |i| &self.0[i + 1..]))
}
pub fn prefix(&self) -> Option<Prefix<'a>> {
self.index().map(|i| Prefix(&self.0[..i]))
}
pub fn decompose(&self) -> (LocalName<'a>, Option<Prefix<'a>>) {
match self.index() {
None => (LocalName(self.0), None),
Some(i) => (LocalName(&self.0[i + 1..]), Some(Prefix(&self.0[..i]))),
}
}
pub fn as_namespace_binding(&self) -> Option<PrefixDeclaration<'a>> {
if self.0.starts_with(b"xmlns") {
return match self.0.get(5) {
None => Some(PrefixDeclaration::Default),
Some(&b':') => Some(PrefixDeclaration::Named(&self.0[6..])),
_ => None,
};
}
None
}
#[inline(always)]
fn index(&self) -> Option<usize> {
memchr(b':', self.0)
}
}
impl<'a> Debug for QName<'a> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "QName(")?;
write_byte_string(f, self.0)?;
write!(f, ")")
}
}
impl<'a> AsRef<[u8]> for QName<'a> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.0
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))]
pub struct LocalName<'a>(&'a [u8]);
impl<'a> LocalName<'a> {
#[inline(always)]
pub const fn into_inner(self) -> &'a [u8] {
self.0
}
}
impl<'a> Debug for LocalName<'a> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "LocalName(")?;
write_byte_string(f, self.0)?;
write!(f, ")")
}
}
impl<'a> AsRef<[u8]> for LocalName<'a> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.0
}
}
impl<'a> From<QName<'a>> for LocalName<'a> {
#[inline]
fn from(name: QName<'a>) -> Self {
Self(name.index().map_or(name.0, |i| &name.0[i + 1..]))
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))]
pub struct Prefix<'a>(&'a [u8]);
impl<'a> Prefix<'a> {
#[inline(always)]
pub const fn into_inner(self) -> &'a [u8] {
self.0
}
}
impl<'a> Debug for Prefix<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Prefix(")?;
write_byte_string(f, self.0)?;
write!(f, ")")
}
}
impl<'a> AsRef<[u8]> for Prefix<'a> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PrefixDeclaration<'a> {
Default,
Named(&'a [u8]),
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))]
pub struct Namespace<'a>(pub &'a [u8]);
impl<'a> Namespace<'a> {
#[inline(always)]
pub const fn into_inner(self) -> &'a [u8] {
self.0
}
}
impl<'a> Debug for Namespace<'a> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Namespace(")?;
write_byte_string(f, self.0)?;
write!(f, ")")
}
}
impl<'a> AsRef<[u8]> for Namespace<'a> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.0
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum ResolveResult<'ns> {
Unbound,
Bound(Namespace<'ns>),
Unknown(Vec<u8>),
}
impl<'ns> Debug for ResolveResult<'ns> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::Unbound => write!(f, "Unbound"),
Self::Bound(ns) => write!(f, "Bound({:?})", ns),
Self::Unknown(p) => {
write!(f, "Unknown(")?;
write_byte_string(f, p)?;
write!(f, ")")
}
}
}
}
impl<'ns> TryFrom<ResolveResult<'ns>> for Option<Namespace<'ns>> {
type Error = Error;
fn try_from(result: ResolveResult<'ns>) -> Result<Self> {
use ResolveResult::*;
match result {
Unbound => Ok(None),
Bound(ns) => Ok(Some(ns)),
Unknown(p) => Err(Error::UnknownPrefix(p)),
}
}
}
#[derive(Debug, Clone)]
struct NamespaceEntry {
start: usize,
prefix_len: usize,
value_len: usize,
level: i32,
}
impl NamespaceEntry {
#[inline]
fn prefix<'b>(&self, ns_buffer: &'b [u8]) -> Option<Prefix<'b>> {
if self.prefix_len == 0 {
None
} else {
Some(Prefix(&ns_buffer[self.start..self.start + self.prefix_len]))
}
}
#[inline]
fn namespace<'ns>(&self, buffer: &'ns [u8]) -> ResolveResult<'ns> {
if self.value_len == 0 {
ResolveResult::Unbound
} else {
let start = self.start + self.prefix_len;
ResolveResult::Bound(Namespace(&buffer[start..start + self.value_len]))
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct NamespaceResolver {
buffer: Vec<u8>,
bindings: Vec<NamespaceEntry>,
nesting_level: i32,
}
const RESERVED_NAMESPACE_XML: (Prefix, Namespace) = (
Prefix(b"xml"),
Namespace(b"http://www.w3.org/XML/1998/namespace"),
);
const RESERVED_NAMESPACE_XMLNS: (Prefix, Namespace) = (
Prefix(b"xmlns"),
Namespace(b"http://www.w3.org/2000/xmlns/"),
);
impl Default for NamespaceResolver {
fn default() -> Self {
let mut buffer = Vec::new();
let mut bindings = Vec::new();
for ent in &[RESERVED_NAMESPACE_XML, RESERVED_NAMESPACE_XMLNS] {
let prefix = ent.0.into_inner();
let uri = ent.1.into_inner();
bindings.push(NamespaceEntry {
start: buffer.len(),
prefix_len: prefix.len(),
value_len: uri.len(),
level: 0,
});
buffer.extend(prefix);
buffer.extend(uri);
}
Self {
buffer,
bindings,
nesting_level: 0,
}
}
}
impl NamespaceResolver {
pub fn push(&mut self, start: &BytesStart) -> Result<()> {
self.nesting_level += 1;
let level = self.nesting_level;
for a in start.attributes().with_checks(false) {
if let Ok(Attribute { key: k, value: v }) = a {
match k.as_namespace_binding() {
Some(PrefixDeclaration::Default) => {
let start = self.buffer.len();
self.buffer.extend_from_slice(&v);
self.bindings.push(NamespaceEntry {
start,
prefix_len: 0,
value_len: v.len(),
level,
});
}
Some(PrefixDeclaration::Named(b"xml")) => {
if Namespace(&v) != RESERVED_NAMESPACE_XML.1 {
return Err(Error::InvalidPrefixBind {
prefix: b"xml".to_vec(),
namespace: v.to_vec(),
});
}
}
Some(PrefixDeclaration::Named(b"xmlns")) => {
return Err(Error::InvalidPrefixBind {
prefix: b"xmlns".to_vec(),
namespace: v.to_vec(),
});
}
Some(PrefixDeclaration::Named(prefix)) => {
let ns = Namespace(&v);
if ns == RESERVED_NAMESPACE_XML.1 || ns == RESERVED_NAMESPACE_XMLNS.1 {
return Err(Error::InvalidPrefixBind {
prefix: prefix.to_vec(),
namespace: v.to_vec(),
});
}
let start = self.buffer.len();
self.buffer.extend_from_slice(prefix);
self.buffer.extend_from_slice(&v);
self.bindings.push(NamespaceEntry {
start,
prefix_len: prefix.len(),
value_len: v.len(),
level,
});
}
None => {}
}
} else {
break;
}
}
Ok(())
}
pub fn pop(&mut self) {
self.nesting_level -= 1;
let current_level = self.nesting_level;
match self.bindings.iter().rposition(|n| n.level <= current_level) {
None => {
self.buffer.clear();
self.bindings.clear();
}
Some(last_valid_pos) => {
if let Some(len) = self.bindings.get(last_valid_pos + 1).map(|n| n.start) {
self.buffer.truncate(len);
self.bindings.truncate(last_valid_pos + 1);
}
}
}
}
#[inline]
pub fn resolve<'n>(
&self,
name: QName<'n>,
use_default: bool,
) -> (ResolveResult, LocalName<'n>) {
let (local_name, prefix) = name.decompose();
(self.resolve_prefix(prefix, use_default), local_name)
}
#[inline]
pub fn find(&self, element_name: QName) -> ResolveResult {
self.resolve_prefix(element_name.prefix(), true)
}
fn resolve_prefix(&self, prefix: Option<Prefix>, use_default: bool) -> ResolveResult {
self.bindings
.iter()
.rev()
.find_map(|n| match (n.prefix(&self.buffer), prefix) {
(None, None) if use_default => Some(n.namespace(&self.buffer)),
(None, None) => Some(ResolveResult::Unbound),
(None, Some(_)) => None,
(Some(_), None) => None,
(Some(definition), Some(usage)) if definition != usage => None,
_ if n.value_len == 0 => Some(Self::maybe_unknown(prefix)),
_ => Some(n.namespace(&self.buffer)),
})
.unwrap_or_else(|| Self::maybe_unknown(prefix))
}
#[inline]
fn maybe_unknown(prefix: Option<Prefix>) -> ResolveResult<'static> {
match prefix {
Some(p) => ResolveResult::Unknown(p.into_inner().to_vec()),
None => ResolveResult::Unbound,
}
}
#[inline]
pub const fn iter(&self) -> PrefixIter {
PrefixIter {
resolver: self,
bindings_cursor: 2,
}
}
}
#[derive(Debug, Clone)]
pub struct PrefixIter<'a> {
resolver: &'a NamespaceResolver,
bindings_cursor: usize,
}
impl<'a> Iterator for PrefixIter<'a> {
type Item = (PrefixDeclaration<'a>, Namespace<'a>);
fn next(&mut self) -> Option<(PrefixDeclaration<'a>, Namespace<'a>)> {
while let Some(namespace_entry) = self.resolver.bindings.get(self.bindings_cursor) {
self.bindings_cursor += 1;
let prefix = namespace_entry.prefix(&self.resolver.buffer);
if self.resolver.bindings[self.bindings_cursor..]
.iter()
.any(|ne| prefix == ne.prefix(&self.resolver.buffer))
{
continue; }
let namespace = if let ResolveResult::Bound(namespace) =
namespace_entry.namespace(&self.resolver.buffer)
{
namespace
} else {
continue; };
let prefix = if let Some(Prefix(prefix)) = prefix {
PrefixDeclaration::Named(prefix)
} else {
PrefixDeclaration::Default
};
return Some((prefix, namespace));
}
None }
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.resolver.bindings.len() - self.bindings_cursor))
}
}
#[cfg(test)]
mod namespaces {
use super::*;
use pretty_assertions::assert_eq;
use ResolveResult::*;
mod unprefixed {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn basic() {
let name = QName(b"simple");
let ns = Namespace(b"default");
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
resolver
.push(&BytesStart::from_content(" xmlns='default'", 0))
.unwrap();
assert_eq!(&resolver.buffer[s..], b"default");
resolver.push(&BytesStart::from_content("", 0)).unwrap();
assert_eq!(&resolver.buffer[s..], b"default");
resolver.pop();
assert_eq!(&resolver.buffer[s..], b"default");
assert_eq!(
resolver.resolve(name, true),
(Bound(ns), LocalName(b"simple"))
);
assert_eq!(
resolver.resolve(name, false),
(Unbound, LocalName(b"simple"))
);
assert_eq!(resolver.find(name), Bound(ns));
}
#[test]
fn override_namespace() {
let name = QName(b"simple");
let old_ns = Namespace(b"old");
let new_ns = Namespace(b"new");
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
resolver
.push(&BytesStart::from_content(" xmlns='old'", 0))
.unwrap();
resolver
.push(&BytesStart::from_content(" xmlns='new'", 0))
.unwrap();
assert_eq!(&resolver.buffer[s..], b"oldnew");
assert_eq!(
resolver.resolve(name, true),
(Bound(new_ns), LocalName(b"simple"))
);
assert_eq!(
resolver.resolve(name, false),
(Unbound, LocalName(b"simple"))
);
assert_eq!(resolver.find(name), Bound(new_ns));
resolver.pop();
assert_eq!(&resolver.buffer[s..], b"old");
assert_eq!(
resolver.resolve(name, true),
(Bound(old_ns), LocalName(b"simple"))
);
assert_eq!(
resolver.resolve(name, false),
(Unbound, LocalName(b"simple"))
);
assert_eq!(resolver.find(name), Bound(old_ns));
}
#[test]
fn reset() {
let name = QName(b"simple");
let old_ns = Namespace(b"old");
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
resolver
.push(&BytesStart::from_content(" xmlns='old'", 0))
.unwrap();
resolver
.push(&BytesStart::from_content(" xmlns=''", 0))
.unwrap();
assert_eq!(&resolver.buffer[s..], b"old");
assert_eq!(
resolver.resolve(name, true),
(Unbound, LocalName(b"simple"))
);
assert_eq!(
resolver.resolve(name, false),
(Unbound, LocalName(b"simple"))
);
assert_eq!(resolver.find(name), Unbound);
resolver.pop();
assert_eq!(&resolver.buffer[s..], b"old");
assert_eq!(
resolver.resolve(name, true),
(Bound(old_ns), LocalName(b"simple"))
);
assert_eq!(
resolver.resolve(name, false),
(Unbound, LocalName(b"simple"))
);
assert_eq!(resolver.find(name), Bound(old_ns));
}
}
mod declared_prefix {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn basic() {
let name = QName(b"p:with-declared-prefix");
let ns = Namespace(b"default");
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
resolver
.push(&BytesStart::from_content(" xmlns:p='default'", 0))
.unwrap();
assert_eq!(&resolver.buffer[s..], b"pdefault");
resolver.push(&BytesStart::from_content("", 0)).unwrap();
assert_eq!(&resolver.buffer[s..], b"pdefault");
resolver.pop();
assert_eq!(&resolver.buffer[s..], b"pdefault");
assert_eq!(
resolver.resolve(name, true),
(Bound(ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(
resolver.resolve(name, false),
(Bound(ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(resolver.find(name), Bound(ns));
}
#[test]
fn override_namespace() {
let name = QName(b"p:with-declared-prefix");
let old_ns = Namespace(b"old");
let new_ns = Namespace(b"new");
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
resolver
.push(&BytesStart::from_content(" xmlns:p='old'", 0))
.unwrap();
resolver
.push(&BytesStart::from_content(" xmlns:p='new'", 0))
.unwrap();
assert_eq!(&resolver.buffer[s..], b"poldpnew");
assert_eq!(
resolver.resolve(name, true),
(Bound(new_ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(
resolver.resolve(name, false),
(Bound(new_ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(resolver.find(name), Bound(new_ns));
resolver.pop();
assert_eq!(&resolver.buffer[s..], b"pold");
assert_eq!(
resolver.resolve(name, true),
(Bound(old_ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(
resolver.resolve(name, false),
(Bound(old_ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(resolver.find(name), Bound(old_ns));
}
#[test]
fn reset() {
let name = QName(b"p:with-declared-prefix");
let old_ns = Namespace(b"old");
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
resolver
.push(&BytesStart::from_content(" xmlns:p='old'", 0))
.unwrap();
resolver
.push(&BytesStart::from_content(" xmlns:p=''", 0))
.unwrap();
assert_eq!(&resolver.buffer[s..], b"poldp");
assert_eq!(
resolver.resolve(name, true),
(Unknown(b"p".to_vec()), LocalName(b"with-declared-prefix"))
);
assert_eq!(
resolver.resolve(name, false),
(Unknown(b"p".to_vec()), LocalName(b"with-declared-prefix"))
);
assert_eq!(resolver.find(name), Unknown(b"p".to_vec()));
resolver.pop();
assert_eq!(&resolver.buffer[s..], b"pold");
assert_eq!(
resolver.resolve(name, true),
(Bound(old_ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(
resolver.resolve(name, false),
(Bound(old_ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(resolver.find(name), Bound(old_ns));
}
}
mod builtin_prefixes {
use super::*;
mod xml {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn undeclared() {
let name = QName(b"xml:random");
let namespace = RESERVED_NAMESPACE_XML.1;
let resolver = NamespaceResolver::default();
assert_eq!(
resolver.resolve(name, true),
(Bound(namespace), LocalName(b"random"))
);
assert_eq!(
resolver.resolve(name, false),
(Bound(namespace), LocalName(b"random"))
);
assert_eq!(resolver.find(name), Bound(namespace));
}
#[test]
fn rebound_to_correct_ns() {
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
resolver.push(
&BytesStart::from_content(
" xmlns:xml='http://www.w3.org/XML/1998/namespace'",
0,
),
).expect("`xml` prefix should be possible to bound to `http://www.w3.org/XML/1998/namespace`");
assert_eq!(&resolver.buffer[s..], b"");
}
#[test]
fn rebound_to_incorrect_ns() {
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
match resolver.push(&BytesStart::from_content(
" xmlns:xml='not_correct_namespace'",
0,
)) {
Err(Error::InvalidPrefixBind { prefix, namespace }) => {
assert_eq!(prefix, b"xml");
assert_eq!(namespace, b"not_correct_namespace");
}
x => panic!(
"Expected `Err(InvalidPrefixBind {{ .. }})`, but got `{:?}`",
x
),
}
assert_eq!(&resolver.buffer[s..], b"");
}
#[test]
fn unbound() {
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
match resolver.push(&BytesStart::from_content(" xmlns:xml=''", 0)) {
Err(Error::InvalidPrefixBind { prefix, namespace }) => {
assert_eq!(prefix, b"xml");
assert_eq!(namespace, b"");
}
x => panic!(
"Expected `Err(InvalidPrefixBind {{ .. }})`, but got `{:?}`",
x
),
}
assert_eq!(&resolver.buffer[s..], b"");
}
#[test]
fn other_prefix_bound_to_xml_namespace() {
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
match resolver.push(&BytesStart::from_content(
" xmlns:not_xml='http://www.w3.org/XML/1998/namespace'",
0,
)) {
Err(Error::InvalidPrefixBind { prefix, namespace }) => {
assert_eq!(prefix, b"not_xml");
assert_eq!(namespace, b"http://www.w3.org/XML/1998/namespace");
}
x => panic!(
"Expected `Err(InvalidPrefixBind {{ .. }})`, but got `{:?}`",
x
),
}
assert_eq!(&resolver.buffer[s..], b"");
}
}
mod xmlns {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn undeclared() {
let name = QName(b"xmlns:random");
let namespace = RESERVED_NAMESPACE_XMLNS.1;
let resolver = NamespaceResolver::default();
assert_eq!(
resolver.resolve(name, true),
(Bound(namespace), LocalName(b"random"))
);
assert_eq!(
resolver.resolve(name, false),
(Bound(namespace), LocalName(b"random"))
);
assert_eq!(resolver.find(name), Bound(namespace));
}
#[test]
fn rebound_to_correct_ns() {
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
match resolver.push(&BytesStart::from_content(
" xmlns:xmlns='http://www.w3.org/2000/xmlns/'",
0,
)) {
Err(Error::InvalidPrefixBind { prefix, namespace }) => {
assert_eq!(prefix, b"xmlns");
assert_eq!(namespace, b"http://www.w3.org/2000/xmlns/");
}
x => panic!(
"Expected `Err(InvalidPrefixBind {{ .. }})`, but got `{:?}`",
x
),
}
assert_eq!(&resolver.buffer[s..], b"");
}
#[test]
fn rebound_to_incorrect_ns() {
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
match resolver.push(&BytesStart::from_content(
" xmlns:xmlns='not_correct_namespace'",
0,
)) {
Err(Error::InvalidPrefixBind { prefix, namespace }) => {
assert_eq!(prefix, b"xmlns");
assert_eq!(namespace, b"not_correct_namespace");
}
x => panic!(
"Expected `Err(InvalidPrefixBind {{ .. }})`, but got `{:?}`",
x
),
}
assert_eq!(&resolver.buffer[s..], b"");
}
#[test]
fn unbound() {
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
match resolver.push(&BytesStart::from_content(" xmlns:xmlns=''", 0)) {
Err(Error::InvalidPrefixBind { prefix, namespace }) => {
assert_eq!(prefix, b"xmlns");
assert_eq!(namespace, b"");
}
x => panic!(
"Expected `Err(InvalidPrefixBind {{ .. }})`, but got `{:?}`",
x
),
}
assert_eq!(&resolver.buffer[s..], b"");
}
#[test]
fn other_prefix_bound_to_xmlns_namespace() {
let mut resolver = NamespaceResolver::default();
let s = resolver.buffer.len();
match resolver.push(&BytesStart::from_content(
" xmlns:not_xmlns='http://www.w3.org/2000/xmlns/'",
0,
)) {
Err(Error::InvalidPrefixBind { prefix, namespace }) => {
assert_eq!(prefix, b"not_xmlns");
assert_eq!(namespace, b"http://www.w3.org/2000/xmlns/");
}
x => panic!(
"Expected `Err(InvalidPrefixBind {{ .. }})`, but got `{:?}`",
x
),
}
assert_eq!(&resolver.buffer[s..], b"");
}
}
}
#[test]
fn undeclared_prefix() {
let name = QName(b"unknown:prefix");
let resolver = NamespaceResolver::default();
assert_eq!(
resolver.buffer,
b"xmlhttp://www.w3.org/XML/1998/namespacexmlnshttp://www.w3.org/2000/xmlns/"
);
assert_eq!(
resolver.resolve(name, true),
(Unknown(b"unknown".to_vec()), LocalName(b"prefix"))
);
assert_eq!(
resolver.resolve(name, false),
(Unknown(b"unknown".to_vec()), LocalName(b"prefix"))
);
assert_eq!(resolver.find(name), Unknown(b"unknown".to_vec()));
}
#[test]
fn prefix_and_local_name() {
let name = QName(b"foo:bus");
assert_eq!(name.prefix(), Some(Prefix(b"foo")));
assert_eq!(name.local_name(), LocalName(b"bus"));
assert_eq!(name.decompose(), (LocalName(b"bus"), Some(Prefix(b"foo"))));
let name = QName(b"foo:");
assert_eq!(name.prefix(), Some(Prefix(b"foo")));
assert_eq!(name.local_name(), LocalName(b""));
assert_eq!(name.decompose(), (LocalName(b""), Some(Prefix(b"foo"))));
let name = QName(b":foo");
assert_eq!(name.prefix(), Some(Prefix(b"")));
assert_eq!(name.local_name(), LocalName(b"foo"));
assert_eq!(name.decompose(), (LocalName(b"foo"), Some(Prefix(b""))));
let name = QName(b"foo:bus:baz");
assert_eq!(name.prefix(), Some(Prefix(b"foo")));
assert_eq!(name.local_name(), LocalName(b"bus:baz"));
assert_eq!(
name.decompose(),
(LocalName(b"bus:baz"), Some(Prefix(b"foo")))
);
}
}