use crate::context::{Context, Offset};
use crate::io::Lifecycle;
pub trait Mapper {
fn setup(&mut self, _ctx: &mut Context) {}
fn map(&mut self, key: usize, value: &[u8], ctx: &mut Context) {
ctx.write(key.to_string().as_bytes(), value);
}
fn cleanup(&mut self, _ctx: &mut Context) {}
}
impl<M> Mapper for M
where
M: FnMut(usize, &[u8], &mut Context),
{
#[inline]
fn map(&mut self, key: usize, value: &[u8], ctx: &mut Context) {
self(key, value, ctx)
}
}
pub(crate) struct MapperLifecycle<M>
where
M: Mapper,
{
mapper: M,
}
impl<M> MapperLifecycle<M>
where
M: Mapper,
{
pub(crate) fn new(mapper: M) -> Self {
Self { mapper }
}
}
impl<M> Lifecycle for MapperLifecycle<M>
where
M: Mapper,
{
#[inline]
fn on_start(&mut self, ctx: &mut Context) {
ctx.insert(Offset::new());
self.mapper.setup(ctx);
}
#[inline]
fn on_entry(&mut self, input: &[u8], ctx: &mut Context) {
let offset = {
ctx.get_mut::<Offset>().unwrap().shift(input.len() + 2)
};
self.mapper.map(offset, input, ctx);
}
#[inline]
fn on_end(&mut self, ctx: &mut Context) {
self.mapper.cleanup(ctx);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::context::Contextual;
use crate::io::Lifecycle;
#[test]
fn test_mapper_lifecycle() {
let mut ctx = Context::new();
let mut mapper = MapperLifecycle::new(TestMapper);
mapper.on_start(&mut ctx);
{
let mut vet = |input: &[u8], expected: usize| {
mapper.on_entry(input, &mut ctx);
let pair = ctx.get::<TestPair>();
assert!(pair.is_some());
let pair = pair.unwrap();
assert_eq!(pair.0, expected);
assert_eq!(pair.1, input);
};
vet(b"first_input_line", 18);
vet(b"second_input_line", 37);
vet(b"third_input_line", 55);
}
mapper.on_end(&mut ctx);
}
struct TestPair(usize, Vec<u8>);
impl Contextual for TestPair {}
struct TestMapper;
impl Mapper for TestMapper {
fn map(&mut self, key: usize, val: &[u8], ctx: &mut Context) {
ctx.insert(TestPair(key, val.to_vec()));
}
}
}