1use crate::{AnyVec, Error, Exit, GenericStoredVec, IterableVec, Result, StoredVec, VecValue};
2
3use super::{CheckedSub, EagerVec};
4
5impl<V> EagerVec<V>
6where
7 V: StoredVec,
8 V::I: CheckedSub,
9{
10 fn compute_with_lookback<A, F>(
11 &mut self,
12 max_from: V::I,
13 source: &impl IterableVec<V::I, A>,
14 lookback_len: usize,
15 exit: &Exit,
16 transform: F,
17 ) -> Result<()>
18 where
19 A: VecValue + Default,
20 F: Fn(usize, A, A) -> V::T,
21 {
22 self.validate_computed_version_or_reset(source.version())?;
23
24 self.truncate_if_needed(max_from)?;
25
26 self.repeat_until_complete(exit, |this| {
27 let skip = this.len();
28 let mut lookback = source.create_lookback(skip, lookback_len, 0);
29
30 for (i, current) in source.iter().enumerate().skip(skip) {
31 let previous = lookback.get_and_push(i, current.clone(), A::default());
32 let result = transform(i, current, previous);
33 this.checked_push_at(i, result)?;
34
35 if this.batch_limit_reached() {
36 break;
37 }
38 }
39
40 Ok(())
41 })
42 }
43
44 pub fn compute_previous_value<A>(
45 &mut self,
46 max_from: V::I,
47 source: &impl IterableVec<V::I, A>,
48 len: usize,
49 exit: &Exit,
50 ) -> Result<()>
51 where
52 A: VecValue + Default,
53 f32: From<A>,
54 V::T: From<f32>,
55 {
56 self.compute_with_lookback(max_from, source, len, exit, |i, _, previous| {
57 if i < len {
59 V::T::from(f32::NAN)
60 } else {
61 V::T::from(f32::from(previous))
62 }
63 })
64 }
65
66 pub fn compute_change<A>(
69 &mut self,
70 max_from: V::I,
71 source: &impl IterableVec<V::I, A>,
72 len: usize,
73 exit: &Exit,
74 ) -> Result<()>
75 where
76 A: VecValue + Default + Into<V::T>,
77 V::T: CheckedSub + Default,
78 {
79 self.compute_with_lookback(max_from, source, len, exit, |i, current, previous| {
80 if i < len {
81 V::T::default()
82 } else {
83 let current: V::T = current.into();
84 let previous: V::T = previous.into();
85 current.checked_sub(previous).unwrap()
86 }
87 })
88 }
89
90 pub fn compute_percentage_change<A>(
91 &mut self,
92 max_from: V::I,
93 source: &impl IterableVec<V::I, A>,
94 len: usize,
95 exit: &Exit,
96 ) -> Result<()>
97 where
98 A: VecValue + Default,
99 f32: From<A>,
100 V::T: From<f32>,
101 {
102 self.compute_with_lookback(max_from, source, len, exit, |i, current, previous| {
103 if i < len {
105 V::T::from(f32::NAN)
106 } else {
107 let current_f32 = f32::from(current);
108 let previous_f32 = f32::from(previous);
109 V::T::from(((current_f32 / previous_f32) - 1.0) * 100.0)
110 }
111 })
112 }
113
114 pub fn compute_cagr<A>(
115 &mut self,
116 max_from: V::I,
117 percentage_returns: &impl IterableVec<V::I, A>,
118 days: usize,
119 exit: &Exit,
120 ) -> Result<()>
121 where
122 A: VecValue + Default,
123 f32: From<A>,
124 V::T: From<f32>,
125 {
126 if days == 0 || !days.is_multiple_of(365) {
127 return Err(Error::InvalidArgument(
128 "days must be non-zero and a multiple of 365",
129 ));
130 }
131
132 let years = days / 365;
133
134 self.compute_transform(
135 max_from,
136 percentage_returns,
137 |(i, percentage, ..)| {
138 let cagr = (((f32::from(percentage) / 100.0 + 1.0).powf(1.0 / years as f32)) - 1.0)
139 * 100.0;
140 (i, V::T::from(cagr))
141 },
142 exit,
143 )
144 }
145}