use crate::id::expression::{Expression, Operand, Operator, Term};
use crate::id::selector::Selector;
use crate::id::Id;
use super::segment::atom::{Character, Wildcard};
use super::segment::{Atom, Segment, Segments, ToSegments};
use super::Specificity;
pub trait ToSpecificity {
fn to_specificity(&self) -> Specificity;
}
impl ToSpecificity for Expression {
#[inline]
fn to_specificity(&self) -> Specificity {
let iter = self.operands().iter().map(ToSpecificity::to_specificity);
match self.operator() {
Operator::Any => iter.reduce(Specificity::min).unwrap_or_default(),
Operator::All => iter.reduce(Specificity::sum).unwrap_or_default(),
Operator::Not => Specificity::default(),
}
}
}
impl ToSpecificity for Term {
#[inline]
fn to_specificity(&self) -> Specificity {
match self {
Term::Id(id) => id.to_specificity(),
Term::Selector(selector) => selector.to_specificity(),
}
}
}
impl ToSpecificity for Operand {
#[inline]
fn to_specificity(&self) -> Specificity {
match self {
Operand::Expression(expr) => expr.to_specificity(),
Operand::Term(term) => term.to_specificity(),
}
}
}
impl ToSpecificity for Id {
#[inline]
fn to_specificity(&self) -> Specificity {
let iter = 1..7;
iter.map(|index| self.as_ref().get(index).to_specificity())
.reduce(Specificity::sum)
.unwrap_or_default()
}
}
impl ToSpecificity for Selector {
#[inline]
fn to_specificity(&self) -> Specificity {
let iter = 1..7;
iter.map(|index| self.as_ref().get(index).to_specificity())
.reduce(Specificity::sum)
.unwrap_or_default()
}
}
impl ToSpecificity for Segments<'_> {
#[inline]
fn to_specificity(&self) -> Specificity {
self.iter()
.map(ToSpecificity::to_specificity)
.reduce(Specificity::sum)
.unwrap_or_default()
}
}
impl ToSpecificity for Segment<'_> {
#[inline]
fn to_specificity(&self) -> Specificity {
self.iter()
.map(ToSpecificity::to_specificity)
.reduce(Specificity::min_sum_len)
.unwrap_or_default()
}
}
impl ToSpecificity for Atom<'_> {
#[inline]
fn to_specificity(&self) -> Specificity {
match self {
Atom::Literal(literal) => {
let len = u16::try_from(literal.len()).unwrap_or(u16::MAX);
Specificity(1, 0, 0, len)
}
Atom::Wildcard(wildcard) => wildcard.to_specificity(),
Atom::Character(character) => character.to_specificity(),
Atom::Group(data) => data
.iter()
.map(ToSpecificity::to_specificity)
.reduce(Specificity::min)
.unwrap_or_default(),
}
}
}
impl ToSpecificity for Wildcard {
#[inline]
fn to_specificity(&self) -> Specificity {
match self {
Wildcard::Character => Specificity(0, 1, 0, 0),
Wildcard::Sequence => Specificity(0, 1, 0, 0),
Wildcard::Traversal => Specificity(0, 0, 1, 0),
}
}
}
impl ToSpecificity for Character<'_> {
#[inline]
fn to_specificity(&self) -> Specificity {
Specificity(0, 1, 0, 1)
}
}
impl<T> ToSpecificity for T
where
T: ToSegments,
{
#[inline]
fn to_specificity(&self) -> Specificity {
self.to_segments().to_specificity()
}
}