orml_traits/
data_provider.rs

1use sp_runtime::DispatchResult;
2use sp_std::vec::Vec;
3
4/// Data provider with ability to provide data with no-op, and provide all data.
5pub trait DataFeeder<Key, Value, AccountId> {
6	/// Provide a new value for a given key from an operator
7	fn feed_value(who: Option<AccountId>, key: Key, value: Value) -> DispatchResult;
8}
9
10/// A simple trait to provide data
11pub trait DataProvider<Key, Value> {
12	/// Get data by key
13	fn get(key: &Key) -> Option<Value>;
14}
15
16/// Extended data provider to provide timestamped data by key with no-op, and
17/// all data.
18pub trait DataProviderExtended<Key, TimestampedValue> {
19	/// Get timestamped value by key
20	fn get_no_op(key: &Key) -> Option<TimestampedValue>;
21	/// Provide a list of tuples of key and timestamped value
22	fn get_all_values() -> Vec<(Key, Option<TimestampedValue>)>;
23}
24
25#[allow(dead_code)] // rust cannot detect usage in macro_rules
26pub 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	// Won't panic as `items` ensured not empty.
34	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}