1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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[..];
}
}