Skip to main content

matrix_sdk/event_cache/states/
selectors.rs

1// Copyright 2026 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
15//! This module contains the [`CacheState`] trait to select a specific cache
16//! state in the full [`State`].
17
18use std::collections::hash_map::Entry;
19
20use ruma::{OwnedEventId, OwnedRoomId};
21
22use super::{
23    super::EventCacheError, EventFocusedCacheKey, EventFocusedCacheState, PinnedEventsCacheState,
24    RoomEventCacheState, State, StateForRoom, ThreadEventCacheState,
25};
26
27/// Trait to select a specific state of a cache inside a [`State`].
28pub trait CacheState {
29    /// The type of the specific state of cache.
30    type Item;
31
32    /// Immutably select a specific state of a cache inside a [`State`].
33    fn select<'state>(&self, state: &'state State) -> Option<&'state Self::Item>;
34
35    /// Mutably select a specific state of a cache inside a [`State`].
36    fn select_mut<'state>(&self, state: &'state mut State) -> Option<&'state mut Self::Item>;
37
38    /// Insert a new [`Self::Item`] in [`State`].
39    ///
40    /// It returns `true` if it's been inserted, `false` otherwise, i.e. if the
41    /// place is occupied.
42    fn insert_once(&self, state: &mut State, cache_state: Self::Item) -> bool;
43}
44
45/// Select all states ([`RoomEventCacheState`], [`ThreadEventCacheState`],
46/// [`PinnedEventsCacheState`] and [`EventFocusedCacheState`]) for a particular
47/// room in [`State`].
48#[derive(Debug)]
49pub(in super::super) struct AllStatesSelector(OwnedRoomId);
50
51impl AllStatesSelector {
52    pub fn new(room_id: OwnedRoomId) -> Self {
53        Self(room_id)
54    }
55}
56
57impl CacheState for AllStatesSelector {
58    type Item = StateForRoom;
59
60    fn select<'state>(&self, state: &'state State) -> Option<&'state Self::Item> {
61        state.by_room.get(&self.0)
62    }
63
64    fn select_mut<'state>(&self, state: &'state mut State) -> Option<&'state mut Self::Item> {
65        state.by_room.get_mut(&self.0)
66    }
67
68    fn insert_once(&self, _state: &mut State, _cache_state: Self::Item) -> bool {
69        false
70    }
71}
72
73impl From<&AllStatesSelector> for EventCacheError {
74    fn from(value: &AllStatesSelector) -> Self {
75        Self::RoomNotFound { room_id: value.0.clone() }
76    }
77}
78
79/// Select a [`RoomEventCacheState`] in [`State`].
80#[derive(Debug)]
81pub struct RoomStateSelector(OwnedRoomId);
82
83impl RoomStateSelector {
84    pub fn new(room_id: OwnedRoomId) -> Self {
85        Self(room_id)
86    }
87}
88
89impl CacheState for RoomStateSelector {
90    type Item = RoomEventCacheState;
91
92    fn select<'state>(&self, state: &'state State) -> Option<&'state Self::Item> {
93        state.by_room.get(&self.0).and_then(|state_for_room| state_for_room.room.as_ref())
94    }
95
96    fn select_mut<'state>(&self, state: &'state mut State) -> Option<&'state mut Self::Item> {
97        state.by_room.get_mut(&self.0).and_then(|state_for_room| state_for_room.room.as_mut())
98    }
99
100    fn insert_once(&self, state: &mut State, cache_state: Self::Item) -> bool {
101        let room = &mut state.by_room.entry(self.0.clone()).or_default().room;
102
103        match room {
104            Some(_) => false,
105            None => {
106                room.replace(cache_state);
107
108                true
109            }
110        }
111    }
112}
113
114impl From<&RoomStateSelector> for EventCacheError {
115    fn from(value: &RoomStateSelector) -> Self {
116        Self::RoomNotFound { room_id: value.0.clone() }
117    }
118}
119
120/// Select a [`ThreadEventCacheState`] in [`State`].
121#[derive(Debug)]
122pub struct ThreadStateSelector(OwnedRoomId, OwnedEventId);
123
124impl ThreadStateSelector {
125    pub fn new(room_id: OwnedRoomId, thread_id: OwnedEventId) -> Self {
126        Self(room_id, thread_id)
127    }
128}
129
130impl CacheState for ThreadStateSelector {
131    type Item = ThreadEventCacheState;
132
133    fn select<'state>(&self, state: &'state State) -> Option<&'state Self::Item> {
134        state.by_room.get(&self.0).and_then(|state_for_room| state_for_room.threads.get(&self.1))
135    }
136
137    fn select_mut<'state>(&self, state: &'state mut State) -> Option<&'state mut Self::Item> {
138        state
139            .by_room
140            .get_mut(&self.0)
141            .and_then(|state_for_room| state_for_room.threads.get_mut(&self.1))
142    }
143
144    fn insert_once(&self, state: &mut State, cache_state: Self::Item) -> bool {
145        let threads = &mut state.by_room.entry(self.0.clone()).or_default().threads;
146
147        match threads.entry(self.1.clone()) {
148            Entry::Occupied(_) => false,
149            Entry::Vacant(entry) => {
150                entry.insert(cache_state);
151
152                true
153            }
154        }
155    }
156}
157
158impl From<&ThreadStateSelector> for EventCacheError {
159    fn from(value: &ThreadStateSelector) -> Self {
160        Self::ThreadNotFound { room_id: value.0.clone(), thread_id: value.1.clone() }
161    }
162}
163
164/// Select a [`PinnedEventCacheState`] in [`State`].
165#[derive(Debug)]
166pub struct PinnedEventsStateSelector(OwnedRoomId);
167
168impl PinnedEventsStateSelector {
169    pub fn new(room_id: OwnedRoomId) -> Self {
170        Self(room_id)
171    }
172}
173
174impl CacheState for PinnedEventsStateSelector {
175    type Item = PinnedEventsCacheState;
176
177    fn select<'state>(&self, state: &'state State) -> Option<&'state Self::Item> {
178        state.by_room.get(&self.0).and_then(|state_for_room| state_for_room.pinned_events.as_ref())
179    }
180
181    fn select_mut<'state>(&self, state: &'state mut State) -> Option<&'state mut Self::Item> {
182        state
183            .by_room
184            .get_mut(&self.0)
185            .and_then(|state_for_room| state_for_room.pinned_events.as_mut())
186    }
187
188    fn insert_once(&self, state: &mut State, cache_state: Self::Item) -> bool {
189        let pinned_events = &mut state.by_room.entry(self.0.clone()).or_default().pinned_events;
190
191        match pinned_events {
192            Some(_) => false,
193            None => {
194                pinned_events.replace(cache_state);
195
196                true
197            }
198        }
199    }
200}
201
202impl From<&PinnedEventsStateSelector> for EventCacheError {
203    fn from(value: &PinnedEventsStateSelector) -> Self {
204        Self::PinnedEventsNotFound { room_id: value.0.clone() }
205    }
206}
207
208/// Select a [`EventFocusedCacheState`] in [`State`].
209#[derive(Debug)]
210pub struct EventFocusedStateSelector(OwnedRoomId, EventFocusedCacheKey);
211
212impl EventFocusedStateSelector {
213    pub fn new(room_id: OwnedRoomId, key: EventFocusedCacheKey) -> Self {
214        Self(room_id, key)
215    }
216}
217
218impl CacheState for EventFocusedStateSelector {
219    type Item = EventFocusedCacheState;
220
221    fn select<'state>(&self, state: &'state State) -> Option<&'state Self::Item> {
222        state
223            .by_room
224            .get(&self.0)
225            .and_then(|state_for_room| state_for_room.event_focused.get(&self.1))
226    }
227
228    fn select_mut<'state>(&self, state: &'state mut State) -> Option<&'state mut Self::Item> {
229        state
230            .by_room
231            .get_mut(&self.0)
232            .and_then(|state_for_room| state_for_room.event_focused.get_mut(&self.1))
233    }
234
235    fn insert_once(&self, state: &mut State, cache_state: Self::Item) -> bool {
236        let event_focused = &mut state.by_room.entry(self.0.clone()).or_default().event_focused;
237
238        match event_focused.entry(self.1.clone()) {
239            Entry::Occupied(_) => false,
240            Entry::Vacant(entry) => {
241                entry.insert(cache_state);
242
243                true
244            }
245        }
246    }
247}
248
249impl From<&EventFocusedStateSelector> for EventCacheError {
250    fn from(value: &EventFocusedStateSelector) -> Self {
251        Self::EventFocusedNotFound { room_id: value.0.clone(), event_focused_id: value.1.clone() }
252    }
253}