moex_client/models/
selectors.rs1use std::cmp::Ordering;
4
5use super::{Index, IndexAnalytics, SecurityBoard};
6
7pub trait IndexesExt {
9 fn retain_actual_by_till(&mut self);
11
12 fn into_actual_by_till(mut self) -> Self
14 where
15 Self: Sized,
16 {
17 self.retain_actual_by_till();
18 self
19 }
20}
21
22impl IndexesExt for Vec<Index> {
23 fn retain_actual_by_till(&mut self) {
24 let latest_till = self.iter().filter_map(Index::till).max();
25 self.retain(|index| index.till() == latest_till);
26 }
27}
28
29pub trait IndexAnalyticsExt {
31 fn retain_actual_by_session(&mut self);
34
35 fn into_actual_by_session(mut self) -> Self
37 where
38 Self: Sized,
39 {
40 self.retain_actual_by_session();
41 self
42 }
43
44 fn sort_by_weight_desc(&mut self);
46
47 fn into_sorted_by_weight_desc(mut self) -> Self
49 where
50 Self: Sized,
51 {
52 self.sort_by_weight_desc();
53 self
54 }
55}
56
57impl IndexAnalyticsExt for Vec<IndexAnalytics> {
58 fn retain_actual_by_session(&mut self) {
59 let Some(latest_trade_session_date) =
61 self.iter().map(IndexAnalytics::trade_session_date).max()
62 else {
63 return;
64 };
65 self.retain(|item| item.trade_session_date() == latest_trade_session_date);
66
67 let Some(latest_tradingsession) = self.iter().map(IndexAnalytics::tradingsession).max()
69 else {
70 return;
71 };
72 self.retain(|item| item.tradingsession() == latest_tradingsession);
73 }
74
75 fn sort_by_weight_desc(&mut self) {
76 self.sort_by(|left, right| {
77 right
78 .weight()
79 .partial_cmp(&left.weight())
82 .unwrap_or(Ordering::Equal)
83 .then_with(|| left.secid().as_str().cmp(right.secid().as_str()))
84 });
85 }
86}
87
88pub trait SecurityBoardsExt {
90 fn stock_primary_or_first(&self) -> Option<&SecurityBoard>;
92
93 fn into_stock_primary_or_first(self) -> Option<SecurityBoard>
95 where
96 Self: Sized;
97}
98
99impl SecurityBoardsExt for Vec<SecurityBoard> {
100 fn stock_primary_or_first(&self) -> Option<&SecurityBoard> {
101 let mut fallback = None;
102 for board in self {
103 if board.engine().as_str() != "stock" {
104 continue;
105 }
106 if board.is_primary() {
107 return Some(board);
108 }
109 if fallback.is_none() {
110 fallback = Some(board);
111 }
112 }
113 fallback
114 }
115
116 fn into_stock_primary_or_first(self) -> Option<SecurityBoard> {
117 let mut fallback = None;
118 for board in self {
119 if board.engine().as_str() != "stock" {
120 continue;
121 }
122 if board.is_primary() {
123 return Some(board);
124 }
125 if fallback.is_none() {
126 fallback = Some(board);
127 }
128 }
129 fallback
130 }
131}