zed/crates/channel/src/channel_store/channel_index.rs
Conrad Irwin 4b672621d3 Aggressively simplify channel permissions:
- Only allow setting permissions on the root channel
- Only allow public channels to be children of public channels
2024-01-25 23:26:32 -07:00

108 lines
3.4 KiB
Rust

use crate::{Channel, ChannelId};
use collections::BTreeMap;
use rpc::proto;
use std::sync::Arc;
#[derive(Default, Debug)]
pub struct ChannelIndex {
channels_ordered: Vec<ChannelId>,
channels_by_id: BTreeMap<ChannelId, Arc<Channel>>,
}
impl ChannelIndex {
pub fn by_id(&self) -> &BTreeMap<ChannelId, Arc<Channel>> {
&self.channels_by_id
}
pub fn ordered_channels(&self) -> &[ChannelId] {
&self.channels_ordered
}
pub fn clear(&mut self) {
self.channels_ordered.clear();
self.channels_by_id.clear();
}
/// Delete the given channels from this index.
pub fn delete_channels(&mut self, channels: &[ChannelId]) {
self.channels_by_id
.retain(|channel_id, _| !channels.contains(channel_id));
self.channels_ordered
.retain(|channel_id| !channels.contains(channel_id));
}
pub fn bulk_insert(&mut self) -> ChannelPathsInsertGuard {
ChannelPathsInsertGuard {
channels_ordered: &mut self.channels_ordered,
channels_by_id: &mut self.channels_by_id,
}
}
}
/// A guard for ensuring that the paths index maintains its sort and uniqueness
/// invariants after a series of insertions
#[derive(Debug)]
pub struct ChannelPathsInsertGuard<'a> {
channels_ordered: &'a mut Vec<ChannelId>,
channels_by_id: &'a mut BTreeMap<ChannelId, Arc<Channel>>,
}
impl<'a> ChannelPathsInsertGuard<'a> {
pub fn insert(&mut self, channel_proto: proto::Channel) -> bool {
let mut ret = false;
if let Some(existing_channel) = self.channels_by_id.get_mut(&channel_proto.id) {
let existing_channel = Arc::make_mut(existing_channel);
ret = existing_channel.visibility != channel_proto.visibility()
|| existing_channel.name != channel_proto.name
|| existing_channel.parent_path != channel_proto.parent_path;
existing_channel.visibility = channel_proto.visibility();
existing_channel.name = channel_proto.name.into();
existing_channel.parent_path = channel_proto.parent_path.into();
} else {
self.channels_by_id.insert(
channel_proto.id,
Arc::new(Channel {
id: channel_proto.id,
visibility: channel_proto.visibility(),
name: channel_proto.name.into(),
parent_path: channel_proto.parent_path,
}),
);
self.insert_root(channel_proto.id);
}
ret
}
fn insert_root(&mut self, channel_id: ChannelId) {
self.channels_ordered.push(channel_id);
}
}
impl<'a> Drop for ChannelPathsInsertGuard<'a> {
fn drop(&mut self) {
self.channels_ordered.sort_by(|a, b| {
let a = channel_path_sorting_key(*a, self.channels_by_id);
let b = channel_path_sorting_key(*b, self.channels_by_id);
a.cmp(b)
});
self.channels_ordered.dedup();
}
}
fn channel_path_sorting_key<'a>(
id: ChannelId,
channels_by_id: &'a BTreeMap<ChannelId, Arc<Channel>>,
) -> impl Iterator<Item = &str> {
let (parent_path, name) = channels_by_id
.get(&id)
.map_or((&[] as &[_], None), |channel| {
(channel.parent_path.as_slice(), Some(channel.name.as_ref()))
});
parent_path
.iter()
.filter_map(|id| Some(channels_by_id.get(id)?.name.as_ref()))
.chain(name)
}