use crate::accum_ftzr::{Ftzr, IterFtzr};
use crate::as_tokens::AsTokens;
use crate::convert::Merged;
use crate::feature_from::FeatureFrom;
#[cfg(feature = "serde1")]
use serde::{Deserialize, Serialize};
use std::cmp;
#[derive(Hash, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Debug)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct BookEnds<A, B> {
front: A,
back: B,
front_size: usize,
back_size: usize,
}
pub fn bookends<A, B>(front: (A, usize), back: (B, usize)) -> BookEnds<A, B> {
BookEnds {
front: front.0,
front_size: front.1,
back_size: back.1,
back: back.0,
}
}
impl<'a, D, T: 'a, TA: 'a, TB: 'a, A, B> IterFtzr<&'a D> for BookEnds<A, B>
where
D: AsTokens<Token = T> + ?Sized,
A: IterFtzr<&'a [T], TokenGroup = TA>,
B: IterFtzr<&'a [T], TokenGroup = TB>,
{
type TokenGroup = FrontBack<TA, TB>;
type Iter = BookEndsIter<A::Iter, B::Iter>;
fn iterate_features(&self, origin: &'a D) -> Self::Iter {
let origin = origin.as_tokens();
let front_end = cmp::min(self.front_size, origin.len());
let back_start = origin.len() - cmp::min(self.back_size, origin.len());
BookEndsIter(
true,
self.front.iterate_features(&origin[..front_end]),
self.back.iterate_features(&origin[back_start..]),
)
}
}
#[derive(Hash, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Debug)]
pub struct BookEndsIter<A, B>(bool, A, B);
impl<A, B> Iterator for BookEndsIter<A, B>
where
A: Iterator,
B: Iterator,
{
type Item = FrontBack<A::Item, B::Item>;
fn next(&mut self) -> Option<Self::Item> {
if self.0 {
match self.1.next() {
None => {
self.0 = false;
self.2.next().map(FrontBack::Back)
}
otherwise => otherwise.map(FrontBack::Front),
}
} else {
self.2.next().map(FrontBack::Back)
}
}
}
#[derive(Hash, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Debug)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum FrontBack<A, B> {
Front(A),
Back(B),
}
impl<A, B, C> FeatureFrom<FrontBack<A, B>> for Merged<C>
where
C: FeatureFrom<A> + FeatureFrom<B>,
{
fn from(x: FrontBack<A, B>) -> Self {
Merged(match x {
FrontBack::Front(a) => FeatureFrom::from(a),
FrontBack::Back(a) => FeatureFrom::from(a),
})
}
}
impl<A, B, Ax, Bx> FeatureFrom<FrontBack<A, B>> for Result<Ax, Bx>
where
Ax: FeatureFrom<A>,
Bx: FeatureFrom<B>,
{
fn from(x: FrontBack<A, B>) -> Self {
match x {
FrontBack::Front(a) => Ok(FeatureFrom::from(a)),
FrontBack::Back(a) => Err(FeatureFrom::from(a)),
}
}
}
impl<A, B, Ax, Bx> FeatureFrom<FrontBack<A, B>> for FrontBack<Ax, Bx>
where
Ax: FeatureFrom<A>,
Bx: FeatureFrom<B>,
{
fn from(x: FrontBack<A, B>) -> Self {
match x {
FrontBack::Front(a) => FrontBack::Front(FeatureFrom::from(a)),
FrontBack::Back(a) => FrontBack::Back(FeatureFrom::from(a)),
}
}
}
impl<Origin, A, B> Ftzr<Origin> for BookEnds<A, B>
where
Self: IterFtzr<Origin>,
{
type TokenGroup = <Self as IterFtzr<Origin>>::TokenGroup;
fn push_tokens<Push>(&self, origin: Origin, push: &mut Push)
where
Push: FnMut(Self::TokenGroup),
{
for t in self.iterate_features(origin) {
push(t)
}
}
}