1use sp_runtime::DispatchResult;
21use sp_std::vec::Vec;
22
23pub trait DataFeeder<Key, Value, AccountId> {
25 fn feed_value(who: Option<AccountId>, key: Key, value: Value) -> DispatchResult;
27}
28
29pub trait DataProvider<Key, Value> {
31 fn get(key: &Key) -> Option<Value>;
33}
34
35pub trait DataProviderExtended<Key, TimestampedValue> {
37 fn get_all_values() -> impl Iterator<Item = (Key, Option<TimestampedValue>)>;
39}
40
41pub fn median<T: Ord + Clone>(mut items: Vec<T>) -> Option<T> {
43 if items.is_empty() {
44 return None;
45 }
46
47 let mid_index = items.len() / 2;
48
49 let (_, item, _) = items.select_nth_unstable(mid_index);
51 Some(item.clone())
52}
53
54#[macro_export]
56macro_rules! create_median_value_data_provider {
57 ($name:ident, $key:ty, $value:ty, $timestamped_value:ty, [$( $provider:ty ),*]) => {
58 pub struct $name;
59 impl $crate::DataProvider<$key, $value> for $name {
60 fn get(key: &$key) -> Option<$value> {
61 let mut values = vec![];
62 $(
63 if let Some(v) = <$provider as $crate::DataProvider<$key, $value>>::get(&key) {
64 values.push(v);
65 }
66 )*
67 $crate::traits::median(values)
68 }
69 }
70 impl $crate::DataProviderExtended<$key, $timestamped_value> for $name {
71 fn get_all_values() -> impl Iterator<Item = ($key, Option<$timestamped_value>)> {
72 let mut keys = sp_std::collections::btree_set::BTreeSet::new();
73 $(
74 <$provider as $crate::DataProviderExtended<$key, $timestamped_value>>::get_all_values()
75 .into_iter()
76 .for_each(|(k, _)| { keys.insert(k); });
77 )*
78 keys.into_iter().map(|k| (k, Self::get(&k)))
79 }
80 }
81 }
82}
83
84pub trait CombineData<Key, TimestampedValue> {
86 fn combine_data(
88 key: &Key,
89 values: Vec<TimestampedValue>,
90 prev_value: Option<TimestampedValue>,
91 ) -> Option<TimestampedValue>;
92}
93
94#[impl_trait_for_tuples::impl_for_tuples(30)]
96pub trait OnNewData<AccountId, Key, Value> {
97 fn on_new_data(who: &AccountId, key: &Key, value: &Value);
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use sp_std::cell::RefCell;
105
106 thread_local! {
107 static MOCK_PRICE_1: RefCell<Option<u8>> = RefCell::new(None);
108 static MOCK_PRICE_2: RefCell<Option<u8>> = RefCell::new(None);
109 static MOCK_PRICE_3: RefCell<Option<u8>> = RefCell::new(None);
110 static MOCK_PRICE_4: RefCell<Option<u8>> = RefCell::new(None);
111 }
112
113 macro_rules! mock_data_provider {
114 ($provider:ident, $price:ident) => {
115 pub struct $provider;
116 impl $provider {
117 fn set_price(price: Option<u8>) {
118 $price.with(|v| *v.borrow_mut() = price)
119 }
120 }
121 impl DataProvider<u8, u8> for $provider {
122 fn get(_: &u8) -> Option<u8> {
123 $price.with(|v| *v.borrow())
124 }
125 }
126 impl DataProviderExtended<u8, u8> for $provider {
127 fn get_all_values() -> impl Iterator<Item = (u8, Option<u8>)> {
128 vec![(0, Self::get(&0))].into_iter()
129 }
130 }
131 };
132 }
133
134 mock_data_provider!(Provider1, MOCK_PRICE_1);
135 mock_data_provider!(Provider2, MOCK_PRICE_2);
136 mock_data_provider!(Provider3, MOCK_PRICE_3);
137 mock_data_provider!(Provider4, MOCK_PRICE_4);
138
139 create_median_value_data_provider!(
140 Providers,
141 u8,
142 u8,
143 u8,
144 [Provider1, Provider2, Provider3, Provider4]
145 );
146
147 #[test]
148 fn median_value_data_provider_works() {
149 assert_eq!(<Providers as DataProvider<_, _>>::get(&0), None);
150
151 let data = vec![
152 (vec![None, None, None, Some(1)], Some(1)),
153 (vec![None, None, Some(2), Some(1)], Some(2)),
154 (vec![Some(5), Some(2), None, Some(7)], Some(5)),
155 (vec![Some(5), Some(13), Some(2), Some(7)], Some(7)),
156 ];
157
158 for (values, target) in data {
159 Provider1::set_price(values[0]);
160 Provider2::set_price(values[1]);
161 Provider3::set_price(values[2]);
162 Provider4::set_price(values[3]);
163
164 assert_eq!(<Providers as DataProvider<_, _>>::get(&0), target);
165 }
166 }
167}