use std::convert::Infallible;
use std::iter;
use std::marker::PhantomData;
pub trait Logger<I>
{
type Error;
fn log(&mut self, item: I) -> Result<(), Self::Error>;
fn by_ref(&mut self) -> &mut Self
{
self
}
fn chain<L>(self, other: L) -> Chain<Self, L>
where Self: Sized
{
Chain{fst: self, snd: other}
}
fn filter<F>(self, f: F) -> Filter<Self, F>
where Self: Sized, F: FnMut(&I) -> bool
{
Filter{inner: self, f}
}
fn map<F, B>(self, f: F) -> Map<Self, F, B>
where Self: Sized
{
Map{inner: self, f, _phantom: PhantomData}
}
fn safe<E>(self) -> Safe<Self, E>
where Self: Sized
{
Safe{inner: self, _phantom: PhantomData}
}
}
impl<'a, I, L> Logger<I> for &'a mut L
where L: Logger<I>
{
type Error = L::Error;
fn log(&mut self, item: I) -> Result<(), Self::Error>
{
(**self).log(item)
}
}
pub struct Chain<L, M>
{
fst: L,
snd: M,
}
impl<I, L, M> Logger<I> for Chain<L, M>
where L: Logger<I>, M: Logger<I, Error=L::Error>, I: Clone
{
type Error = L::Error;
fn log(&mut self, item: I) -> Result<(), Self::Error>
{
self.fst.log(item.clone())?;
self.snd.log(item)
}
}
pub fn empty<I, E>() -> Empty<I, E>
{
Empty{_phantom: PhantomData}
}
pub struct Empty<I, E>
{
_phantom: PhantomData<fn() -> (I, E)>,
}
impl<I, E> Logger<I> for Empty<I, E>
{
type Error = E;
fn log(&mut self, _item: I) -> Result<(), E>
{
Ok(())
}
}
pub fn extender<C, I>(container: C) -> Extender<C, I>
{
Extender{container, _phantom: PhantomData}
}
pub struct Extender<C, I>
{
pub container: C,
_phantom: PhantomData<fn() -> I>,
}
impl<C, I> Logger<I> for Extender<C, I>
where C: Extend<I>
{
type Error = Infallible;
fn log(&mut self, item: I) -> Result<(), Self::Error>
{
let from = iter::once(item);
self.container.extend(from);
Ok(())
}
}
pub struct Filter<L, F>
{
inner: L,
f: F,
}
impl<I, L, F> Logger<I> for Filter<L, F>
where L: Logger<I>, F: FnMut(&I) -> bool
{
type Error = L::Error;
fn log(&mut self, item: I) -> Result<(), Self::Error>
{
if (self.f)(&item) {
self.inner.log(item)
} else {
Ok(())
}
}
}
pub struct Map<L, F, B>
{
inner: L,
f: F,
_phantom: PhantomData<fn() -> B>,
}
impl<I, L, F, B> Logger<B> for Map<L, F, B>
where L: Logger<I>, F: FnMut(B) -> I
{
type Error = L::Error;
fn log(&mut self, item: B) -> Result<(), Self::Error>
{
let new_item = (self.f)(item);
self.inner.log(new_item)
}
}
pub struct Safe<L, E>
{
inner: L,
_phantom: PhantomData<fn() -> E>,
}
impl<I, L, E> Logger<I> for Safe<L, E>
where L: Logger<I>
{
type Error = E;
fn log(&mut self, item: I) -> Result<(), Self::Error>
{
let result = self.inner.log(item);
drop(result);
Ok(())
}
}
#[cfg(test)]
mod tests
{
use super::*;
#[test]
fn test_chain()
{
let mut fst = extender(Vec::new());
let mut snd = extender(Vec::new());
let mut thd = fst.by_ref().chain(&mut snd);
thd.log(0).unwrap();
assert_eq!(&fst.container, &[0]);
assert_eq!(&snd.container, &[0]);
}
#[test]
fn test_filter()
{
let mut fst = extender(Vec::new());
let mut snd = fst.by_ref().filter(|&i| i >= 0);
snd.log(-1).unwrap();
snd.log(0).unwrap();
snd.log(1).unwrap();
assert_eq!(&fst.container, &[0, 1]);
}
#[test]
fn test_map()
{
let mut fst = extender(Vec::new());
let mut snd = fst.by_ref().map(|i: i32| i.abs());
snd.log(-1).unwrap();
snd.log(0).unwrap();
snd.log(1).unwrap();
assert_eq!(&fst.container, &[1, 0, 1]);
}
}