matrix_sdk/event_handler/
maps.rsuse std::{
borrow::Borrow,
collections::{btree_map, BTreeMap},
};
use ruma::{OwnedRoomId, RoomId};
use super::{EventHandlerFn, EventHandlerHandle, EventHandlerWrapper, HandlerKind};
#[derive(Default)]
pub(super) struct EventHandlerMaps {
by_kind: BTreeMap<HandlerKind, Vec<EventHandlerWrapper>>,
by_kind_type: BTreeMap<KindTypeWrap, Vec<EventHandlerWrapper>>,
by_kind_roomid: BTreeMap<KindRoomId, Vec<EventHandlerWrapper>>,
by_kind_type_roomid: BTreeMap<KindTypeRoomIdWrap, Vec<EventHandlerWrapper>>,
}
impl EventHandlerMaps {
pub fn add(&mut self, handle: EventHandlerHandle, handler_fn: Box<EventHandlerFn>) {
let wrapper = EventHandlerWrapper { handler_id: handle.handler_id, handler_fn };
match Key::new(handle) {
Key::Kind(key) => {
self.by_kind.entry(key).or_default().push(wrapper);
}
Key::KindType(key) => {
self.by_kind_type.entry(key).or_default().push(wrapper);
}
Key::KindRoomId(key) => {
self.by_kind_roomid.entry(key).or_default().push(wrapper);
}
Key::KindTypeRoomId(key) => {
self.by_kind_type_roomid.entry(key).or_default().push(wrapper)
}
}
}
pub fn get_handlers<'a>(
&'a self,
ev_kind: HandlerKind,
ev_type: &str,
room_id: Option<&'a RoomId>,
) -> impl Iterator<Item = (EventHandlerHandle, &'a EventHandlerFn)> + 'a {
let kind_kv = self.by_kind.get_key_value(&ev_kind).map(|(_, handlers)| (None, handlers));
let kind_type_kv = self
.by_kind_type
.get_key_value(&KindType { ev_kind, ev_type })
.map(|(key, handlers)| (Some(key.0.ev_type), handlers));
let maybe_roomid_kvs = room_id
.map(|r_id| {
let room_id = r_id.to_owned();
let kind_roomid_kv = self
.by_kind_roomid
.get_key_value(&KindRoomId { ev_kind, room_id })
.map(|(_, handlers)| (None, handlers));
let room_id = r_id.to_owned();
let kind_type_roomid_kv = self
.by_kind_type_roomid
.get_key_value(&KindTypeRoomId { ev_kind, ev_type, room_id })
.map(|(key, handlers)| (Some(key.0.ev_type), handlers));
[kind_roomid_kv, kind_type_roomid_kv]
})
.into_iter()
.flatten();
[kind_kv, kind_type_kv].into_iter().chain(maybe_roomid_kvs).flatten().flat_map(
move |(ev_type, handlers)| {
handlers.iter().map(move |wrap| {
let handle = EventHandlerHandle {
ev_kind,
ev_type,
room_id: room_id.map(ToOwned::to_owned),
handler_id: wrap.handler_id,
};
(handle, &*wrap.handler_fn)
})
},
)
}
pub fn remove(&mut self, handle: EventHandlerHandle) {
fn remove_entry<K: Ord>(
map: &mut BTreeMap<K, Vec<EventHandlerWrapper>>,
key: K,
handler_id: u64,
) {
if let btree_map::Entry::Occupied(mut o) = map.entry(key) {
let v = o.get_mut();
v.retain(|e| e.handler_id != handler_id);
if v.is_empty() {
o.remove();
}
}
}
let handler_id = handle.handler_id;
match Key::new(handle) {
Key::Kind(key) => {
remove_entry(&mut self.by_kind, key, handler_id);
}
Key::KindType(key) => {
remove_entry(&mut self.by_kind_type, key, handler_id);
}
Key::KindRoomId(key) => {
remove_entry(&mut self.by_kind_roomid, key, handler_id);
}
Key::KindTypeRoomId(key) => {
remove_entry(&mut self.by_kind_type_roomid, key, handler_id);
}
}
}
#[cfg(test)]
pub fn len(&self) -> usize {
self.by_kind_type.len() + self.by_kind_type_roomid.len()
}
}
enum Key {
Kind(HandlerKind),
KindType(KindTypeWrap),
KindRoomId(KindRoomId),
KindTypeRoomId(KindTypeRoomIdWrap),
}
impl Key {
fn new(handle: EventHandlerHandle) -> Self {
let EventHandlerHandle { ev_kind, ev_type, room_id, .. } = handle;
match (ev_type, room_id) {
(None, None) => Key::Kind(ev_kind),
(Some(ev_type), None) => Key::KindType(KindTypeWrap(KindType { ev_kind, ev_type })),
(None, Some(room_id)) => Key::KindRoomId(KindRoomId { ev_kind, room_id }),
(Some(ev_type), Some(room_id)) => {
let inner = KindTypeRoomId { ev_kind, ev_type, room_id };
Key::KindTypeRoomId(KindTypeRoomIdWrap(inner))
}
}
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
struct KindTypeWrap(KindType<'static>);
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
struct KindType<'a> {
ev_kind: HandlerKind,
ev_type: &'a str,
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
struct KindRoomId {
ev_kind: HandlerKind,
room_id: OwnedRoomId,
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
struct KindTypeRoomIdWrap(KindTypeRoomId<'static>);
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
struct KindTypeRoomId<'a> {
ev_kind: HandlerKind,
ev_type: &'a str,
room_id: OwnedRoomId,
}
impl<'a> Borrow<KindType<'a>> for KindTypeWrap {
fn borrow(&self) -> &KindType<'a> {
&self.0
}
}
impl<'a> Borrow<KindTypeRoomId<'a>> for KindTypeRoomIdWrap {
fn borrow(&self) -> &KindTypeRoomId<'a> {
&self.0
}
}