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}