matrix_sdk/event_handler/
maps.rs

1// Copyright 2022 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::{
16    borrow::Borrow,
17    collections::{btree_map, BTreeMap},
18};
19
20use ruma::{OwnedRoomId, RoomId};
21
22use super::{EventHandlerFn, EventHandlerHandle, EventHandlerWrapper, HandlerKind};
23
24#[derive(Default)]
25pub(super) struct EventHandlerMaps {
26    by_kind: BTreeMap<HandlerKind, Vec<EventHandlerWrapper>>,
27    by_kind_type: BTreeMap<KindTypeWrap, Vec<EventHandlerWrapper>>,
28    by_kind_roomid: BTreeMap<KindRoomId, Vec<EventHandlerWrapper>>,
29    by_kind_type_roomid: BTreeMap<KindTypeRoomIdWrap, Vec<EventHandlerWrapper>>,
30}
31
32impl EventHandlerMaps {
33    pub fn add(&mut self, handle: EventHandlerHandle, handler_fn: Box<EventHandlerFn>) {
34        let wrapper = EventHandlerWrapper { handler_id: handle.handler_id, handler_fn };
35
36        match Key::new(handle) {
37            Key::Kind(key) => {
38                self.by_kind.entry(key).or_default().push(wrapper);
39            }
40            Key::KindType(key) => {
41                self.by_kind_type.entry(key).or_default().push(wrapper);
42            }
43            Key::KindRoomId(key) => {
44                self.by_kind_roomid.entry(key).or_default().push(wrapper);
45            }
46            Key::KindTypeRoomId(key) => {
47                self.by_kind_type_roomid.entry(key).or_default().push(wrapper)
48            }
49        }
50    }
51
52    pub fn get_handlers<'a>(
53        &'a self,
54        ev_kind: HandlerKind,
55        ev_type: &str,
56        room_id: Option<&'a RoomId>,
57    ) -> impl Iterator<Item = (EventHandlerHandle, &'a EventHandlerFn)> + 'a {
58        // Use get_key_value instead of just get to be able to access the event_type
59        // from the BTreeMap key as &'static str, required for EventHandlerHandle.
60        let kind_kv = self.by_kind.get_key_value(&ev_kind).map(|(_, handlers)| (None, handlers));
61        let kind_type_kv = self
62            .by_kind_type
63            .get_key_value(&KindType { ev_kind, ev_type })
64            .map(|(key, handlers)| (Some(key.0.ev_type), handlers));
65        let maybe_roomid_kvs = room_id
66            .map(|r_id| {
67                let room_id = r_id.to_owned();
68                let kind_roomid_kv = self
69                    .by_kind_roomid
70                    .get_key_value(&KindRoomId { ev_kind, room_id })
71                    .map(|(_, handlers)| (None, handlers));
72
73                let room_id = r_id.to_owned();
74                let kind_type_roomid_kv = self
75                    .by_kind_type_roomid
76                    .get_key_value(&KindTypeRoomId { ev_kind, ev_type, room_id })
77                    .map(|(key, handlers)| (Some(key.0.ev_type), handlers));
78
79                [kind_roomid_kv, kind_type_roomid_kv]
80            })
81            .into_iter()
82            .flatten();
83
84        [kind_kv, kind_type_kv].into_iter().chain(maybe_roomid_kvs).flatten().flat_map(
85            move |(ev_type, handlers)| {
86                handlers.iter().map(move |wrap| {
87                    let handle = EventHandlerHandle {
88                        ev_kind,
89                        ev_type,
90                        room_id: room_id.map(ToOwned::to_owned),
91                        handler_id: wrap.handler_id,
92                    };
93
94                    (handle, &*wrap.handler_fn)
95                })
96            },
97        )
98    }
99
100    pub fn remove(&mut self, handle: EventHandlerHandle) {
101        // Generic closure would be a lot nicer
102        fn remove_entry<K: Ord>(
103            map: &mut BTreeMap<K, Vec<EventHandlerWrapper>>,
104            key: K,
105            handler_id: u64,
106        ) {
107            if let btree_map::Entry::Occupied(mut o) = map.entry(key) {
108                let v = o.get_mut();
109                v.retain(|e| e.handler_id != handler_id);
110
111                if v.is_empty() {
112                    o.remove();
113                }
114            }
115        }
116
117        let handler_id = handle.handler_id;
118        match Key::new(handle) {
119            Key::Kind(key) => {
120                remove_entry(&mut self.by_kind, key, handler_id);
121            }
122            Key::KindType(key) => {
123                remove_entry(&mut self.by_kind_type, key, handler_id);
124            }
125            Key::KindRoomId(key) => {
126                remove_entry(&mut self.by_kind_roomid, key, handler_id);
127            }
128            Key::KindTypeRoomId(key) => {
129                remove_entry(&mut self.by_kind_type_roomid, key, handler_id);
130            }
131        }
132    }
133
134    #[cfg(test)]
135    pub fn len(&self) -> usize {
136        self.by_kind_type.len() + self.by_kind_type_roomid.len()
137    }
138}
139
140enum Key {
141    Kind(HandlerKind),
142    KindType(KindTypeWrap),
143    KindRoomId(KindRoomId),
144    KindTypeRoomId(KindTypeRoomIdWrap),
145}
146
147impl Key {
148    fn new(handle: EventHandlerHandle) -> Self {
149        let EventHandlerHandle { ev_kind, ev_type, room_id, .. } = handle;
150        match (ev_type, room_id) {
151            (None, None) => Key::Kind(ev_kind),
152            (Some(ev_type), None) => Key::KindType(KindTypeWrap(KindType { ev_kind, ev_type })),
153            (None, Some(room_id)) => Key::KindRoomId(KindRoomId { ev_kind, room_id }),
154            (Some(ev_type), Some(room_id)) => {
155                let inner = KindTypeRoomId { ev_kind, ev_type, room_id };
156                Key::KindTypeRoomId(KindTypeRoomIdWrap(inner))
157            }
158        }
159    }
160}
161
162#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
163struct KindTypeWrap(KindType<'static>);
164
165#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
166struct KindType<'a> {
167    ev_kind: HandlerKind,
168    ev_type: &'a str,
169}
170
171#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
172struct KindRoomId {
173    ev_kind: HandlerKind,
174    room_id: OwnedRoomId,
175}
176
177#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
178struct KindTypeRoomIdWrap(KindTypeRoomId<'static>);
179
180#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
181struct KindTypeRoomId<'a> {
182    ev_kind: HandlerKind,
183    ev_type: &'a str,
184    room_id: OwnedRoomId,
185}
186
187// These lifetime-generic impls are what makes it possible to obtain a
188// &'static str event type from get_key_value in call_event_handlers.
189impl<'a> Borrow<KindType<'a>> for KindTypeWrap {
190    fn borrow(&self) -> &KindType<'a> {
191        &self.0
192    }
193}
194
195impl<'a> Borrow<KindTypeRoomId<'a>> for KindTypeRoomIdWrap {
196    fn borrow(&self) -> &KindTypeRoomId<'a> {
197        &self.0
198    }
199}