124 lines
5.2 KiB
Rust
124 lines
5.2 KiB
Rust
// file: crates/ksp-offchain-transport-lib/src/market_price_registry.rs
|
|
// version: 2
|
|
|
|
//! Provider-neutral registry projection for configured market-price providers.
|
|
|
|
const MARKET_PRICE_PROVIDER_REGISTRY_MAX_ENTRIES: usize = 64;
|
|
|
|
/// Immutable provider descriptor plus its current generic runtime state.
|
|
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
|
|
pub struct MarketPriceProviderRegistryEntry {
|
|
descriptor: crate::MarketPriceProviderDescriptor,
|
|
state: crate::MarketPriceProviderState,
|
|
}
|
|
|
|
impl crate::MarketPriceProviderRegistryEntry {
|
|
/// Returns the provider capability descriptor.
|
|
#[must_use]
|
|
pub const fn descriptor(&self) -> &crate::MarketPriceProviderDescriptor {
|
|
return &self.descriptor;
|
|
}
|
|
|
|
/// Returns the provider-neutral runtime state.
|
|
#[must_use]
|
|
pub const fn state(&self) -> &crate::MarketPriceProviderState {
|
|
return &self.state;
|
|
}
|
|
|
|
/// Replaces this entry's generic availability projection for the owning runtime service.
|
|
pub(crate) fn set_availability(&mut self, availability: crate::MarketPriceProviderAvailability) {
|
|
self.state.set_availability(availability);
|
|
}
|
|
|
|
/// Creates one generic registry entry while keeping descriptor and state identity synchronized.
|
|
#[must_use]
|
|
pub fn new(descriptor: crate::MarketPriceProviderDescriptor, availability: crate::MarketPriceProviderAvailability) -> Self {
|
|
let state = crate::MarketPriceProviderState::new(descriptor.id().clone(), availability);
|
|
return Self { descriptor, state };
|
|
}
|
|
}
|
|
|
|
/// Deterministically ordered registry of configured market-price providers.
|
|
#[derive(Clone, Debug, Default, Eq, PartialEq, serde::Serialize)]
|
|
pub struct MarketPriceProviderRegistry {
|
|
entries: std::vec::Vec<crate::MarketPriceProviderRegistryEntry>,
|
|
}
|
|
|
|
impl crate::MarketPriceProviderRegistry {
|
|
/// Returns a provider descriptor by opaque identifier.
|
|
#[must_use]
|
|
pub fn descriptor(&self, provider_id: &crate::MarketPriceProviderId) -> std::option::Option<&crate::MarketPriceProviderDescriptor> {
|
|
return self.entry(provider_id).map(crate::MarketPriceProviderRegistryEntry::descriptor);
|
|
}
|
|
|
|
/// Returns all configured provider entries in stable provider-id order.
|
|
#[must_use]
|
|
pub fn entries(&self) -> &[crate::MarketPriceProviderRegistryEntry] {
|
|
return self.entries.as_slice();
|
|
}
|
|
|
|
/// Returns one configured registry entry by opaque identifier.
|
|
#[must_use]
|
|
pub fn entry(&self, provider_id: &crate::MarketPriceProviderId) -> std::option::Option<&crate::MarketPriceProviderRegistryEntry> {
|
|
let index = self.entries.binary_search_by(|entry| return entry.descriptor().id().cmp(provider_id));
|
|
return match index {
|
|
std::result::Result::Ok(value) => self.entries.get(value),
|
|
std::result::Result::Err(_) => std::option::Option::None,
|
|
};
|
|
}
|
|
|
|
/// Reports whether no provider is currently registered.
|
|
#[must_use]
|
|
pub fn is_empty(&self) -> bool {
|
|
return self.entries.is_empty();
|
|
}
|
|
|
|
/// Returns the configured provider count.
|
|
#[must_use]
|
|
pub fn len(&self) -> usize {
|
|
return self.entries.len();
|
|
}
|
|
|
|
/// Returns one provider-neutral runtime state by opaque identifier.
|
|
#[must_use]
|
|
pub fn state(&self, provider_id: &crate::MarketPriceProviderId) -> std::option::Option<&crate::MarketPriceProviderState> {
|
|
return self.entry(provider_id).map(crate::MarketPriceProviderRegistryEntry::state);
|
|
}
|
|
|
|
/// Updates one existing provider availability and reports whether the provider was present.
|
|
pub(crate) fn set_availability(&mut self, provider_id: &crate::MarketPriceProviderId, availability: crate::MarketPriceProviderAvailability) -> bool {
|
|
let index = self.entries.binary_search_by(|entry| return entry.descriptor().id().cmp(provider_id));
|
|
let entry = match index {
|
|
std::result::Result::Ok(value) => self.entries.get_mut(value),
|
|
std::result::Result::Err(_) => std::option::Option::None,
|
|
};
|
|
if let std::option::Option::Some(entry) = entry {
|
|
entry.set_availability(availability);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Builds one bounded deterministic registry and rejects duplicate provider identifiers.
|
|
pub fn new(mut entries: std::vec::Vec<crate::MarketPriceProviderRegistryEntry>) -> ksp_core_lib::Result<Self> {
|
|
if entries.len() > MARKET_PRICE_PROVIDER_REGISTRY_MAX_ENTRIES {
|
|
return std::result::Result::Err(registry_error("entry_count"));
|
|
}
|
|
entries.sort_by(|left, right| return left.descriptor().id().cmp(right.descriptor().id()));
|
|
for index in 1..entries.len() {
|
|
if entries[index - 1].descriptor().id() == entries[index].descriptor().id() {
|
|
return std::result::Result::Err(registry_error("provider_id"));
|
|
}
|
|
}
|
|
return std::result::Result::Ok(Self { entries });
|
|
}
|
|
}
|
|
|
|
fn registry_error(field: &'static str) -> ksp_core_lib::Error {
|
|
return ksp_core_lib::Error::new(crate::ERROR_CODE_MARKET_PRICE_REGISTRY_INVALID, "Market-price provider registry is invalid").with_context("field", field);
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "../unit_tests/market_price_registry.rs"]
|
|
mod tests;
|