1212// See the License for that specific language governing permissions and
1313// limitations under the License.
1414
15+ use std:: pin:: Pin ;
16+
17+ use futures_util:: { Stream , StreamExt as _} ;
1518use matrix_sdk:: {
16- deserialized_responses:: TimelineEvent ,
17- message_search:: {
18- GlobalSearchIterator as SdkGlobalSearchIterator ,
19- RoomSearchIterator as SdkRoomSearchIterator , SearchError as SdkSearchError ,
20- } ,
19+ deserialized_responses:: TimelineEvent , message_search:: SearchError as SdkSearchError ,
2120} ;
2221use matrix_sdk_ui:: timeline:: TimelineDetails ;
22+ use ruma:: OwnedRoomId ;
2323use tokio:: sync:: Mutex ;
2424
2525use crate :: {
@@ -47,6 +47,13 @@ impl From<SdkSearchError> for SearchError {
4747 }
4848}
4949
50+ /// A boxed stream of the [`TimelineEvent`]s matching a single-room search.
51+ type RoomEventStream = Pin < Box < dyn Stream < Item = Result < TimelineEvent , SdkSearchError > > + Send > > ;
52+
53+ /// A boxed stream of the `(room_id, event)`s matching a global search.
54+ type GlobalEventStream =
55+ Pin < Box < dyn Stream < Item = Result < ( OwnedRoomId , TimelineEvent ) , SdkSearchError > > + Send > > ;
56+
5057#[ matrix_sdk_ffi_macros:: export]
5158impl Room {
5259 /// Search for messages in this room matching the given query, returning an
@@ -55,28 +62,40 @@ impl Room {
5562 pub fn search_messages ( & self , query : String , num_results_per_batch : u32 ) -> RoomSearchIterator {
5663 RoomSearchIterator {
5764 sdk_room : ( * self . inner ) . clone ( ) ,
58- inner : Mutex :: new ( self . inner . search_messages ( query, num_results_per_batch as usize ) ) ,
65+ stream : Mutex :: new ( Box :: pin ( self . inner . search_messages_events ( query) ) ) ,
66+ num_results_per_batch : num_results_per_batch as usize ,
5967 }
6068 }
6169}
6270
6371#[ derive( uniffi:: Object ) ]
6472pub struct RoomSearchIterator {
6573 sdk_room : matrix_sdk:: room:: Room ,
66- inner : Mutex < SdkRoomSearchIterator > ,
74+ stream : Mutex < RoomEventStream > ,
75+ num_results_per_batch : usize ,
6776}
6877
6978#[ matrix_sdk_ffi_macros:: export]
7079impl RoomSearchIterator {
7180 /// Return a list of events for the next batch of search results, or `None`
7281 /// if there are no more results.
7382 pub async fn next_events ( & self ) -> Result < Option < Vec < RoomSearchResult > > , SearchError > {
74- let Some ( events) = self . inner . lock ( ) . await . next_events ( ) . await ? else {
83+ let mut stream = self . stream . lock ( ) . await ;
84+
85+ let mut events = Vec :: with_capacity ( self . num_results_per_batch ) ;
86+ while events. len ( ) < self . num_results_per_batch {
87+ let Some ( event) = stream. next ( ) . await else {
88+ break ;
89+ } ;
90+ events. push ( event?) ;
91+ }
92+
93+ if events. is_empty ( ) {
7594 return Ok ( None ) ;
76- } ;
95+ }
96+ drop ( stream) ;
7797
7898 let mut results = Vec :: with_capacity ( events. len ( ) ) ;
79-
8099 for event in events {
81100 if let Some ( result) = RoomSearchResult :: from ( & self . sdk_room , event) . await {
82101 results. push ( result) ;
@@ -142,15 +161,19 @@ impl Client {
142161 num_results_per_batch : u32 ,
143162 ) -> Result < GlobalSearchIterator , ClientError > {
144163 let sdk_client = ( * self . inner ) . clone ( ) ;
145- let mut search = sdk_client. search_messages ( query, num_results_per_batch as usize ) ;
164+ let mut builder = sdk_client. search_messages ( query) ;
146165
147166 match filter {
148167 SearchRoomFilter :: Rooms => { }
149- SearchRoomFilter :: Dms => search = search . only_dm_rooms ( ) . await ?,
150- SearchRoomFilter :: NonDms => search = search . no_dms ( ) . await ?,
168+ SearchRoomFilter :: Dms => builder = builder . only_dm_rooms ( ) . await ?,
169+ SearchRoomFilter :: NonDms => builder = builder . no_dms ( ) . await ?,
151170 }
152171
153- Ok ( GlobalSearchIterator { sdk_client, inner : Mutex :: new ( search. build ( ) ) } )
172+ Ok ( GlobalSearchIterator {
173+ sdk_client,
174+ stream : Mutex :: new ( Box :: pin ( builder. build_events ( ) ) ) ,
175+ num_results_per_batch : num_results_per_batch as usize ,
176+ } )
154177 }
155178}
156179
@@ -163,21 +186,32 @@ pub struct GlobalSearchResult {
163186#[ derive( uniffi:: Object ) ]
164187pub struct GlobalSearchIterator {
165188 sdk_client : matrix_sdk:: Client ,
166- inner : Mutex < SdkGlobalSearchIterator > ,
189+ stream : Mutex < GlobalEventStream > ,
190+ num_results_per_batch : usize ,
167191}
168192
169193#[ matrix_sdk_ffi_macros:: export]
170194impl GlobalSearchIterator {
171195 /// Return a list of events for the next batch of search results, or `None`
172196 /// if there are no more results.
173197 pub async fn next_events ( & self ) -> Result < Option < Vec < GlobalSearchResult > > , SearchError > {
174- let Some ( events) = self . inner . lock ( ) . await . next_events ( ) . await ? else {
175- return Ok ( None ) ;
176- } ;
198+ let mut stream = self . stream . lock ( ) . await ;
177199
178- let mut results = Vec :: with_capacity ( events. len ( ) ) ;
200+ let mut batch = Vec :: with_capacity ( self . num_results_per_batch ) ;
201+ while batch. len ( ) < self . num_results_per_batch {
202+ let Some ( item) = stream. next ( ) . await else {
203+ break ;
204+ } ;
205+ batch. push ( item?) ;
206+ }
207+
208+ if batch. is_empty ( ) {
209+ return Ok ( None ) ;
210+ }
211+ drop ( stream) ;
179212
180- for ( room_id, event) in events {
213+ let mut results = Vec :: with_capacity ( batch. len ( ) ) ;
214+ for ( room_id, event) in batch {
181215 let Some ( room) = self . sdk_client . get_room ( & room_id) else {
182216 continue ;
183217 } ;
0 commit comments