// 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, } 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) -> ksp_core_lib::Result { 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;