argus/argus-core/src/signals/iter.rs
2023-05-05 14:33:19 -07:00

60 lines
1.7 KiB
Rust

//! Signal iterator.
use std::iter::{zip, Zip};
use std::time::Duration;
use super::Signal;
/// An iterator over a [`Signal`].
///
/// This takes into account if the signal is iterable or not, i.e., it produces samples
/// only for [`Signal::Sampled`] and empty iterators for [`Signal::Empty`] (as it
/// contains no values) and [`Signal::Constant`] (as there is no well defined start and
/// end to the signal).
#[derive(Debug, Default)]
pub enum Iter<'a, T> {
#[doc(hidden)]
#[default]
Empty,
#[doc(hidden)]
Iter(Zip<core::slice::Iter<'a, Duration>, core::slice::Iter<'a, T>>),
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = (&'a Duration, &'a T);
fn next(&mut self) -> Option<Self::Item> {
match self {
Iter::Empty => None,
Iter::Iter(iter) => iter.next(),
}
}
}
impl<'a, T> IntoIterator for &'a Signal<T> {
type IntoIter = Iter<'a, T>;
type Item = <Self::IntoIter as Iterator>::Item;
fn into_iter(self) -> Self::IntoIter {
match self {
Signal::Empty => Iter::default(),
Signal::Constant { value: _ } => Iter::default(),
Signal::Sampled { values, time_points } => Iter::Iter(zip(time_points, values)),
}
}
}
impl<T> FromIterator<(Duration, T)> for Signal<T>
where
T: Copy,
{
/// Takes a sequence of sample points and creates a signal.
///
/// # Panics
///
/// If the input data does not contain strictly monotonically increasing time
/// stamps. If this isn't desired, sort and deduplicate the input data.
fn from_iter<I: IntoIterator<Item = (Duration, T)>>(iter: I) -> Self {
Self::try_from_iter(iter).unwrap()
}
}