use std::{convert::TryFrom, marker::PhantomData, ops::Deref};
use alloy_primitives::Address;
use crate::{AssetId, Denomination, FeedConfig, FeedId, OracleError, StalenessPolicy};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FeedReady;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FeedBuilderState;
pub type FeedBuilder = Feed<FeedBuilderState>;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Feed<State = FeedReady> {
access: FeedAccess,
_state: PhantomData<State>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FeedAccess {
inner: FeedInner,
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct FeedInner {
kind: FeedKind,
id: Option<FeedId>,
label: Option<String>,
base: Option<AssetId>,
quote: Option<Denomination>,
staleness: StalenessPolicy,
}
#[derive(Clone, Debug, PartialEq, Eq)]
enum FeedKind {
Proxy { proxy: Address },
}
impl Feed<FeedBuilderState> {
pub fn proxy(proxy: Address) -> Self {
Self {
access: FeedAccess {
inner: FeedInner {
kind: FeedKind::Proxy { proxy },
id: None,
label: None,
base: None,
quote: None,
staleness: StalenessPolicy::default(),
},
},
_state: PhantomData,
}
}
pub fn id(mut self, id: impl Into<String>) -> Self {
self.access.inner.id = Some(FeedId::new(id));
self
}
pub fn feed_id(mut self, id: FeedId) -> Self {
self.access.inner.id = Some(id);
self
}
pub fn label(mut self, label: impl Into<String>) -> Self {
self.access.inner.label = Some(label.into());
self
}
pub fn base(mut self, base: AssetId) -> Self {
self.access.inner.base = Some(base);
self
}
pub fn quote(mut self, quote: Denomination) -> Self {
self.access.inner.quote = Some(quote);
self
}
pub fn max_age_secs(mut self, max_age_secs: u64) -> Feed {
self.access.inner.staleness = StalenessPolicy::max_age(max_age_secs);
self.build()
}
pub fn staleness(mut self, staleness: StalenessPolicy) -> Feed {
self.access.inner.staleness = staleness;
self.build()
}
pub fn build(self) -> Feed {
Feed {
access: self.access,
_state: PhantomData,
}
}
}
impl Deref for Feed {
type Target = FeedAccess;
fn deref(&self) -> &Self::Target {
&self.access
}
}
impl FeedAccess {
pub fn proxy(&self) -> Option<Address> {
match self.inner.kind {
FeedKind::Proxy { proxy } => Some(proxy),
}
}
pub fn id(&self) -> Option<FeedId> {
self.inner.id.clone()
}
pub fn base(&self) -> Option<&AssetId> {
self.inner.base.as_ref()
}
pub fn quote(&self) -> Option<&Denomination> {
self.inner.quote.as_ref()
}
pub fn label(&self) -> Option<&str> {
self.inner.label.as_deref()
}
}
impl TryFrom<Feed> for FeedConfig {
type Error = OracleError;
fn try_from(feed: Feed) -> Result<Self, Self::Error> {
feed_config_from_inner(feed.access.inner)
}
}
impl TryFrom<FeedBuilder> for FeedConfig {
type Error = OracleError;
fn try_from(feed: FeedBuilder) -> Result<Self, Self::Error> {
feed_config_from_inner(feed.access.inner)
}
}
fn feed_config_from_inner(feed: FeedInner) -> Result<FeedConfig, OracleError> {
let FeedKind::Proxy { proxy } = feed.kind;
Ok(FeedConfig {
proxy,
id: feed.id,
label: feed.label,
base: feed.base.map(String::from),
quote: feed.quote.map(String::from),
staleness: feed.staleness,
})
}