use errors::{Error, ErrorKind};
use std::borrow::{Borrow, Cow};
use sxd_xpath::{Factory, XPath};
use util::Refable;
#[derive(Debug)]
pub struct XPathExpression<'a>(Repr<'a>);
pub fn parse(xpath_expr: &str) -> Result<XPathExpression<'static>, Error> {
parse_xpath(xpath_expr).map(|x| XPathExpression(Repr::Parsed(Refable::Owned(x))))
}
#[derive(Debug)]
enum Repr<'a> {
Parsed(Refable<'a, XPath>),
Unparsed(Cow<'a, str>),
}
impl<'a> XPathExpression<'a> {
pub(crate) fn parsed(&self) -> Result<Refable<XPath>, Error> {
match self.0 {
Repr::Parsed(ref refable) => Ok(refable.clone_ref()),
Repr::Unparsed(ref s) => parse_xpath(s).map(|x| Refable::Owned(x)),
}
}
pub(crate) fn to_string(&self) -> String {
match self.0 {
Repr::Parsed(ref refable) => {
let xpath: &XPath = refable.borrow();
format!("{:?}", xpath)
}
Repr::Unparsed(ref s) => s.to_string(),
}
}
}
impl From<XPath> for XPathExpression<'static> {
fn from(xpath: XPath) -> Self {
XPathExpression(Repr::Parsed(Refable::Owned(xpath)))
}
}
impl<'a> From<&'a XPath> for XPathExpression<'a> {
fn from(xpath: &'a XPath) -> Self {
XPathExpression(Repr::Parsed(Refable::Borrowed(xpath)))
}
}
impl<'a> From<&'a str> for XPathExpression<'a> {
fn from(s: &'a str) -> Self {
XPathExpression(Repr::Unparsed(Cow::Borrowed(s)))
}
}
impl<'a> From<String> for XPathExpression<'a> {
fn from(s: String) -> Self {
XPathExpression(Repr::Unparsed(Cow::Owned(s)))
}
}
impl<'a> From<&'a XPathExpression<'a>> for XPathExpression<'a> {
fn from(x: &'a XPathExpression<'a>) -> Self {
match x.0 {
Repr::Parsed(ref refable) => XPathExpression(Repr::Parsed(refable.clone_ref())),
Repr::Unparsed(ref s) => XPathExpression(Repr::Unparsed(s.clone())),
}
}
}
fn parse_xpath(xpath_expr: &str) -> Result<XPath, Error> {
Factory::new()
.build(xpath_expr)
.map_err(|e| Error::internal(format!("{}", e), ErrorKind::ParseXPath))?
.ok_or_else(|| Error::internal("Empty XPath expression.", ErrorKind::ParseXPath))
}