siraph 0.1.2

A node-based digital signal processing crate
Documentation
use crate::{Input, Node, Output, Register};

use rand::distributions::{Distribution, Standard};
use rand::rngs::ThreadRng;
use rand::Rng;

/// A node that outputs a new value each time the `resample` input is set to `true`.
///
/// # Inputs
/// * **resample**: When this input is set to true, a new value is sampled from the
/// given distribution and random number generatior.
///
/// # Outputs
/// * **output**: The sampled values.
pub struct SampleAndHold<R, D, T> {
    rng: R,
    dist: D,

    resample: Input<bool>,
    output: Output<T>,
}

impl<T> Default for SampleAndHold<ThreadRng, Standard, T> {
    fn default() -> Self {
        Self::new()
    }
}

impl<R, D, T> SampleAndHold<R, D, T> {
    /// Creates a new `SampleAndHold` node with the given `Rng` and `Distribution`.
    pub fn with_rng_dist(rng: R, dist: D) -> Self {
        Self {
            rng,
            dist,
            resample: Input::default(),
            output: Output::default(),
        }
    }
}

impl<R, T> SampleAndHold<R, Standard, T> {
    /// Creates a new `SampleAndHold` node with the given `Rng` and the `Standard`
    /// distribution.
    pub fn with_rng(rng: R) -> Self {
        Self::with_rng_dist(rng, Standard)
    }
}

impl<D, T> SampleAndHold<ThreadRng, D, T> {
    /// Creates a new `SampleAndHold` node with `ThreadRng` and the given
    /// distribution.
    pub fn with_dist(dist: D) -> Self {
        Self::with_rng_dist(ThreadRng::default(), dist)
    }
}

impl<T> SampleAndHold<ThreadRng, Standard, T> {
    /// Creates a new `SampleAndHold` node with `ThreadRng` and the `Standard`
    /// distribution.
    pub fn new() -> Self {
        Self::with_rng(ThreadRng::default())
    }
}

impl<R, D, T> Node for SampleAndHold<R, D, T>
where
    R: Rng,
    D: Distribution<T>,
    T: 'static,
{
    fn register(&self, r: &mut Register) {
        r.input("resample", &self.resample);
        r.output("output", &self.output);
    }

    fn process(&mut self) {
        if self.output.is_used() {
            if self.resample.get().unwrap_or_default() {
                self.output.set(self.dist.sample(&mut self.rng));
            }
        }
    }

    fn reset(&mut self) {}
}