sac-base 0.0.7

Base crate of the sac-signal and sac-control crates
Documentation
use alloc::vec::Vec;
use alloc::boxed::Box;
use core::any::Any;

pub struct Node<T>
    where T: Copy + Clone
{
    /// Stores data required to process the functions. This data can be specified the operations
    /// themselves. Allowing the operations to specify their own data containers, requires the
    /// use of boxed trait objects. This unfortunately induces a bit over runtime overhead.
    /// There might be a faster way to do this.
    pub data_container: Box<dyn Any>,

    /// Stores the data of the operation. This is the data that will be polled. This value is public
    /// to allow others to change the value without having to call a function. Which is supped to
    /// help speed up the setting and polling of data
    pub data: Vec<T>,

    /// A function pointer that will be called when the operation has to process its data.
    /// All operations have to specify a function to process its data. This can as example contain
    /// the functionality to add two values. Here they can mutate the value of self.data and access
    /// the data contained in data_container.
    /// The &Vec<T> acts an input from other operations. The length of the vector is dependant
    /// on how many operations are connected to it.
    /// Some operations can handle mutliple inputs (Add, Sub,...) while others like Diff can only
    /// handle one inputs and will ignore the others.
    pub clk: fn((Vec<&[T]>, usize), &mut Box<dyn Any>, &mut Vec<T>),
}

impl<T> Node<T>
    where T: Copy + Clone
{
    /// Generates a new node. This is done by all the operations. A operation has to specify a
    /// function according to which its data will be processed.
    /// Additionally the node requires a value according to which it can initialize its data field.
    /// If this wouldn't be provided, the network (and value) would be in a uninitialized state.
    /// Each operation can choose to specify a container to store data in it.
    /// Currently, all operations have to box a value and use it to init the node. This causes
    /// some unnecessary RAM usage. Maybe this could be avoided with Box::new_uninit();
    /// But this would put us into a undefined state which is to be avoided...
    ///
    /// ## Example
    /// ```rust
    /// use sac_base::network::node::Node;
    /// use std::any::Any;
    /// use core::ops;
    ///
    /// // Example code of the differentiation which uses an additional buffered value to safe the
    /// // last state. Instead of just one value, a whole struct could be allocated and moved into
    /// // the node as storage
    /// fn new<T>() -> Node<T>
    ///     where T: Copy + ops::Sub<Output=T> + 'static + Default
    /// {
    ///     let storage = Box::new(T::default()) as Box<dyn Any>;
    ///     let mut node = Node::new(storage, |data_input, data_buffer, output| {
    ///         let (inputs, max_len) = data_input;
    ///         let last_val: &mut T = data_buffer.downcast_mut::<T>().unwrap();
    ///         inputs.into_iter().take(1).into_iter().for_each(|data| {
    ///             data.into_iter().take(max_len).into_iter().for_each(|v| {
    ///                 let diff_result = *v - *last_val;
    ///                 output.insert(0, diff_result);
    ///                 *last_val = *v;
    ///             })
    ///         })
    ///     });
    ///     // Make sure we got a default value in location 0 of the vector
    ///     node.data.push(T::default());
    ///     return node;
    /// }
    /// ```
    pub fn new(container: Box<dyn Any>, clk: fn((Vec<&[T]>, usize),
                                         &mut Box<dyn Any>, &mut Vec<T>)) -> Self {
        Node {
            data_container: container,
            data: Vec::new(),
            clk: clk,
        }
    }

    /// Triggers the execution of the provided callback
    pub fn process(&mut self, inputs: (Vec<&[T]>, usize)){
        (self.clk)(inputs, &mut self.data_container, &mut self.data);
    }

    /// Sets the input value. Not necessarily needed since data is public.
    pub fn feed(&mut self, input: &[T]) {
        self.data = Vec::from(input);
    }

    /// Polls the value. Not necessarily needed since data is public.
    /// Currently the data is copied when polled.
    pub fn poll(&self) -> &[T] {
        // Copy the vector to allow the next client to work with it.
        // This is not ideal for performance and should be replace with a reference
        return &self.data[..];
    }
}