orml_traits/
data_provider.rs1use sp_runtime::DispatchResult;
2use sp_std::vec::Vec;
3
4pub trait DataFeeder<Key, Value, AccountId> {
6 fn feed_value(who: Option<AccountId>, key: Key, value: Value) -> DispatchResult;
8}
9
10pub trait DataProvider<Key, Value> {
12 fn get(key: &Key) -> Option<Value>;
14}
15
16pub trait DataProviderExtended<Key, TimestampedValue> {
19 fn get_no_op(key: &Key) -> Option<TimestampedValue>;
21 fn get_all_values() -> Vec<(Key, Option<TimestampedValue>)>;
23}
24
25#[allow(dead_code)] pub fn median<T: Ord + Clone>(mut items: Vec<T>) -> Option<T> {
27 if items.is_empty() {
28 return None;
29 }
30
31 let mid_index = items.len() / 2;
32
33 let (_, item, _) = items.select_nth_unstable(mid_index);
35 Some(item.clone())
36}
37
38#[macro_export]
39macro_rules! create_median_value_data_provider {
40 ($name:ident, $key:ty, $value:ty, $timestamped_value:ty, [$( $provider:ty ),*]) => {
41 pub struct $name;
42 impl $crate::DataProvider<$key, $value> for $name {
43 fn get(key: &$key) -> Option<$value> {
44 let mut values = vec![];
45 $(
46 if let Some(v) = <$provider as $crate::DataProvider<$key, $value>>::get(&key) {
47 values.push(v);
48 }
49 )*
50 $crate::data_provider::median(values)
51 }
52 }
53 impl $crate::DataProviderExtended<$key, $timestamped_value> for $name {
54 fn get_no_op(key: &$key) -> Option<$timestamped_value> {
55 let mut values = vec![];
56 $(
57 if let Some(v) = <$provider as $crate::DataProviderExtended<$key, $timestamped_value>>::get_no_op(&key) {
58 values.push(v);
59 }
60 )*
61 $crate::data_provider::median(values)
62 }
63 fn get_all_values() -> Vec<($key, Option<$timestamped_value>)> {
64 let mut keys = sp_std::collections::btree_set::BTreeSet::new();
65 $(
66 <$provider as $crate::DataProviderExtended<$key, $timestamped_value>>::get_all_values()
67 .into_iter()
68 .for_each(|(k, _)| { keys.insert(k); });
69 )*
70 keys.into_iter().map(|k| (k, Self::get_no_op(&k))).collect()
71 }
72 }
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use sp_std::cell::RefCell;
80
81 thread_local! {
82 static MOCK_PRICE_1: RefCell<Option<u8>> = RefCell::new(None);
83 static MOCK_PRICE_2: RefCell<Option<u8>> = RefCell::new(None);
84 static MOCK_PRICE_3: RefCell<Option<u8>> = RefCell::new(None);
85 static MOCK_PRICE_4: RefCell<Option<u8>> = RefCell::new(None);
86 }
87
88 macro_rules! mock_data_provider {
89 ($provider:ident, $price:ident) => {
90 pub struct $provider;
91 impl $provider {
92 fn set_price(price: Option<u8>) {
93 $price.with(|v| *v.borrow_mut() = price)
94 }
95 }
96 impl DataProvider<u8, u8> for $provider {
97 fn get(_: &u8) -> Option<u8> {
98 $price.with(|v| *v.borrow())
99 }
100 }
101 impl DataProviderExtended<u8, u8> for $provider {
102 fn get_no_op(_: &u8) -> Option<u8> {
103 $price.with(|v| *v.borrow())
104 }
105 fn get_all_values() -> Vec<(u8, Option<u8>)> {
106 vec![(0, Self::get_no_op(&0))]
107 }
108 }
109 };
110 }
111
112 mock_data_provider!(Provider1, MOCK_PRICE_1);
113 mock_data_provider!(Provider2, MOCK_PRICE_2);
114 mock_data_provider!(Provider3, MOCK_PRICE_3);
115 mock_data_provider!(Provider4, MOCK_PRICE_4);
116
117 create_median_value_data_provider!(Providers, u8, u8, u8, [Provider1, Provider2, Provider3, Provider4]);
118
119 #[test]
120 fn median_value_data_provider_works() {
121 assert_eq!(<Providers as DataProvider<_, _>>::get(&0), None);
122
123 let data = vec![
124 (vec![None, None, None, Some(1)], Some(1)),
125 (vec![None, None, Some(2), Some(1)], Some(2)),
126 (vec![Some(5), Some(2), None, Some(7)], Some(5)),
127 (vec![Some(5), Some(13), Some(2), Some(7)], Some(7)),
128 ];
129
130 for (values, target) in data {
131 Provider1::set_price(values[0]);
132 Provider2::set_price(values[1]);
133 Provider3::set_price(values[2]);
134 Provider4::set_price(values[3]);
135
136 assert_eq!(<Providers as DataProvider<_, _>>::get(&0), target);
137 }
138 }
139}