use slab::Slab;
use crate::id::matcher::Matcher;
use super::condition::Condition;
use super::error::Result;
use super::expression::{IntoExpression, Operator, Term};
use super::Filter;
#[derive(Debug, Default)]
pub struct Builder {
conditions: Slab<Condition>,
}
impl Filter {
#[inline]
#[must_use]
pub fn builder() -> Builder {
Builder::default()
}
#[inline]
#[must_use]
pub fn into_builder(self) -> Builder {
Builder { conditions: self.conditions }
}
}
impl Builder {
#[inline]
#[must_use]
pub fn insert<T>(&mut self, expr: T) -> usize
where
T: IntoExpression,
{
let builder = Condition::builder(expr);
self.conditions.insert(builder.optimize().build())
}
#[inline]
pub fn remove(&mut self, index: usize) {
self.conditions.remove(index);
}
#[allow(clippy::cast_possible_truncation)]
pub fn build(self) -> Result<Filter> {
let mut builder = Matcher::builder();
let mut mapping = Vec::with_capacity(self.conditions.len());
let mut negations = Vec::new();
for (index, condition) in &self.conditions {
for term in condition.terms() {
mapping.push(index as u32);
match term {
Term::Id(id) => builder.add(id)?,
Term::Selector(selector) => builder.add(selector)?,
};
}
let mut iter = condition.instructions().iter();
if iter.any(|instruction| instruction.operator() == Operator::Not) {
negations.push(index as u32);
}
}
Ok(Filter {
conditions: self.conditions,
negations,
mapping,
matcher: builder.build()?,
})
}
}
#[allow(clippy::must_use_candidate)]
impl Builder {
#[inline]
pub fn len(&self) -> usize {
self.conditions.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.conditions.is_empty()
}
}