use super::*;
use core::marker::PhantomData;
#[derive(Clone)]
struct EntrySnapshotInner {
registry: VeilidComponentRegistry,
cur_ts: Timestamp,
entries: Vec<BucketEntrySnapshot>,
}
impl fmt::Debug for EntrySnapshotInner {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EntrySnapshotInner")
.field("cur_ts", &self.cur_ts)
.field("entries_len", &self.entries.len())
.finish()
}
}
#[derive(Debug)]
pub(crate) struct EntrySnapshot {
inner: Arc<EntrySnapshotInner>,
_not_send: PhantomData<*const ()>,
}
impl Clone for EntrySnapshot {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
_not_send: PhantomData,
}
}
}
impl VeilidComponentRegistryAccessor for EntrySnapshot {
fn registry(&self) -> VeilidComponentRegistry {
self.inner.registry.clone()
}
}
impl EntrySnapshot {
pub fn new(
registry: VeilidComponentRegistry,
cur_ts: Timestamp,
entries: Vec<BucketEntrySnapshot>,
) -> Self {
Self {
inner: Arc::new(EntrySnapshotInner {
registry,
cur_ts,
entries,
}),
_not_send: PhantomData,
}
}
#[expect(dead_code)]
pub fn cur_ts(&self) -> Timestamp {
self.inner.cur_ts
}
pub fn entries(&self) -> &[BucketEntrySnapshot] {
&self.inner.entries
}
pub fn existing_node_ids(&self) -> HashSet<NodeId> {
self.inner
.entries
.iter()
.flat_map(|snap| snap.node_ids.iter().cloned())
.collect()
}
#[expect(dead_code)]
pub fn into_entries(self) -> Vec<BucketEntrySnapshot> {
Arc::unwrap_or_clone(self.inner).entries
}
#[cfg_attr(feature = "instrument", instrument(level = "trace", skip_all, fields(__VEILID_LOG_KEY = self.log_key())))]
pub fn get_peers_with_sort_and_filter<T, O>(
&self,
node_count: usize,
cur_ts: Timestamp,
mut filters: VecDeque<RoutingTableEntryFilter>,
mut pre_sort_filter: RoutingTableEntryPreSortFilter,
mut compare: RoutingTableEntrySort,
transform: T,
) -> Vec<O>
where
T: FnMut(Option<BucketEntrySnapshot>) -> O,
{
let self_entry: Option<BucketEntrySnapshot> = None;
let include_self = filters.iter_mut().all(|filter| filter(&self_entry, cur_ts));
let mut nodes: Vec<Option<BucketEntrySnapshot>> =
Vec::with_capacity(self.inner.entries.len() + if include_self { 1 } else { 0 });
for entry in self.inner.entries.iter().cloned().map(Some) {
if filters.iter_mut().all(|filter| filter(&entry, cur_ts)) {
nodes.push(entry);
}
}
if include_self {
nodes.push(None);
}
pre_sort_filter(&mut nodes, cur_ts);
nodes.sort_by(|a, b| compare(a, b, cur_ts));
nodes.into_iter().take(node_count).map(transform).collect()
}
#[expect(dead_code)]
pub fn get_entry_count(
&self,
routing_domain_set: RoutingDomainSet,
min_state: BucketEntryState,
crypto_kinds: &[CryptoKind],
) -> usize {
let mut count = 0usize;
for entry in &self.inner.entries {
if entry.state >= min_state
&& !entry.routing_domain_set().is_disjoint(routing_domain_set)
&& !common_crypto_kinds(&entry.crypto_kinds(), crypto_kinds).is_empty()
{
count += 1;
}
}
count
}
}