Files
khadhroony-solana-project/crates/ksp-offchain-transport-lib/src/market_price_registry.rs
2026-08-26 10:23:42 +02:00

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;