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())
	}
}