use ahash::AHasher;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::fmt::{self, Debug, Display};
use std::hash::{Hash, Hasher};
use std::str::FromStr;
use super::expression::Term;
use super::format::Format;
use super::{Error, Id, Result};
mod builder;
mod convert;
mod macros;
pub use builder::Builder;
pub use convert::TryToSelector;
#[derive(Clone)]
pub struct Selector {
format: Format<7>,
hash: u64,
}
impl Selector {
#[inline]
#[must_use]
pub fn as_str(&self) -> &str {
self.format.as_str()
}
}
#[allow(clippy::must_use_candidate)]
impl Selector {
#[inline]
pub fn provider(&self) -> Option<Cow<'_, str>> {
Some(self.format.get(1)).filter(|value| !value.is_empty())
}
#[inline]
pub fn resource(&self) -> Option<Cow<'_, str>> {
Some(self.format.get(2)).filter(|value| !value.is_empty())
}
#[inline]
pub fn variant(&self) -> Option<Cow<'_, str>> {
Some(self.format.get(3)).filter(|value| !value.is_empty())
}
#[inline]
pub fn context(&self) -> Option<Cow<'_, str>> {
Some(self.format.get(4)).filter(|value| !value.is_empty())
}
#[inline]
pub fn location(&self) -> Option<Cow<'_, str>> {
Some(self.format.get(5)).filter(|value| !value.is_empty())
}
#[inline]
pub fn fragment(&self) -> Option<Cow<'_, str>> {
Some(self.format.get(6)).filter(|value| !value.is_empty())
}
}
impl AsRef<Format<7>> for Selector {
#[inline]
fn as_ref(&self) -> &Format<7> {
&self.format
}
}
impl FromStr for Selector {
type Err = Error;
fn from_str(value: &str) -> Result<Self> {
let format = Format::from_str(value)?;
if format.get(0) != "zrs" {
Err(Error::Prefix)?;
}
let hash = {
let mut hasher = AHasher::default();
format.hash(&mut hasher);
hasher.finish()
};
Ok(Self { format, hash })
}
}
impl TryFrom<Id> for Selector {
type Error = Error;
#[inline]
fn try_from(id: Id) -> Result<Self> {
let format = id.format.to_builder().with(0, "zrs").build()?;
let hash = {
let mut hasher = AHasher::default();
format.hash(&mut hasher);
hasher.finish()
};
Ok(Self { format, hash })
}
}
impl TryFrom<Term> for Selector {
type Error = Error;
#[inline]
fn try_from(term: Term) -> Result<Self> {
match term {
Term::Id(id) => id.try_into(),
Term::Selector(selector) => Ok(selector),
}
}
}
impl Hash for Selector {
#[inline]
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
state.write_u64(self.hash);
}
}
impl PartialEq for Selector {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.hash == other.hash && self.format == other.format
}
}
impl Eq for Selector {}
impl PartialOrd for Selector {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Selector {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.format.cmp(&other.format)
}
}
impl Display for Selector {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.format, f)
}
}
impl Debug for Selector {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Selector")
.field("provider", &self.provider())
.field("resource", &self.resource())
.field("variant", &self.variant())
.field("context", &self.context())
.field("location", &self.location())
.field("fragment", &self.fragment())
.finish()
}
}