use num_traits::FromPrimitive;
use num_traits::real::Real;
use core::iter::FusedIterator;
use core::ops::RangeBounds;
use super::Equidistant;
use super::{Clamp, Composite, Repeat, Slice, Stack};
pub trait Signal<Input> {
type Output;
fn eval(&self, input: Input) -> Self::Output;
#[cfg_attr(feature = "linear", doc = "```rust")]
#[cfg_attr(not(feature = "linear"), doc = "```ignore")]
fn extract<I, J>(self, iterator: I) -> Extract<Self, J>
where
Self: Sized,
I: IntoIterator<IntoIter = J>,
J: Iterator<Item = Input>,
{
Extract {
signal: self,
iterator: iterator.into_iter(),
}
}
#[cfg_attr(feature = "linear", doc = "```rust")]
#[cfg_attr(not(feature = "linear"), doc = "```ignore")]
fn stack<G>(self, signal: G) -> Stack<Self, G>
where
Self: Sized,
{
Stack::new(self, signal)
}
#[cfg_attr(feature = "bezier", doc = "```rust")]
#[cfg_attr(not(feature = "bezier"), doc = "```ignore")]
fn composite<G>(self, signal: G) -> Composite<Self, G>
where
Self: Sized,
{
Composite::new(self, signal)
}
fn by_ref(&self) -> &Self {
self
}
#[cfg_attr(feature = "linear", doc = "```rust")]
#[cfg_attr(not(feature = "linear"), doc = "```ignore")]
fn sample<I, J>(&self, iterator: I) -> Extract<&Self, J>
where
Self: Sized,
I: IntoIterator<IntoIter = J>,
J: Iterator<Item = Input>,
{
self.extract(iterator)
}
}
impl<G: Signal<I> + ?Sized, I> Signal<I> for &G {
type Output = G::Output;
fn eval(&self, input: I) -> Self::Output {
(**self).eval(input)
}
}
pub trait Curve<R>: Signal<R>
where
R: Real,
{
fn domain(&self) -> [R; 2];
#[cfg_attr(feature = "linear", doc = "```rust")]
#[cfg_attr(not(feature = "linear"), doc = "```ignore")]
fn take(self, samples: usize) -> Take<Self, R>
where
Self: Sized,
R: FromPrimitive,
{
let [start, end] = self.domain();
Take(self.extract(Stepper::new(samples, start, end)))
}
#[cfg_attr(feature = "linear", doc = "```rust")]
#[cfg_attr(not(feature = "linear"), doc = "```ignore")]
fn slice<B>(self, bounds: B) -> Slice<Self, R>
where
Self: Sized,
B: RangeBounds<R>,
{
Slice::new(self, bounds)
}
#[cfg_attr(feature = "linear", doc = "```rust")]
#[cfg_attr(not(feature = "linear"), doc = "```ignore")]
fn clamp(self) -> Clamp<Self>
where
Self: Sized,
{
Clamp::new(self)
}
}
impl<C: Curve<R> + ?Sized, R> Curve<R> for &C
where
R: Real,
{
fn domain(&self) -> [R; 2] {
(**self).domain()
}
}
pub trait Chain: Signal<usize> {
fn len(&self) -> usize;
fn first(&self) -> Option<Self::Output> {
if self.is_empty() {
return None;
}
Some(self.eval(0))
}
fn last(&self) -> Option<Self::Output> {
if self.is_empty() {
return None;
}
Some(self.eval(self.len() - 1))
}
fn is_empty(&self) -> bool {
self.len() == 0
}
fn into_iter(self) -> IntoIter<Self>
where
Self: Sized,
{
IntoIter::new(self)
}
fn iter(&self) -> IntoIter<&Self> {
IntoIter::new(self)
}
fn repeat(self) -> Repeat<Self>
where
Self: Sized,
{
Repeat::new(self)
}
}
impl<G: Chain + ?Sized> Chain for &G {
fn len(&self) -> usize {
(**self).len()
}
}
pub trait ConstChain<const N: usize>: Chain {
fn to_array(&self) -> [Self::Output; N]
where
Self::Output: Copy + Default,
{
let mut arr = [Default::default(); N];
for (i, val) in arr.iter_mut().enumerate().take(N) {
*val = self.eval(i);
}
arr
}
}
impl<G: ConstChain<N> + ?Sized, const N: usize> ConstChain<N> for &G {}
#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct IntoIter<G> {
signal: G,
front: usize,
back: usize,
}
impl<G> IntoIter<G>
where
G: Chain,
{
pub fn new(signal: G) -> Self {
IntoIter {
front: 0,
back: signal.len(),
signal,
}
}
}
impl<G> Iterator for IntoIter<G>
where
G: Chain,
{
type Item = G::Output;
fn next(&mut self) -> Option<Self::Item> {
if self.front < self.back {
let res = self.signal.eval(self.front);
self.front += 1;
return Some(res);
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.back - self.front;
(len, Some(len))
}
fn count(self) -> usize {
self.back - self.front
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
if n >= self.back - self.front {
return None;
}
self.front += n;
self.next()
}
}
impl<G> FusedIterator for IntoIter<G> where G: Chain {}
impl<G> ExactSizeIterator for IntoIter<G> where G: Chain {}
impl<G> DoubleEndedIterator for IntoIter<G>
where
G: Chain,
{
fn next_back(&mut self) -> Option<Self::Item> {
if self.front < self.back {
let res = self.signal.eval(self.back);
self.back -= 1;
return Some(res);
}
None
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
if n >= self.back - self.front {
return None;
}
self.back -= n;
self.next_back()
}
}
#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Extract<G, I> {
signal: G,
iterator: I,
}
impl<G, I> Iterator for Extract<G, I>
where
G: Signal<I::Item>,
I: Iterator,
{
type Item = G::Output;
fn next(&mut self) -> Option<Self::Item> {
Some(self.signal.eval(self.iterator.next()?))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iterator.size_hint()
}
fn count(self) -> usize {
self.iterator.count()
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
Some(self.signal.eval(self.iterator.nth(n)?))
}
}
impl<G, I> FusedIterator for Extract<G, I>
where
G: Signal<I::Item>,
I: FusedIterator,
{
}
impl<G, I> ExactSizeIterator for Extract<G, I>
where
G: Signal<I::Item>,
I: ExactSizeIterator,
{
}
impl<G, I> DoubleEndedIterator for Extract<G, I>
where
G: Signal<I::Item>,
I: DoubleEndedIterator,
{
fn next_back(&mut self) -> Option<Self::Item> {
Some(self.signal.eval(self.iterator.next_back()?))
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
Some(self.signal.eval(self.iterator.nth_back(n)?))
}
}
#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Take<C, R>(Extract<C, Stepper<R>>)
where
R: Real;
impl<C, R> Iterator for Take<C, R>
where
C: Curve<R>,
R: Real + FromPrimitive,
{
type Item = C::Output;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
fn count(self) -> usize {
self.0.count()
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.0.nth(n)
}
}
impl<C, R> FusedIterator for Take<C, R>
where
C: Curve<R>,
R: Real + FromPrimitive,
{
}
impl<C, R> ExactSizeIterator for Take<C, R>
where
C: Curve<R>,
R: Real + FromPrimitive,
{
}
impl<C, R> DoubleEndedIterator for Take<C, R>
where
C: Curve<R>,
R: Real + FromPrimitive,
{
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.0.nth_back(n)
}
}
#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Stepper<R: Real = f64>(IntoIter<Equidistant<R>>);
impl<R> Stepper<R>
where
R: Real + FromPrimitive,
{
pub fn normalized(steps: usize) -> Self {
Stepper(Equidistant::normalized(steps).into_iter())
}
pub fn new(steps: usize, start: R, end: R) -> Self {
Stepper(Equidistant::new(steps, start, end).into_iter())
}
}
impl<R> Iterator for Stepper<R>
where
R: Real + FromPrimitive,
{
type Item = R;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
fn count(self) -> usize {
self.0.count()
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.0.nth(n)
}
}
impl<R> FusedIterator for Stepper<R> where R: Real + FromPrimitive {}
impl<R> ExactSizeIterator for Stepper<R> where R: Real + FromPrimitive {}
impl<R> DoubleEndedIterator for Stepper<R>
where
R: Real + FromPrimitive,
{
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.0.nth_back(n)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn stepper() {
let mut stepper = Stepper::<f64>::normalized(11);
let res = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0];
for val in res {
assert_f64_near!(val, stepper.next().unwrap());
}
let mut stepper = Stepper::new(5, 3.0, 5.0);
let res = [3.0, 3.5, 4.0, 4.5, 5.0];
for val in res {
assert_f64_near!(val, stepper.next().unwrap());
}
}
}