1use crate::context::{Context, Offset};
7use crate::io::Lifecycle;
8
9pub trait Mapper {
15 fn setup(&mut self, _ctx: &mut Context) {}
17
18 fn map(&mut self, key: usize, value: &[u8], ctx: &mut Context) {
24 ctx.write(key.to_string().as_bytes(), value);
25 }
26
27 fn cleanup(&mut self, _ctx: &mut Context) {}
29}
30
31impl<M> Mapper for M
33where
34 M: FnMut(usize, &[u8], &mut Context),
35{
36 #[inline]
38 fn map(&mut self, key: usize, value: &[u8], ctx: &mut Context) {
39 self(key, value, ctx)
40 }
41}
42
43pub(crate) struct MapperLifecycle<M>
45where
46 M: Mapper,
47{
48 mapper: M,
49}
50
51impl<M> MapperLifecycle<M>
53where
54 M: Mapper,
55{
56 pub(crate) fn new(mapper: M) -> Self {
58 Self { mapper }
59 }
60}
61
62impl<M> Lifecycle for MapperLifecycle<M>
64where
65 M: Mapper,
66{
67 #[inline]
69 fn on_start(&mut self, ctx: &mut Context) {
70 ctx.insert(Offset::new());
71 self.mapper.setup(ctx);
72 }
73
74 #[inline]
79 fn on_entry(&mut self, input: &[u8], ctx: &mut Context) {
80 let offset = {
81 ctx.get_mut::<Offset>().unwrap().shift(input.len() + 2)
83 };
84
85 self.mapper.map(offset, input, ctx);
86 }
87
88 #[inline]
90 fn on_end(&mut self, ctx: &mut Context) {
91 self.mapper.cleanup(ctx);
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98 use crate::context::Contextual;
99 use crate::io::Lifecycle;
100
101 #[test]
102 fn test_mapper_lifecycle() {
103 let mut ctx = Context::new();
104 let mut mapper = MapperLifecycle::new(TestMapper);
105
106 mapper.on_start(&mut ctx);
107
108 {
109 let mut vet = |input: &[u8], expected: usize| {
110 mapper.on_entry(input, &mut ctx);
111
112 let pair = ctx.get::<TestPair>();
113
114 assert!(pair.is_some());
115
116 let pair = pair.unwrap();
117
118 assert_eq!(pair.0, expected);
119 assert_eq!(pair.1, input);
120 };
121
122 vet(b"first_input_line", 18);
123 vet(b"second_input_line", 37);
124 vet(b"third_input_line", 55);
125 }
126
127 mapper.on_end(&mut ctx);
128 }
129
130 struct TestPair(usize, Vec<u8>);
131
132 impl Contextual for TestPair {}
133
134 struct TestMapper;
135
136 impl Mapper for TestMapper {
137 fn map(&mut self, key: usize, val: &[u8], ctx: &mut Context) {
138 ctx.insert(TestPair(key, val.to_vec()));
139 }
140 }
141}