channel_index.rs

  1use crate::{Channel, ChannelId};
  2use collections::BTreeMap;
  3use rpc::proto;
  4use std::sync::Arc;
  5
  6#[derive(Default, Debug)]
  7pub struct ChannelIndex {
  8    channels_ordered: Vec<ChannelId>,
  9    channels_by_id: BTreeMap<ChannelId, Arc<Channel>>,
 10}
 11
 12impl ChannelIndex {
 13    pub fn by_id(&self) -> &BTreeMap<ChannelId, Arc<Channel>> {
 14        &self.channels_by_id
 15    }
 16
 17    pub fn ordered_channels(&self) -> &[ChannelId] {
 18        &self.channels_ordered
 19    }
 20
 21    pub fn clear(&mut self) {
 22        self.channels_ordered.clear();
 23        self.channels_by_id.clear();
 24    }
 25
 26    /// Delete the given channels from this index.
 27    pub fn delete_channels(&mut self, channels: &[ChannelId]) {
 28        self.channels_by_id
 29            .retain(|channel_id, _| !channels.contains(channel_id));
 30        self.channels_ordered
 31            .retain(|channel_id| !channels.contains(channel_id));
 32    }
 33
 34    pub fn bulk_insert(&mut self) -> ChannelPathsInsertGuard {
 35        ChannelPathsInsertGuard {
 36            channels_ordered: &mut self.channels_ordered,
 37            channels_by_id: &mut self.channels_by_id,
 38        }
 39    }
 40}
 41
 42/// A guard for ensuring that the paths index maintains its sort and uniqueness
 43/// invariants after a series of insertions
 44#[derive(Debug)]
 45pub struct ChannelPathsInsertGuard<'a> {
 46    channels_ordered: &'a mut Vec<ChannelId>,
 47    channels_by_id: &'a mut BTreeMap<ChannelId, Arc<Channel>>,
 48}
 49
 50impl<'a> ChannelPathsInsertGuard<'a> {
 51    pub fn insert(&mut self, channel_proto: proto::Channel) -> bool {
 52        let mut ret = false;
 53        if let Some(existing_channel) = self.channels_by_id.get_mut(&channel_proto.id) {
 54            let existing_channel = Arc::make_mut(existing_channel);
 55
 56            ret = existing_channel.visibility != channel_proto.visibility()
 57                || existing_channel.name != channel_proto.name
 58                || existing_channel.parent_path != channel_proto.parent_path;
 59
 60            existing_channel.visibility = channel_proto.visibility();
 61            existing_channel.name = channel_proto.name.into();
 62            existing_channel.parent_path = channel_proto.parent_path.into();
 63        } else {
 64            self.channels_by_id.insert(
 65                channel_proto.id,
 66                Arc::new(Channel {
 67                    id: channel_proto.id,
 68                    visibility: channel_proto.visibility(),
 69                    name: channel_proto.name.into(),
 70                    parent_path: channel_proto.parent_path,
 71                }),
 72            );
 73            self.insert_root(channel_proto.id);
 74        }
 75        ret
 76    }
 77
 78    fn insert_root(&mut self, channel_id: ChannelId) {
 79        self.channels_ordered.push(channel_id);
 80    }
 81}
 82
 83impl<'a> Drop for ChannelPathsInsertGuard<'a> {
 84    fn drop(&mut self) {
 85        self.channels_ordered.sort_by(|a, b| {
 86            let a = channel_path_sorting_key(*a, self.channels_by_id);
 87            let b = channel_path_sorting_key(*b, self.channels_by_id);
 88            a.cmp(b)
 89        });
 90        self.channels_ordered.dedup();
 91    }
 92}
 93
 94fn channel_path_sorting_key<'a>(
 95    id: ChannelId,
 96    channels_by_id: &'a BTreeMap<ChannelId, Arc<Channel>>,
 97) -> impl Iterator<Item = &str> {
 98    let (parent_path, name) = channels_by_id
 99        .get(&id)
100        .map_or((&[] as &[_], None), |channel| {
101            (channel.parent_path.as_slice(), Some(channel.name.as_ref()))
102        });
103    parent_path
104        .iter()
105        .filter_map(|id| Some(channels_by_id.get(id)?.name.as_ref()))
106        .chain(name)
107}