use std::sync::Arc;
use bacnet_types::enums::ObjectType;
use bacnet_types::primitives::ObjectIdentifier;
use super::ObjectDatabase;
#[doc(hidden)]
pub type MembershipWaker = dyn Fn() + Send + Sync;
#[derive(Default)]
pub(super) struct MembershipQueue {
changed: Vec<ObjectIdentifier>,
schedule_retries: Vec<(ObjectIdentifier, ObjectIdentifier)>,
waker: Option<Arc<MembershipWaker>>,
}
#[doc(hidden)]
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct MembershipWork {
pub changed: Vec<ObjectIdentifier>,
pub schedule_retries: Vec<(ObjectIdentifier, ObjectIdentifier)>,
}
impl MembershipWork {
pub fn is_empty(&self) -> bool {
self.changed.is_empty() && self.schedule_retries.is_empty()
}
}
impl ObjectDatabase {
#[doc(hidden)]
pub fn set_membership_waker_internal(&mut self, waker: Option<Arc<MembershipWaker>>) {
self.membership.waker = waker;
}
#[doc(hidden)]
pub fn take_membership_work_internal(&mut self) -> MembershipWork {
MembershipWork {
changed: std::mem::take(&mut self.membership.changed),
schedule_retries: std::mem::take(&mut self.membership.schedule_retries),
}
}
pub(super) fn membership_changed(&mut self, oid: ObjectIdentifier, added: bool) {
let mut changed = self.recheck_input_references(oid);
changed.retain(|converter| *converter != oid);
let retries = if added {
self.schedules_refusing(oid)
} else {
Vec::new()
};
if changed.is_empty() && retries.is_empty() {
return;
}
for oid in changed {
if !self.membership.changed.contains(&oid) {
self.membership.changed.push(oid);
}
}
for retry in retries.into_iter().map(|schedule| (schedule, oid)) {
if !self.membership.schedule_retries.contains(&retry) {
self.membership.schedule_retries.push(retry);
}
}
if let Some(waker) = &self.membership.waker {
waker();
}
}
fn schedules_refusing(&self, oid: ObjectIdentifier) -> Vec<ObjectIdentifier> {
self.type_index
.get(&ObjectType::SCHEDULE)
.into_iter()
.flatten()
.copied()
.filter(|schedule| {
self.objects
.get(schedule)
.is_some_and(|object| object.retry_refusals_naming(oid).is_some())
})
.collect()
}
}
#[cfg(test)]
#[path = "membership_tests.rs"]
mod tests;