use crate::error::{SelectorNotMatched, SelectorResult};
use crate::traits::*;
pub mod number;
pub mod string;
pub mod ptr;
pub struct Selector<'a, Current, Parent: SelectorInstance> {
pub cursor: Option<&'a Current>,
pub parent: Parent,
}
impl<'a, Current, Parent: SelectorInstance> Copy for Selector<'a, Current, Parent> {}
impl<'a, Current, Parent: SelectorInstance> Clone for Selector<'a, Current, Parent> {
fn clone(&self) -> Self {
*self
}
}
impl<'a, C, P: SelectorInstance> Snapshot for Selector<'a, C, P> {
fn snapshot(&self) -> Self {
*self
}
}
impl<'a, C, P: SelectorInstance> Unmatch for Selector<'a, C, P> {
fn unmatch(&self) -> Self {
self.same_parent(None)
}
fn cond_unmatch(&self, condition: bool) -> Self {
if condition {
self.unmatch()
} else {
self.snapshot()
}
}
}
impl<'b, A, B: SelectorInstance> Selector<'b, A, B> {
pub fn with<'a, C, P: SelectorInstance>(cursor: Option<&'a C>, parent: P) -> Selector<'a, C, P> {
Selector { cursor, parent }
}
pub fn new<'a, C>(current: &'a C) -> Selector<'a, C, ()> {
Self::with(Some(current), ())
}
pub fn same_parent<C>(&self, cursor: Option<&'b C>) -> Selector<'b, C, B> {
Self::with(cursor, self.parent.snapshot())
}
}
impl<'a, C, P: SelectorInstance> Selector<'a, C, P> {
pub fn route_to<R>(
&self,
extractor: impl FnOnce(&'a C, &Self) -> Option<&'a R>,
) -> Selector<'a, R, Self> {
Self::with(self.cursor.and_then(|cursor| extractor(cursor, self)), self.snapshot())
}
pub fn backtrack(&self) -> P {
self.parent.snapshot()
}
pub fn up(&self) -> P {
if self.cursor.is_some() {
self.parent.snapshot()
} else {
self.parent.snapshot().unmatch()
}
}
}
impl<'a, C, P: SelectorInstance> Selector<'a, C, P> {
pub fn replace<T>(&self, v: &'a T) -> Selector<'a, T, P> {
self.same_parent(Some(v))
}
pub fn map<R>(&self, f: impl FnOnce(&'a C, &Self) -> &'a R) -> Selector<'a, R, P> {
self.same_parent(self.cursor.map(|cursor| f(cursor, self)))
}
pub fn require_matched(&self) -> SelectorResult<Self> {
if self.cursor.is_some() {
Ok(self.snapshot())
} else {
Err(SelectorNotMatched)
}
}
pub fn filter(&self, f: impl FnOnce(&'a C, &Self) -> bool) -> Self {
if let Some(cursor) = self.cursor && !f(cursor, self) {
self.unmatch()
} else {
self.snapshot()
}
}
pub fn cond_filter(&self, condition: bool, f: impl FnOnce(&'a C, &Self) -> bool) -> Self {
if condition {
self.filter(f)
} else {
self.snapshot()
}
}
pub async fn filter_async(&self, f: impl AsyncFnOnce(&'a C, &Self) -> bool) -> Self {
if let Some(cursor) = self.cursor && !f(cursor, self).await {
self.unmatch()
} else {
self.snapshot()
}
}
pub async fn cond_filter_async(&self, condition: bool, f: impl AsyncFnOnce(&'a C, &Self) -> bool) -> Self {
if condition {
self.filter_async(f).await
} else {
self.snapshot()
}
}
}
impl<'a, C, P: SelectorInstance> Selector<'a, C, P> {
pub fn select(&self) -> Option<&'a C> {
self.cursor
}
pub fn parent(&self) -> P {
self.parent.snapshot()
}
pub fn is_matched(&self) -> bool {
self.cursor.is_some()
}
pub fn extract<R>(&self, f: impl FnOnce(&'a C, &Self) -> R) -> Option<R> {
self.cursor.map(|cursor| f(cursor, self))
}
pub fn cond_extract<R>(&self, condition: bool, f: impl FnOnce(&'a C, &Self) -> R) -> Option<R> {
if condition {
self.extract(f)
} else {
None
}
}
pub async fn extract_async<R>(&self, f: impl AsyncFnOnce(&'a C, &Self) -> R) -> Option<R> {
if let Some(cursor) = self.cursor {
Some(f(cursor, self).await)
} else {
None
}
}
pub async fn cond_extract_async<R>(&self, condition: bool, f: impl AsyncFnOnce(&'a C, &Self) -> R) -> Option<R> {
if condition {
self.extract_async(f).await
} else {
None
}
}
pub fn inspect(&self, f: impl FnOnce(Option<&'a C>, &Self)) -> Self {
f(self.cursor, self);
self.snapshot()
}
pub fn cond_inspect(&self, condition: bool, f: impl FnOnce(Option<&'a C>, &Self)) -> Self {
if condition {
self.inspect(f)
} else {
self.snapshot()
}
}
pub async fn inspect_async(&self, f: impl AsyncFnOnce(Option<&'a C>, &Self)) -> Self {
f(self.cursor, self).await;
self.snapshot()
}
pub async fn cond_inspect_async(&self, condition: bool, f: impl AsyncFnOnce(Option<&'a C>, &Self)) -> Self {
if condition {
self.inspect_async(f).await
} else {
self.snapshot()
}
}
pub fn inspect_cursor(&self, f: impl FnOnce(&'a C, &Self)) -> Self {
if let Some(cursor) = self.cursor {
f(cursor, self)
}
self.snapshot()
}
pub fn cond_inspect_cursor(&self, condition: bool, f: impl FnOnce(&'a C, &Self)) -> Self {
if condition {
self.inspect_cursor(f)
} else {
self.snapshot()
}
}
pub async fn inspect_cursor_async(&self, f: impl AsyncFnOnce(&'a C, &Self)) -> Self {
if let Some(cursor) = self.cursor {
f(cursor, self).await
}
self.snapshot()
}
pub async fn cond_inspect_cursor_async(&self, condition: bool, f: impl AsyncFnOnce(&'a C, &Self)) -> Self {
if condition {
self.inspect_cursor_async(f).await
} else {
self.snapshot()
}
}
}