use std::borrow::Cow;
use std::collections::btree_map::Iter as Entries;
use std::collections::btree_map::{BTreeMap, Entry};
use std::collections::HashSet;
use std::iter::{Map, Rev};
use std::slice::Iter;
pub const NS_XMLNS_PREFIX: &str = "xmlns";
pub const NS_XMLNS_URI: &str = "http://www.w3.org/2000/xmlns/";
pub const NS_XML_PREFIX: &str = "xml";
pub const NS_XML_URI: &str = "http://www.w3.org/XML/1998/namespace";
pub const NS_NO_PREFIX: &str = "";
pub const NS_EMPTY_URI: &str = "";
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Namespace(pub BTreeMap<String, String>);
impl Namespace {
#[inline]
#[must_use]
pub fn empty() -> Namespace {
Namespace(BTreeMap::new())
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[must_use]
pub fn is_essentially_empty(&self) -> bool {
if self.0.len() > 3 { return false; }
self.0.iter().all(|(k, v)| match (&**k, &**v) {
(NS_NO_PREFIX, NS_EMPTY_URI) => true,
(NS_XMLNS_PREFIX, NS_XMLNS_URI) => true,
(NS_XML_PREFIX, NS_XML_URI) => true,
_ => false
})
}
#[inline]
pub fn contains<P: ?Sized + AsRef<str>>(&self, prefix: &P) -> bool {
self.0.contains_key(prefix.as_ref())
}
pub fn put<P, U>(&mut self, prefix: P, uri: U) -> bool
where P: Into<String>, U: Into<String>
{
match self.0.entry(prefix.into()) {
Entry::Occupied(_) => false,
Entry::Vacant(ve) => {
ve.insert(uri.into());
true
}
}
}
pub fn force_put<P, U>(&mut self, prefix: P, uri: U) -> Option<String>
where P: Into<String>, U: Into<String>
{
self.0.insert(prefix.into(), uri.into())
}
pub fn get<'a, P: ?Sized + AsRef<str>>(&'a self, prefix: &P) -> Option<&'a str> {
self.0.get(prefix.as_ref()).map(|s| &**s)
}
#[must_use]
pub fn borrow(&self) -> Cow<'_, Self> {
Cow::Borrowed(self)
}
}
pub type NamespaceMappings<'a> = Map<
Entries<'a, String, String>,
for<'b> fn((&'b String, &'b String)) -> UriMapping<'b>
>;
impl<'a> IntoIterator for &'a Namespace {
type Item = UriMapping<'a>;
type IntoIter = NamespaceMappings<'a>;
fn into_iter(self) -> Self::IntoIter {
fn mapper<'a>((prefix, uri): (&'a String, &'a String)) -> UriMapping<'a> {
(prefix, uri)
}
self.0.iter().map(mapper)
}
}
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct NamespaceStack(pub Vec<Namespace>);
impl NamespaceStack {
#[inline]
#[must_use]
pub fn empty() -> NamespaceStack {
NamespaceStack(Vec::with_capacity(2))
}
#[inline]
#[must_use]
pub fn default() -> NamespaceStack {
let mut nst = NamespaceStack::empty();
nst.push_empty();
nst.put(NS_XML_PREFIX, NS_XML_URI);
nst.put(NS_XMLNS_PREFIX, NS_XMLNS_URI);
nst.put(NS_NO_PREFIX, NS_EMPTY_URI);
nst
}
#[inline]
pub fn push_empty(&mut self) -> &mut NamespaceStack {
self.0.push(Namespace::empty());
self
}
#[inline]
pub fn pop(&mut self) -> Namespace {
self.0.pop().unwrap()
}
#[inline]
pub fn try_pop(&mut self) -> Option<Namespace> {
self.0.pop()
}
#[inline]
pub fn peek_mut(&mut self) -> &mut Namespace {
self.0.last_mut().unwrap()
}
#[inline]
#[must_use]
pub fn peek(&self) -> &Namespace {
self.0.last().unwrap()
}
pub fn put_checked<P, U>(&mut self, prefix: P, uri: U) -> bool
where P: Into<String> + AsRef<str>,
U: Into<String> + AsRef<str>
{
if self.0.iter().any(|ns| ns.get(&prefix) == Some(uri.as_ref())) {
false
} else {
self.put(prefix, uri);
true
}
}
#[inline]
pub fn put<P, U>(&mut self, prefix: P, uri: U) -> bool
where P: Into<String>, U: Into<String>
{
if let Some(ns) = self.0.last_mut() {
ns.put(prefix, uri)
} else {
false
}
}
#[inline]
pub fn get<'a, P: ?Sized + AsRef<str>>(&'a self, prefix: &P) -> Option<&'a str> {
let prefix = prefix.as_ref();
for ns in self.0.iter().rev() {
match ns.get(prefix) {
None => {},
r => return r,
}
}
None
}
#[must_use]
pub fn squash(&self) -> Namespace {
let mut result = BTreeMap::new();
for ns in &self.0 {
result.extend(ns.0.iter().map(|(k, v)| (k.clone(), v.clone())));
}
Namespace(result)
}
#[inline]
pub fn checked_target(&mut self) -> CheckedTarget<'_> {
CheckedTarget(self)
}
#[inline]
#[must_use]
pub fn iter(&self) -> NamespaceStackMappings<'_> {
self.into_iter()
}
}
pub struct NamespaceStackMappings<'a> {
namespaces: Rev<Iter<'a, Namespace>>,
current_namespace: Option<NamespaceMappings<'a>>,
used_keys: HashSet<&'a str>,
}
impl<'a> NamespaceStackMappings<'a> {
fn go_to_next_namespace(&mut self) -> bool {
self.current_namespace = self.namespaces.next().map(|ns| ns.into_iter());
self.current_namespace.is_some()
}
}
impl<'a> Iterator for NamespaceStackMappings<'a> {
type Item = UriMapping<'a>;
fn next(&mut self) -> Option<UriMapping<'a>> {
if self.current_namespace.is_none() && !self.go_to_next_namespace() {
return None;
}
let next_item = self.current_namespace.as_mut()?.next();
match next_item {
Some((k, v)) => if self.used_keys.contains(&k) {
self.next()
} else {
self.used_keys.insert(k);
Some((k, v))
},
None => if self.go_to_next_namespace() {
self.next()
} else {
None
}
}
}
}
impl<'a> IntoIterator for &'a NamespaceStack {
type Item = UriMapping<'a>;
type IntoIter = NamespaceStackMappings<'a>;
fn into_iter(self) -> Self::IntoIter {
NamespaceStackMappings {
namespaces: self.0.iter().rev(),
current_namespace: None,
used_keys: HashSet::new(),
}
}
}
pub type UriMapping<'a> = (&'a str, &'a str);
impl<'a> Extend<UriMapping<'a>> for Namespace {
fn extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=UriMapping<'a>> {
for (prefix, uri) in iterable {
self.put(prefix, uri);
}
}
}
impl<'a> Extend<UriMapping<'a>> for NamespaceStack {
fn extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=UriMapping<'a>> {
for (prefix, uri) in iterable {
self.put(prefix, uri);
}
}
}
pub struct CheckedTarget<'a>(&'a mut NamespaceStack);
impl<'a, 'b> Extend<UriMapping<'b>> for CheckedTarget<'a> {
fn extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=UriMapping<'b>> {
for (prefix, uri) in iterable {
self.0.put_checked(prefix, uri);
}
}
}