use alloc::collections::BTreeMap;
use alloc::collections::BTreeSet;
use alloc::collections::btree_map::Entry;
use alloc::vec::Vec;
use iceoryx2::{
config::Config,
prelude::CallbackProgression,
service::{Service, ServiceDetails, ServiceListError, service_hash::ServiceHash},
};
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum SyncError {
InsufficientPermissions,
ServiceLookupFailure,
}
impl core::fmt::Display for SyncError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "SyncError::{self:?}")
}
}
impl core::error::Error for SyncError {}
impl From<ServiceListError> for SyncError {
fn from(error: ServiceListError) -> Self {
match error {
ServiceListError::InsufficientPermissions => Self::InsufficientPermissions,
ServiceListError::InternalError => Self::ServiceLookupFailure,
}
}
}
#[derive(Debug, Default)]
pub struct Tracker<S: Service> {
config: Config,
services: BTreeMap<ServiceHash, ServiceDetails<S>>,
}
impl<S: Service> Tracker<S> {
pub fn new(config: &Config) -> Self {
Self {
config: config.clone(),
services: BTreeMap::new(),
}
}
pub fn sync(&mut self) -> Result<(Vec<ServiceHash>, Vec<ServiceDetails<S>>), SyncError> {
let mut discovered_ids = BTreeSet::<ServiceHash>::new();
let mut added_ids = Vec::<ServiceHash>::new();
S::list(&self.config, |service| {
let id = *service.static_details.service_hash();
discovered_ids.insert(id);
if let Entry::Vacant(e) = self.services.entry(id) {
e.insert(service);
added_ids.push(id);
}
CallbackProgression::Continue
})?;
let mut removed_services = Vec::new();
let undiscovered_ids: Vec<ServiceHash> = self
.services
.keys()
.filter(|&id| !discovered_ids.contains(id))
.cloned()
.collect();
for id in undiscovered_ids {
if let Some(service) = self.services.remove(&id) {
removed_services.push(service);
}
}
Ok((added_ids, removed_services))
}
pub fn get(&self, id: &ServiceHash) -> Option<&ServiceDetails<S>> {
self.services.get(id)
}
pub fn get_all(&self) -> Vec<&ServiceDetails<S>> {
self.services.values().collect()
}
}