From: Chris Mikkelson Date: Wed, 9 Apr 2025 19:51:06 +0000 (-0500) Subject: Add map capability to Source, SeekableIter X-Git-Url: https://git.mikk.net/?a=commitdiff_plain;h=refs%2Fheads%2Fback-to-impl;p=mtbl-rs Add map capability to Source, SeekableIter --- diff --git a/src/iter.rs b/src/iter.rs index e72a287..67a92dc 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -1,5 +1,6 @@ use crate::dupsort::DupsortIter; use crate::filter::FilterIter; +use crate::map::MapIter; use crate::merge::MergeIter; use crate::Entry; use std::cmp::Ordering; @@ -31,6 +32,14 @@ pub trait SeekableIter: Iterator { { FilterIter::new(self, filter_func) } + + fn map_func(self, map_func: F) -> MapIter + where + F: FnMut(Self::Item) -> O, + Self: Sized, + { + MapIter::new(self, map_func) + } } impl SeekableIter for Box { diff --git a/src/lib.rs b/src/lib.rs index 7b47e6f..d8060fb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ mod dupsort; mod entry; mod filter; mod iter; +mod map; mod merge; mod merger; pub mod reader; diff --git a/src/map.rs b/src/map.rs new file mode 100644 index 0000000..a2f746b --- /dev/null +++ b/src/map.rs @@ -0,0 +1,117 @@ +use crate::{SeekableIter, Source}; + +pub struct MapIter +where + I: SeekableIter, + F: FnMut(I::Item) -> O, +{ + iter: I, + mapf: F, +} + +impl MapIter +where + I: SeekableIter, + F: FnMut(I::Item) -> O, +{ + pub fn new(iter: I, mapf: F) -> Self { + Self { iter, mapf } + } +} + +impl Iterator for MapIter +where + I: SeekableIter, + F: FnMut(I::Item) -> O, +{ + type Item = O; + + fn next(&mut self) -> Option { + let item = self.iter.next()?; + Some((self.mapf)(item)) + } +} + +impl SeekableIter for MapIter +where + I: SeekableIter, + F: FnMut(I::Item) -> O, +{ + fn seek(&mut self, key: &[u8]) { + self.iter.seek(key); + } +} + +pub struct MapSource +where + S: Source, +{ + source: S, + #[allow(clippy::type_complexity)] + map: Box O>, +} + +impl MapSource +where + S: Source, +{ + pub fn new(source: S, map: F) -> Self + where + F: Fn(S::Item) -> O + 'static, + { + Self { + source, + map: Box::new(map), + } + } +} + +impl Source for MapSource +where + S: Source, +{ + type Item = O; + fn iter(&self) -> impl SeekableIter { + self.source.iter().map_func(&self.map) + } +} + +#[cfg(test)] +mod test { + use crate::source::test_source::TestSource; + use crate::Entry; + use crate::Source; + + struct CompVec(Vec); + impl PartialEq<[u8]> for CompVec { + fn eq(&self, other: &[u8]) -> bool { + self.0.as_slice().eq(other) + } + } + impl PartialOrd<[u8]> for CompVec { + fn partial_cmp(&self, other: &[u8]) -> Option { + self.0.as_slice().partial_cmp(other) + } + } + + #[test] + fn test_mapsource() { + let ts = TestSource((0u8..10).map(|i| Entry::new(vec![i], vec![])).collect()) + .map(|e| CompVec(Vec::from(e.key()))); + assert_eq!( + ts.iter().map(|cv| cv.0).collect::>(), + (0u8..10).map(|i| vec![i]).collect::>() + ); + assert_eq!( + ts.get_range(&[2u8], &[7u8]) + .map(|cv| cv.0) + .collect::>(), + (2u8..8) + .map(|i| { + println!("{i}"); + vec![i] + }) + .collect::>() + ) + } +} diff --git a/src/source.rs b/src/source.rs index 04d9dd3..4efbb29 100644 --- a/src/source.rs +++ b/src/source.rs @@ -1,6 +1,7 @@ use crate::dupsort::DupsortSource; use crate::filter::FilterSource; use crate::iter::{PrefixIter, RangeIter}; +use crate::map::MapSource; use crate::merge::MergeSource; use crate::{Entry, SeekableIter}; @@ -51,6 +52,14 @@ pub trait Source { FilterSource::new(self, filter_func) } + fn map(self, map_func: F) -> MapSource + where + Self: Sized, + F: Fn(Self::Item) -> O + 'static, + { + MapSource::new(self, map_func) + } + fn into_boxed(self) -> Box> where Self: Sized + 'static,