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 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
use super::{Error, Sequence};
use crate::helpers::{WithHistory, WithLastValue};
use std::fmt;
type BoxedFnMethod<'a, M> = Box<dyn FnMut(&'a <M as Method>::Input) -> <M as Method>::Output>;
/// Trait for creating methods for timeseries
///
/// # Regular methods usage
///
/// ### Iterate over vector's values
///
/// ```
/// use yata::methods::SMA;
/// use yata::prelude::*;
///
/// let s: Vec<_> = vec![1.,2.,3.,4.,5.,6.,7.,8.,9.,10.];
/// let mut ma = SMA::new(2, &s[0]).unwrap();
///
/// s.iter().enumerate().for_each(|(index, value)| {
/// assert_eq!(ma.next(value), (*value + s[index.saturating_sub(1)])/2.);
/// });
/// ```
///
/// ### Get a whole new vector over the input vector
///
/// You can call method `over` any `Sequence`:
/// ```
/// use yata::methods::SMA;
/// use yata::prelude::*;
///
/// let s: Vec<_> = vec![1.,2.,3.,4.,5.,6.,7.,8.,9.,10.];
/// let mut ma = SMA::new(2, &s[0]).unwrap();
///
/// let result = ma.over(s);
/// assert_eq!(result.as_slice(), &[1., 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]);
/// ```
///
/// Or you can provide `Method` to `Sequence`:
/// ```
/// use yata::methods::SMA;
/// use yata::prelude::*;
///
/// let s: Vec<_> = vec![1.,2.,3.,4.,5.,6.,7.,8.,9.,10.];
/// let mut ma = SMA::new(2, &s[0]).unwrap();
///
/// let result = s.call(&mut ma);
/// assert_eq!(result.as_slice(), &[1., 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]);
/// ```
///
/// Or you can even change `Sequence` values in-place:
/// ```
/// use yata::methods::SMA;
/// use yata::prelude::*;
///
/// let mut s: Vec<_> = vec![1.,2.,3.,4.,5.,6.,7.,8.,9.,10.];
/// let mut ma = SMA::new(2, &s[0]).unwrap();
///
/// s.apply(&mut ma);
/// assert_eq!(s.as_slice(), &[1., 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]);
/// ```
///
/// # Be advised
/// There is no `reset` method on the trait. If you need reset a state of the `Method` instance, you should just create a new one.
pub trait Method {
/// Method parameters
type Params;
/// Input value type
type Input: ?Sized;
/// Output value type
type Output;
/// Static method for creating an instance of the method with given `parameters` and initial `value` (simply first input value)
fn new(parameters: Self::Params, initial_value: &Self::Input) -> Result<Self, Error>
where
Self: Sized;
/// Generates next output value based on the given input `value`
fn next(&mut self, value: &Self::Input) -> Self::Output;
/// Creates an instance of the method with given `parameters` and initial `value`, wrapped by historical data holder
fn with_history(
parameters: Self::Params,
initial_value: &Self::Input,
) -> Result<WithHistory<Self, Self::Output>, Error>
where
Self: Sized,
Self::Output: fmt::Debug + Clone,
{
WithHistory::new(parameters, initial_value)
}
/// Creates an instance of the method with given `parameters` and initial `value`, wrapped by last produced value holder
fn with_last_value(
parameters: Self::Params,
initial_value: &Self::Input,
) -> Result<WithLastValue<Self, Self::Output>, Error>
where
Self: Sized,
Self::Output: fmt::Debug + Clone,
{
WithLastValue::new(parameters, initial_value)
}
/// Returns a name of the method
fn name(&self) -> &str {
let parts = std::any::type_name::<Self>().split("::");
parts.last().unwrap_or_default()
}
/// Returns memory size of the method `(size, align)`
#[deprecated]
fn memsize(&self) -> (usize, usize)
where
Self: Sized,
{
(std::mem::size_of::<Self>(), std::mem::align_of::<Self>())
}
/// Iterates the `Method` over the given `inputs` slice and returns `Vec` of output values.
///
/// # Guarantees
///
/// The length of an output `Vec` is always equal to the length of an `inputs` slice.
/// ```
/// use yata::methods::SMA;
/// use yata::prelude::*;
///
/// let s: Vec<_> = vec![1.,2.,3.,4.,5.,6.,7.,8.,9.,10.];
/// let mut ma = SMA::new(5, &s[0]).unwrap();
///
/// let result = ma.over(&s);
/// assert_eq!(result.len(), s.len());
/// ```
///
/// ```
/// use yata::methods::SMA;
/// use yata::prelude::*;
///
/// let s: Vec<_> = vec![1.,2.,3.,4.,5.,6.,7.,8.,9.,10.];
/// let mut ma = SMA::new(100, &s[0]).unwrap();
///
/// let result = ma.over(&s);
/// assert_eq!(result.len(), s.len());
/// ```
#[inline]
fn over<S>(&mut self, inputs: S) -> Vec<Self::Output>
where
S: Sequence<Self::Input>,
Self::Input: Sized,
Self: Sized,
{
inputs.call(self)
}
/// Applies method to the sequence in-place.
fn apply<T, S>(&mut self, sequence: &mut S)
where
S: Sequence<T> + AsMut<[T]> + ?Sized,
Self: Method<Input = T, Output = T> + Sized,
{
sequence.apply(self);
}
/// Creates new `Method` instance and iterates it over the given `inputs` slice and returns `Vec` of output values.
///
/// # Guarantees
///
/// The length of an output `Vec` is always equal to the length of an `inputs` slice.
fn new_over<S>(parameters: Self::Params, inputs: S) -> Result<Vec<Self::Output>, Error>
where
S: Sequence<Self::Input>,
Self::Input: Sized,
Self: Sized,
{
match inputs.get_initial_value() {
Some(v) => {
let mut method = Self::new(parameters, v)?;
Ok(inputs.call(&mut method))
}
None => Ok(Vec::new()),
}
}
/// Creates new `Method` instance and applies it to the `sequence`.
fn new_apply<T, S>(parameters: Self::Params, sequence: &mut S) -> Result<(), Error>
where
S: Sequence<T> + AsMut<[T]>,
Self: Method<Input = T, Output = T> + Sized,
{
let initial_value = {
// Why do we need to get immutable reference to get initial value?
// If try to remove it, then compile error occured.
// Looks like some Rust type system bug?
let seq = &*sequence;
match seq.get_initial_value() {
Some(v) => v,
None => return Ok(()),
}
};
let mut m = Self::new(parameters, initial_value)?;
sequence.apply(&mut m);
Ok(())
}
/// Creates a function from the `Method` instance
fn into_fn<'a>(mut self) -> BoxedFnMethod<'a, Self>
where
Self: Sized + 'static,
Self::Input: 'static,
{
let f = move |x| self.next(x);
Box::new(f)
}
/// Creates new function based on the method
fn new_fn(
params: Self::Params,
initial_value: &Self::Input,
) -> Result<BoxedFnMethod<Self>, Error>
where
Self: Sized + 'static,
{
let instance = Self::new(params, initial_value)?;
Ok(instance.into_fn())
}
}