[−][src]Trait iterpipes::Pipe
An iterator-style pipe.
For more general information about pipes, please see the module-level documentation.
Associated Types
type InputItem
The type of input this pipe accepts.
type OutputItem
The type of output this pipe produces.
Required methods
fn next(&mut self, item: Self::InputItem) -> Self::OutputItem
Calculate the next output item, based on an input item.
Provided methods
fn bypass(self) -> Bypass<Self> where
Self: Sized,
Self::InputItem: Clone,
Self: Sized,
Self::InputItem: Clone,
Create a bypassed version of the pipe.
The returned pipe clones the input item, calculates the next output item and returns both the copied input item and the output item.
Example
use iterpipes::*; /// A pipe that rounds a floating point value to the nearest integer. struct Round; impl Pipe for Round { type InputItem = f32; type OutputItem = i32; fn next(&mut self, input: f32) -> i32 { input.round() as i32 } } let mut pipe = Round {}.bypass(); assert_eq!((0.5, 1), pipe.next(0.5)); assert_eq!((-2.2, -2), pipe.next(-2.2));
fn compose(self) -> Composed<Self> where
Self: Sized,
Self: Sized,
Create a composable pipe.
Composable pipes implement the >>
operator that concatenates pipes.
Example
use iterpipes::*; /// A pipe that turns an index into a periodic progress value between 0.0 and 1.0. struct Progress { period_length: usize, } impl Pipe for Progress { type InputItem = usize; type OutputItem = f32; fn next(&mut self, index: usize) -> f32 { (index % self.period_length) as f32 / self.period_length as f32 } } /// A pipe that turns a progress value into a square wave. struct SquareWave; impl Pipe for SquareWave { type InputItem = f32; type OutputItem = f32; fn next(&mut self, progress: f32) -> f32 { if progress < 0.5 { -1.0 } else { 1.0 } } } let mut pipe = PipeIter::new(0..).compose() >> Lazy::new(|i: Option<usize>| i.unwrap()) >> Progress {period_length: 4}.compose() >> SquareWave; for frame in &[-1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0] { assert_eq!(*frame, pipe.next(())); }
A technical note
The Compose
struct is a workaround the fact that this crate can not implement the Shr
trait (the >>
operator) for every type that implements Pipe
since Shr
isn't a part of this crate. This patttern is known as the newtype pattern.
fn connect<O: Pipe<InputItem = Self::OutputItem>>(
self,
other: O
) -> Connector<Self, O> where
Self: Sized,
self,
other: O
) -> Connector<Self, O> where
Self: Sized,
Connect two pipes.
The created pipe takes an input item for self
, calculates the intermediate value and then uses it to calculate the output value of the other
pipe.
Obviously, the InputItem
of self
and the OutputItem
of the other
pipe have to match!
Example
use iterpipes::*; /// A pipe that turns an index into a periodic progress value between 0.0 and 1.0. struct Progress { period_length: usize, } impl Pipe for Progress { type InputItem = usize; type OutputItem = f32; fn next(&mut self, index: usize) -> f32 { (index % self.period_length) as f32 / self.period_length as f32 } } /// A pipe that turns a progress value into a square wave. struct SquareWave; impl Pipe for SquareWave { type InputItem = f32; type OutputItem = f32; fn next(&mut self, progress: f32) -> f32 { if progress < 0.5 { -1.0 } else { 1.0 } } } let mut pipe = Progress {period_length: 4}.connect(SquareWave); for (index, frame) in [-1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0].iter().enumerate() { assert_eq!(*frame, pipe.next(index)); }
fn into_iter(self) -> IterPipe<Self> where
Self::InputItem: Default,
Self: Sized + Pipe<InputItem = ()>,
Self::InputItem: Default,
Self: Sized + Pipe<InputItem = ()>,
Wrap the pipe into an iterator.
For example, this can be used to iterate over a pipeline in a for
loop. The input item needs to have a default value, since the iterator has to create it on it's own, and the output item must be an Option
al value.
Example
use iterpipes::*; /// An pipe/iterator over a slice. struct SlicePipe<'a, T> { data: &'a [T], index: usize, } impl<'a, T> Pipe for SlicePipe<'a, T> { type InputItem = (); type OutputItem = Option<&'a T>; fn next(&mut self, _: ()) -> Option<&'a T> { let value = self.data.get(self.index); if value.is_some() { self.index += 1; } value } } const DATA: &[u32] = &[3, 2, 1]; for (index, value) in (SlicePipe {data: DATA, index: 0}).into_iter().enumerate() { assert_eq!(DATA[index], *value); }
fn optional(self) -> Optional<Self> where
Self: Sized,
Self: Sized,
Optionalize the pipe.
The decorated pipe's input and output items are the optional versions of the original input and output items. If an input item is fed into the decorated pipe, it returns some output value, but if None
is fed into the decorated pipe, None
is returned.
Example
use iterpipes::*; /// A pipe that multiplies an input item by a factor. struct Multiply<T> where T: std::ops::Mul<T> + Copy { factor: T, } impl<T> Pipe for Multiply<T> where T: std::ops::Mul<T> + Copy { type InputItem = T; type OutputItem = T::Output; fn next(&mut self, item: T) -> T::Output { item * self.factor } } let mut pipe = Multiply::<u32> { factor: 2 }.optional(); assert_eq!(Some(4), pipe.next(Some(2))); assert_eq!(None, pipe.next(None));
fn enumerate(self) -> Enumerate<Self> where
Self: Sized,
Self: Sized,
Enumerate the output items of a pipe.
The decorated pipe will return a tuple of an index and the output item. The index starts from 0 and is counted up for every output item.
Example
use iterpipes::*; /// A pipe that always returns a clone of the same value. struct DefaultPipe<T: Clone> { value: T, } impl<T: Clone> Pipe for DefaultPipe<T> { type InputItem = (); type OutputItem = T; fn next(&mut self, _: ()) -> T { self.value.clone() } } let mut pipe = DefaultPipe { value: 42u8 }.enumerate(); assert_eq!((0, 42), pipe.next(())); assert_eq!((1, 42), pipe.next(())); assert_eq!((2, 42), pipe.next(()));
fn boxed(
self
) -> Box<dyn Pipe<InputItem = Self::InputItem, OutputItem = Self::OutputItem>> where
Self: Sized + 'static,
self
) -> Box<dyn Pipe<InputItem = Self::InputItem, OutputItem = Self::OutputItem>> where
Self: Sized + 'static,
Create a boxed trait object of the pipe.
This might be useful to move pipes across API bounds since it hides the internal composition of the pipe.
Example
use iterpipes::*; fn create_pipe() -> Box<dyn Pipe<InputItem = usize, OutputItem = usize>> { Lazy::new(|i| i * 2).boxed() } let mut pipe = create_pipe(); for i in 0..4 { assert_eq!(i*2, pipe.next(i)); }
Implementations on Foreign Types
impl Pipe for ()
[src]
Loading content...
Implementors
impl<I, O, F> Pipe for Lazy<I, O, F> where
F: FnMut(I) -> O,
[src]
F: FnMut(I) -> O,
impl<I: Iterator> Pipe for PipeIter<I>
[src]
type InputItem = ()
type OutputItem = Option<I::Item>
fn next(&mut self, _: ()) -> Option<I::Item>
[src]
impl<P> Pipe for Bypass<P> where
P: Pipe,
P::InputItem: Clone,
[src]
P: Pipe,
P::InputItem: Clone,
type InputItem = P::InputItem
type OutputItem = (P::InputItem, P::OutputItem)
fn next(&mut self, input: P::InputItem) -> (P::InputItem, P::OutputItem)
[src]
impl<P> Pipe for Composed<P> where
P: Pipe,
[src]
P: Pipe,
type InputItem = P::InputItem
type OutputItem = P::OutputItem
fn next(&mut self, item: P::InputItem) -> P::OutputItem
[src]
impl<P> Pipe for Optional<P> where
P: Pipe,
[src]
P: Pipe,
type InputItem = Option<P::InputItem>
type OutputItem = Option<P::OutputItem>
fn next(&mut self, item: Option<P::InputItem>) -> Option<P::OutputItem>
[src]
impl<P0, P1> Pipe for Connector<P0, P1> where
P0: Pipe,
P1: Pipe<InputItem = P0::OutputItem>,
[src]
P0: Pipe,
P1: Pipe<InputItem = P0::OutputItem>,