templar_proxy_oracle_kernel/proxy/aggregator/
mod.rs

1pub mod method;
2
3#[cfg(any(feature = "borsh", feature = "schemars"))]
4use alloc::format;
5#[cfg(feature = "schemars")]
6use alloc::{boxed::Box, vec};
7
8use crate::Price;
9use method::{
10    median::{MedianHigh, MedianLow},
11    priority::Priority,
12    Aggregate,
13};
14
15use super::WeightedSource;
16
17serialize! {
18    #[derive(Debug, Clone, PartialEq, Eq)]
19    pub enum Aggregator<S> {
20        MedianLow(MedianLow<S>),
21        Priority(Priority<S>),
22        MedianHigh(MedianHigh<S>),
23    }
24}
25
26pub enum SourceIter<'a, S> {
27    Weighted(core::slice::Iter<'a, WeightedSource<S>>),
28    Plain(core::slice::Iter<'a, S>),
29}
30
31impl<S> SourceIter<'_, S> {
32    #[must_use]
33    pub fn is_empty(&self) -> bool {
34        match self {
35            Self::Weighted(iter) => iter.as_slice().is_empty(),
36            Self::Plain(iter) => iter.as_slice().is_empty(),
37        }
38    }
39}
40
41impl<'a, S> Iterator for SourceIter<'a, S> {
42    type Item = &'a S;
43
44    fn next(&mut self) -> Option<Self::Item> {
45        match self {
46            Self::Weighted(iter) => iter.next().map(|entry| &entry.source),
47            Self::Plain(iter) => iter.next(),
48        }
49    }
50
51    fn size_hint(&self) -> (usize, Option<usize>) {
52        match self {
53            Self::Weighted(iter) => iter.size_hint(),
54            Self::Plain(iter) => iter.size_hint(),
55        }
56    }
57}
58
59impl<S> ExactSizeIterator for SourceIter<'_, S> {}
60
61impl<S> Aggregator<S> {
62    pub fn median_low(entries: impl IntoIterator<Item = S>) -> Self {
63        Self::MedianLow(MedianLow::new(
64            entries.into_iter().map(|s| WeightedSource::new(s, 1)),
65        ))
66    }
67
68    pub fn median_high(entries: impl IntoIterator<Item = S>) -> Self {
69        Self::MedianHigh(MedianHigh::new(
70            entries.into_iter().map(|s| WeightedSource::new(s, 1)),
71        ))
72    }
73
74    pub fn priority(entries: impl IntoIterator<Item = S>) -> Self {
75        Self::Priority(Priority::new(entries))
76    }
77
78    pub fn name(&self) -> &'static str {
79        match self {
80            Self::MedianLow(_) => "MedianLow",
81            Self::Priority(_) => "Priority",
82            Self::MedianHigh(_) => "MedianHigh",
83        }
84    }
85
86    pub fn sources(&self) -> SourceIter<'_, S> {
87        match self {
88            Self::MedianLow(inner) => SourceIter::Weighted(inner.sources.iter()),
89            Self::Priority(inner) => SourceIter::Plain(inner.sources.iter()),
90            Self::MedianHigh(inner) => SourceIter::Weighted(inner.sources.iter()),
91        }
92    }
93}
94
95impl<S> Aggregate<S> for Aggregator<S> {
96    fn aggregate<I>(&self, prices: I) -> Result<Price, method::Error>
97    where
98        I: IntoIterator<Item = Option<Price>>,
99        I::IntoIter: ExactSizeIterator<Item = Option<Price>>,
100    {
101        match self {
102            Self::MedianLow(inner) => inner.aggregate(prices),
103            Self::Priority(inner) => inner.aggregate(prices),
104            Self::MedianHigh(inner) => inner.aggregate(prices),
105        }
106    }
107}