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