use std::marker::PhantomData;
pub struct LazyPipeline<T, I>
where
I: Iterator<Item = T>,
{
source: I,
_phantom: PhantomData<T>,
}
impl<T, I> LazyPipeline<T, I>
where
I: Iterator<Item = T>,
{
pub fn new(source: I) -> Self {
Self {
source,
_phantom: PhantomData,
}
}
pub fn map<U, F>(self, f: F) -> LazyPipeline<U, impl Iterator<Item = U>>
where
F: FnMut(T) -> U,
{
LazyPipeline::new(self.source.map(f))
}
pub fn filter<F>(self, predicate: F) -> LazyPipeline<T, impl Iterator<Item = T>>
where
F: FnMut(&T) -> bool,
{
LazyPipeline::new(self.source.filter(predicate))
}
pub fn flat_map<U, F, II>(self, f: F) -> LazyPipeline<U, impl Iterator<Item = U>>
where
F: FnMut(T) -> II,
II: IntoIterator<Item = U>,
{
LazyPipeline::new(self.source.flat_map(f))
}
pub fn take(self, n: usize) -> LazyPipeline<T, impl Iterator<Item = T>> {
LazyPipeline::new(self.source.take(n))
}
pub fn skip(self, n: usize) -> LazyPipeline<T, impl Iterator<Item = T>> {
LazyPipeline::new(self.source.skip(n))
}
pub fn collect<C: FromIterator<T>>(self) -> C {
self.source.collect()
}
pub fn fold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, T) -> B,
{
self.source.fold(init, f)
}
pub fn any<F>(mut self, predicate: F) -> bool
where
F: FnMut(T) -> bool,
{
self.source.any(predicate)
}
pub fn all<F>(mut self, predicate: F) -> bool
where
F: FnMut(T) -> bool,
{
self.source.all(predicate)
}
pub fn count(self) -> usize {
self.source.count()
}
}
pub struct TransformationPipeline<T> {
transformations: Vec<fn(T) -> T>,
}
impl<T> Default for TransformationPipeline<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> TransformationPipeline<T> {
pub fn new() -> Self {
Self {
transformations: Vec::new(),
}
}
pub fn add_transformation(mut self, f: fn(T) -> T) -> Self {
self.transformations.push(f);
self
}
pub fn apply(&self, value: T) -> T {
self.transformations
.iter()
.fold(value, |acc, transform| transform(acc))
}
pub fn apply_all<I>(&self, values: I) -> Vec<T>
where
I: IntoIterator<Item = T>,
{
values.into_iter().map(|value| self.apply(value)).collect()
}
}
pub struct Lazy<T> {
value: Option<T>,
generator: Option<Box<dyn FnOnce() -> T>>,
}
impl<T> Lazy<T> {
pub fn new<F>(generator: F) -> Self
where
F: FnOnce() -> T + 'static,
{
Self {
value: None,
generator: Some(Box::new(generator)),
}
}
pub fn force(&mut self) -> &T {
if self.value.is_none() {
if let Some(generator) = self.generator.take() {
self.value = Some(generator());
}
}
self.value
.as_ref()
.expect("Lazy::force called but generator was already consumed and value is None")
}
pub fn is_evaluated(&self) -> bool {
self.value.is_some()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_lazy_pipeline() {
let numbers = vec![1, 2, 3, 4, 5];
let result: Vec<i32> = LazyPipeline::new(numbers.into_iter())
.filter(|&x| x > 2)
.map(|x| x * 2)
.collect();
assert_eq!(result, vec![6, 8, 10]);
}
#[test]
fn test_lazy_pipeline_take() {
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let result: Vec<i32> = LazyPipeline::new(numbers.into_iter()).take(3).collect();
assert_eq!(result, vec![1, 2, 3]);
}
#[test]
fn test_lazy_pipeline_skip() {
let numbers = vec![1, 2, 3, 4, 5];
let result: Vec<i32> = LazyPipeline::new(numbers.into_iter()).skip(2).collect();
assert_eq!(result, vec![3, 4, 5]);
}
#[test]
fn test_lazy_pipeline_flat_map() {
let numbers = vec![1, 2, 3];
let result: Vec<i32> = LazyPipeline::new(numbers.into_iter())
.flat_map(|x| vec![x, x * 2])
.collect();
assert_eq!(result, vec![1, 2, 2, 4, 3, 6]);
}
#[test]
fn test_lazy_pipeline_fold() {
let numbers = vec![1, 2, 3, 4, 5];
let sum = LazyPipeline::new(numbers.into_iter()).fold(0, |acc, x| acc + x);
assert_eq!(sum, 15);
}
#[test]
fn test_lazy_pipeline_any() {
let numbers = vec![1, 2, 3, 4, 5];
let has_three = LazyPipeline::new(numbers.into_iter()).any(|x| x == 3);
assert!(has_three);
}
#[test]
fn test_lazy_pipeline_all() {
let numbers = vec![2, 4, 6, 8];
let all_even = LazyPipeline::new(numbers.into_iter()).all(|x| x % 2 == 0);
assert!(all_even);
}
#[test]
fn test_lazy_pipeline_count() {
let numbers = vec![1, 2, 3, 4, 5];
let count = LazyPipeline::new(numbers.into_iter())
.filter(|&x| x > 2)
.count();
assert_eq!(count, 3);
}
#[test]
fn test_transformation_pipeline() {
let pipeline = TransformationPipeline::new()
.add_transformation(|x| x + 1)
.add_transformation(|x| x * 2);
let result = pipeline.apply(5);
assert_eq!(result, 12); }
#[test]
fn test_transformation_pipeline_apply_all() {
let pipeline = TransformationPipeline::new().add_transformation(|x| x + 10);
let values = vec![1, 2, 3];
let results = pipeline.apply_all(values);
assert_eq!(results, vec![11, 12, 13]);
}
#[test]
fn test_transformation_pipeline_empty() {
let pipeline = TransformationPipeline::<i32>::new();
let result = pipeline.apply(42);
assert_eq!(result, 42); }
#[test]
fn test_lazy_value() {
let mut lazy = Lazy::new(|| {
println!("Computing expensive value");
42
});
assert!(!lazy.is_evaluated());
assert_eq!(*lazy.force(), 42);
assert!(lazy.is_evaluated());
}
#[test]
fn test_lazy_value_multiple_force() {
let mut lazy = Lazy::new(|| 100);
assert_eq!(*lazy.force(), 100);
assert_eq!(*lazy.force(), 100); assert!(lazy.is_evaluated());
}
#[test]
fn test_lazy_pipeline_complex_chain() {
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let result: Vec<i32> = LazyPipeline::new(numbers.into_iter())
.filter(|&x| x % 2 == 0)
.map(|x| x * x)
.take(3)
.collect();
assert_eq!(result, vec![4, 16, 36]);
}
}