fix: membership deserializing
This commit is contained in:
		
							parent
							
								
									51aa6448bc
								
							
						
					
					
						commit
						84f4ce73e5
					
				
					 9 changed files with 74 additions and 63 deletions
				
			
		
							
								
								
									
										14
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										14
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							|  | @ -877,9 +877,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "libc" | name = "libc" | ||||||
| version = "0.2.92" | version = "0.2.93" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" | checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "linked-hash-map" | name = "linked-hash-map" | ||||||
|  | @ -2125,7 +2125,7 @@ checksum = "3015a7d0a5fd5105c91c3710d42f9ccf0abfb287d62206484dcc67f9569a6483" | ||||||
| [[package]] | [[package]] | ||||||
| name = "state-res" | name = "state-res" | ||||||
| version = "0.1.0" | version = "0.1.0" | ||||||
| source = "git+https://github.com/ruma/state-res?rev=af450d0fe2b0e1c890284d0bc3b9d6d4008ac475#af450d0fe2b0e1c890284d0bc3b9d6d4008ac475" | source = "git+https://github.com/timokoesters/state-res?rev=1ec42ea2fc0b0728bf027a5899839ad94bb3091b#1ec42ea2fc0b0728bf027a5899839ad94bb3091b" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "itertools", |  "itertools", | ||||||
|  "log", |  "log", | ||||||
|  | @ -2578,9 +2578,9 @@ dependencies = [ | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "unicode-bidi" | name = "unicode-bidi" | ||||||
| version = "0.3.4" | version = "0.3.5" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" | checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "matches", |  "matches", | ||||||
| ] | ] | ||||||
|  | @ -2760,9 +2760,9 @@ checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "wildmatch" | name = "wildmatch" | ||||||
| version = "2.0.0" | version = "2.1.0" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "07ae7ce410f81ba679081aac1d4874f3b1c328535b630209aa5b4cdaaf895e20" | checksum = "d6c48bd20df7e4ced539c12f570f937c6b4884928a87fee70a479d72f031d4e0" | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "winapi" | name = "winapi" | ||||||
|  |  | ||||||
|  | @ -23,11 +23,8 @@ ruma = { git = "https://github.com/ruma/ruma", rev = "a310ccc318a4eb51062923d570 | ||||||
| #ruma = { path = "../ruma/ruma", features = ["unstable-exhaustive-types", "rand", "client-api", "federation-api", "push-gateway-api", "unstable-pre-spec", "unstable-synapse-quirks"] } | #ruma = { path = "../ruma/ruma", features = ["unstable-exhaustive-types", "rand", "client-api", "federation-api", "push-gateway-api", "unstable-pre-spec", "unstable-synapse-quirks"] } | ||||||
| 
 | 
 | ||||||
| # Used when doing state resolution | # Used when doing state resolution | ||||||
| state-res = { git = "https://github.com/ruma/state-res", rev = "af450d0fe2b0e1c890284d0bc3b9d6d4008ac475", features = ["unstable-pre-spec"] } | state-res = { git = "https://github.com/timokoesters/state-res", rev = "1ec42ea2fc0b0728bf027a5899839ad94bb3091b", features = ["unstable-pre-spec"] } | ||||||
| # TODO: remove the gen-eventid feature | #state-res = { path = "../state-res", features = ["unstable-pre-spec"] } | ||||||
| #state-res = { git = "https://github.com/ruma/state-res", branch = "main", features = ["unstable-pre-spec", "gen-eventid"] } |  | ||||||
| #state-res = { git = "https://github.com/ruma/state-res", rev = "1621a491a9e867a1ad4dff9f2f92b0c1e2d44aa0", features = ["unstable-pre-spec", "gen-eventid"] } |  | ||||||
| #state-res = { path = "../state-res", features = ["unstable-pre-spec", "gen-eventid"] } |  | ||||||
| 
 | 
 | ||||||
| # Used for long polling and federation sender, should be the same as rocket::tokio | # Used for long polling and federation sender, should be the same as rocket::tokio | ||||||
| tokio = "1.2.0" | tokio = "1.2.0" | ||||||
|  |  | ||||||
|  | @ -604,12 +604,16 @@ async fn join_room_by_id_helper( | ||||||
|                     db.rooms.update_membership( |                     db.rooms.update_membership( | ||||||
|                         &pdu.room_id, |                         &pdu.room_id, | ||||||
|                         &target_user_id, |                         &target_user_id, | ||||||
|                         serde_json::from_value::<member::MemberEventContent>(pdu.content.clone()) |                         serde_json::from_value::<member::MembershipState>( | ||||||
|                             .map_err(|_| { |                             pdu.content | ||||||
|                             Error::BadRequest( |                                 .get("membership") | ||||||
|                                 ErrorKind::InvalidParam, |                                 .ok_or_else(|| { | ||||||
|                                 "Invalid member event content.", |                                     Error::BadServerResponse("Invalid member event content") | ||||||
|                             ) |                                 })? | ||||||
|  |                                 .clone(), | ||||||
|  |                         ) | ||||||
|  |                         .map_err(|_| { | ||||||
|  |                             Error::BadServerResponse("Invalid membership state content.") | ||||||
|                         })?, |                         })?, | ||||||
|                         &pdu.sender, |                         &pdu.sender, | ||||||
|                         &db.account_data, |                         &db.account_data, | ||||||
|  |  | ||||||
|  | @ -91,10 +91,24 @@ pub async fn create_room_route( | ||||||
|     )?; |     )?; | ||||||
| 
 | 
 | ||||||
|     // 3. Power levels
 |     // 3. Power levels
 | ||||||
|  | 
 | ||||||
|  |     // Figure out preset. We need it for preset specific events
 | ||||||
|  |     let preset = body | ||||||
|  |         .preset | ||||||
|  |         .clone() | ||||||
|  |         .unwrap_or_else(|| match &body.visibility { | ||||||
|  |             room::Visibility::Private => create_room::RoomPreset::PrivateChat, | ||||||
|  |             room::Visibility::Public => create_room::RoomPreset::PublicChat, | ||||||
|  |             room::Visibility::_Custom(_) => create_room::RoomPreset::PrivateChat, // Room visibility should not be custom
 | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|     let mut users = BTreeMap::new(); |     let mut users = BTreeMap::new(); | ||||||
|     users.insert(sender_user.clone(), 100.into()); |     users.insert(sender_user.clone(), 100.into()); | ||||||
|     for invite_ in &body.invite { | 
 | ||||||
|         users.insert(invite_.clone(), 100.into()); |     if preset == create_room::RoomPreset::TrustedPrivateChat { | ||||||
|  |         for invite_ in &body.invite { | ||||||
|  |             users.insert(invite_.clone(), 100.into()); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     let power_levels_content = if let Some(power_levels) = &body.power_level_content_override { |     let power_levels_content = if let Some(power_levels) = &body.power_level_content_override { | ||||||
|  | @ -133,16 +147,6 @@ pub async fn create_room_route( | ||||||
| 
 | 
 | ||||||
|     // 4. Events set by preset
 |     // 4. Events set by preset
 | ||||||
| 
 | 
 | ||||||
|     // Figure out preset. We need it for preset specific events
 |  | ||||||
|     let preset = body |  | ||||||
|         .preset |  | ||||||
|         .clone() |  | ||||||
|         .unwrap_or_else(|| match &body.visibility { |  | ||||||
|             room::Visibility::Private => create_room::RoomPreset::PrivateChat, |  | ||||||
|             room::Visibility::Public => create_room::RoomPreset::PublicChat, |  | ||||||
|             room::Visibility::_Custom(s) => create_room::RoomPreset::_Custom(s.into()), |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|     // 4.1 Join Rules
 |     // 4.1 Join Rules
 | ||||||
|     db.rooms.build_and_append_pdu( |     db.rooms.build_and_append_pdu( | ||||||
|         PduBuilder { |         PduBuilder { | ||||||
|  |  | ||||||
|  | @ -108,7 +108,7 @@ impl Database { | ||||||
|     pub async fn load_or_create(config: Config) -> Result<Self> { |     pub async fn load_or_create(config: Config) -> Result<Self> { | ||||||
|         let db = sled::Config::default() |         let db = sled::Config::default() | ||||||
|             .path(&config.database_path) |             .path(&config.database_path) | ||||||
|             .cache_capacity(config.cache_capacity as u64) |             .cache_capacity(config.cache_capacity as usize) | ||||||
|             .use_compression(true) |             .use_compression(true) | ||||||
|             .open()?; |             .open()?; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -196,7 +196,7 @@ pub async fn send_push_notice( | ||||||
|     let mut notify = None; |     let mut notify = None; | ||||||
|     let mut tweaks = Vec::new(); |     let mut tweaks = Vec::new(); | ||||||
| 
 | 
 | ||||||
|     for action in ruleset.get_actions(&pdu.to_sync_state_event(), &ctx) { |     for action in ruleset.get_actions(&pdu.to_sync_room_event(), &ctx) { | ||||||
|         let n = match action { |         let n = match action { | ||||||
|             Action::DontNotify => false, |             Action::DontNotify => false, | ||||||
|             // TODO: Implement proper support for coalesce
 |             // TODO: Implement proper support for coalesce
 | ||||||
|  |  | ||||||
|  | @ -465,7 +465,7 @@ impl Rooms { | ||||||
|     /// Returns the pdu.
 |     /// Returns the pdu.
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// This does __NOT__ check the outliers `Tree`.
 |     /// This does __NOT__ check the outliers `Tree`.
 | ||||||
|     pub fn get_pdu_from_id(&self, pdu_id: &IVec) -> Result<Option<PduEvent>> { |     pub fn get_pdu_from_id(&self, pdu_id: &[u8]) -> Result<Option<PduEvent>> { | ||||||
|         self.pduid_pdu.get(pdu_id)?.map_or(Ok(None), |pdu| { |         self.pduid_pdu.get(pdu_id)?.map_or(Ok(None), |pdu| { | ||||||
|             Ok(Some( |             Ok(Some( | ||||||
|                 serde_json::from_slice(&pdu) |                 serde_json::from_slice(&pdu) | ||||||
|  | @ -671,11 +671,21 @@ impl Rooms { | ||||||
|                     self.update_membership( |                     self.update_membership( | ||||||
|                         &pdu.room_id, |                         &pdu.room_id, | ||||||
|                         &target_user_id, |                         &target_user_id, | ||||||
|                         serde_json::from_value::<member::MemberEventContent>(pdu.content.clone()) |                         serde_json::from_value::<member::MembershipState>( | ||||||
|                             .map_err(|_| { |                             pdu.content | ||||||
|  |                                 .get("membership") | ||||||
|  |                                 .ok_or_else(|| { | ||||||
|  |                                     Error::BadRequest( | ||||||
|  |                                         ErrorKind::InvalidParam, | ||||||
|  |                                         "Invalid member event content", | ||||||
|  |                                     ) | ||||||
|  |                                 })? | ||||||
|  |                                 .clone(), | ||||||
|  |                         ) | ||||||
|  |                         .map_err(|_| { | ||||||
|                             Error::BadRequest( |                             Error::BadRequest( | ||||||
|                                 ErrorKind::InvalidParam, |                                 ErrorKind::InvalidParam, | ||||||
|                                 "Invalid member event content.", |                                 "Invalid membership state content.", | ||||||
|                             ) |                             ) | ||||||
|                         })?, |                         })?, | ||||||
|                         &pdu.sender, |                         &pdu.sender, | ||||||
|  | @ -895,19 +905,14 @@ impl Rooms { | ||||||
|                 .scan_prefix(&old_shortstatehash) |                 .scan_prefix(&old_shortstatehash) | ||||||
|                 .filter_map(|pdu| pdu.map_err(|e| error!("{}", e)).ok()) |                 .filter_map(|pdu| pdu.map_err(|e| error!("{}", e)).ok()) | ||||||
|                 // Chop the old_shortstatehash out leaving behind the short state key
 |                 // Chop the old_shortstatehash out leaving behind the short state key
 | ||||||
|                 .map(|(k, v)| { |                 .map(|(k, v)| (k[old_shortstatehash.len()..].to_vec(), v)) | ||||||
|                     ( |                 .collect::<HashMap<Vec<u8>, IVec>>() | ||||||
|                         k.subslice(old_shortstatehash.len(), k.len() - old_shortstatehash.len()), |  | ||||||
|                         v, |  | ||||||
|                     ) |  | ||||||
|                 }) |  | ||||||
|                 .collect::<HashMap<IVec, IVec>>() |  | ||||||
|         } else { |         } else { | ||||||
|             HashMap::new() |             HashMap::new() | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         if let Some(state_key) = &new_pdu.state_key { |         if let Some(state_key) = &new_pdu.state_key { | ||||||
|             let mut new_state: HashMap<IVec, IVec> = old_state; |             let mut new_state: HashMap<Vec<u8>, IVec> = old_state; | ||||||
| 
 | 
 | ||||||
|             let mut new_state_key = new_pdu.kind.as_ref().as_bytes().to_vec(); |             let mut new_state_key = new_pdu.kind.as_ref().as_bytes().to_vec(); | ||||||
|             new_state_key.push(0xff); |             new_state_key.push(0xff); | ||||||
|  | @ -935,7 +940,7 @@ impl Rooms { | ||||||
|                 } |                 } | ||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|             new_state.insert(shortstatekey.into(), shorteventid.into()); |             new_state.insert(shortstatekey, shorteventid.into()); | ||||||
| 
 | 
 | ||||||
|             let new_state_hash = self.calculate_hash( |             let new_state_hash = self.calculate_hash( | ||||||
|                 &new_state |                 &new_state | ||||||
|  | @ -1377,13 +1382,11 @@ impl Rooms { | ||||||
|         &self, |         &self, | ||||||
|         room_id: &RoomId, |         room_id: &RoomId, | ||||||
|         user_id: &UserId, |         user_id: &UserId, | ||||||
|         member_content: member::MemberEventContent, |         membership: member::MembershipState, | ||||||
|         sender: &UserId, |         sender: &UserId, | ||||||
|         account_data: &super::account_data::AccountData, |         account_data: &super::account_data::AccountData, | ||||||
|         globals: &super::globals::Globals, |         globals: &super::globals::Globals, | ||||||
|     ) -> Result<()> { |     ) -> Result<()> { | ||||||
|         let membership = member_content.membership; |  | ||||||
| 
 |  | ||||||
|         let mut roomserver_id = room_id.as_bytes().to_vec(); |         let mut roomserver_id = room_id.as_bytes().to_vec(); | ||||||
|         roomserver_id.push(0xff); |         roomserver_id.push(0xff); | ||||||
|         roomserver_id.extend_from_slice(user_id.server_name().as_bytes()); |         roomserver_id.extend_from_slice(user_id.server_name().as_bytes()); | ||||||
|  | @ -1633,7 +1636,7 @@ impl Rooms { | ||||||
|         &'a self, |         &'a self, | ||||||
|         room_id: &RoomId, |         room_id: &RoomId, | ||||||
|         search_string: &str, |         search_string: &str, | ||||||
|     ) -> Result<(impl Iterator<Item = IVec> + 'a, Vec<String>)> { |     ) -> Result<(impl Iterator<Item = Vec<u8>> + 'a, Vec<String>)> { | ||||||
|         let mut prefix = room_id.as_bytes().to_vec(); |         let mut prefix = room_id.as_bytes().to_vec(); | ||||||
|         prefix.push(0xff); |         prefix.push(0xff); | ||||||
| 
 | 
 | ||||||
|  | @ -1661,7 +1664,7 @@ impl Rooms { | ||||||
|                         .0 |                         .0 | ||||||
|                         + 1; // +1 because the pdu id starts AFTER the separator
 |                         + 1; // +1 because the pdu id starts AFTER the separator
 | ||||||
| 
 | 
 | ||||||
|                     let pdu_id = key.subslice(pduid_index, key.len() - pduid_index); |                     let pdu_id = key[pduid_index..].to_vec(); | ||||||
| 
 | 
 | ||||||
|                     Ok::<_, Error>(pdu_id) |                     Ok::<_, Error>(pdu_id) | ||||||
|                 }) |                 }) | ||||||
|  | @ -1700,7 +1703,7 @@ impl Rooms { | ||||||
|                         .0 |                         .0 | ||||||
|                         + 1; // +1 because the room id starts AFTER the separator
 |                         + 1; // +1 because the room id starts AFTER the separator
 | ||||||
| 
 | 
 | ||||||
|                     let room_id = key.subslice(roomid_index, key.len() - roomid_index); |                     let room_id = key[roomid_index..].to_vec(); | ||||||
| 
 | 
 | ||||||
|                     Ok::<_, Error>(room_id) |                     Ok::<_, Error>(room_id) | ||||||
|                 }) |                 }) | ||||||
|  |  | ||||||
|  | @ -47,7 +47,7 @@ impl Sending { | ||||||
|             let mut futures = FuturesUnordered::new(); |             let mut futures = FuturesUnordered::new(); | ||||||
| 
 | 
 | ||||||
|             // Retry requests we could not finish yet
 |             // Retry requests we could not finish yet
 | ||||||
|             let mut current_transactions = HashMap::<OutgoingKind, Vec<IVec>>::new(); |             let mut current_transactions = HashMap::<OutgoingKind, Vec<Vec<u8>>>::new(); | ||||||
| 
 | 
 | ||||||
|             for (key, outgoing_kind, pdu) in servercurrentpdus |             for (key, outgoing_kind, pdu) in servercurrentpdus | ||||||
|                 .iter() |                 .iter() | ||||||
|  | @ -55,7 +55,7 @@ impl Sending { | ||||||
|                 .filter_map(|(key, _)| { |                 .filter_map(|(key, _)| { | ||||||
|                     Self::parse_servercurrentpdus(&key) |                     Self::parse_servercurrentpdus(&key) | ||||||
|                         .ok() |                         .ok() | ||||||
|                         .map(|(k, p)| (key, k, p)) |                         .map(|(k, p)| (key, k, p.to_vec())) | ||||||
|                 }) |                 }) | ||||||
|             { |             { | ||||||
|                 if pdu.is_empty() { |                 if pdu.is_empty() { | ||||||
|  | @ -150,7 +150,7 @@ impl Sending { | ||||||
|                                     .keys() |                                     .keys() | ||||||
|                                     .filter_map(|r| r.ok()) |                                     .filter_map(|r| r.ok()) | ||||||
|                                     .map(|k| { |                                     .map(|k| { | ||||||
|                                         k.subslice(prefix.len(), k.len() - prefix.len()) |                                         k[prefix.len()..].to_vec() | ||||||
|                                     }) |                                     }) | ||||||
|                                     .take(30) |                                     .take(30) | ||||||
|                                     .collect::<Vec<_>>(); |                                     .collect::<Vec<_>>(); | ||||||
|  | @ -211,7 +211,11 @@ impl Sending { | ||||||
|                         }; |                         }; | ||||||
|                     }, |                     }, | ||||||
|                     Some(event) = &mut subscriber => { |                     Some(event) = &mut subscriber => { | ||||||
|                         if let sled::Event::Insert { key, .. } = event { |                         for (_tree, key, value_opt) in &event { | ||||||
|  |                             if value_opt.is_none() { | ||||||
|  |                                 continue; | ||||||
|  |                             } | ||||||
|  | 
 | ||||||
|                             let servernamepduid = key.clone(); |                             let servernamepduid = key.clone(); | ||||||
| 
 | 
 | ||||||
|                             let exponential_backoff = |(tries, instant): &(u32, Instant)| { |                             let exponential_backoff = |(tries, instant): &(u32, Instant)| { | ||||||
|  | @ -265,7 +269,7 @@ impl Sending { | ||||||
|                                 futures.push( |                                 futures.push( | ||||||
|                                     Self::handle_event( |                                     Self::handle_event( | ||||||
|                                         outgoing_kind, |                                         outgoing_kind, | ||||||
|                                         vec![pdu_id], |                                         vec![pdu_id.to_vec()], | ||||||
|                                         &db, |                                         &db, | ||||||
|                                     ) |                                     ) | ||||||
|                                 ); |                                 ); | ||||||
|  | @ -310,7 +314,7 @@ impl Sending { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #[tracing::instrument] |     #[tracing::instrument] | ||||||
|     fn calculate_hash(keys: &[IVec]) -> Vec<u8> { |     fn calculate_hash(keys: &[Vec<u8>]) -> Vec<u8> { | ||||||
|         // We only hash the pdu's event ids, not the whole pdu
 |         // We only hash the pdu's event ids, not the whole pdu
 | ||||||
|         let bytes = keys.join(&0xff); |         let bytes = keys.join(&0xff); | ||||||
|         let hash = digest::digest(&digest::SHA256, &bytes); |         let hash = digest::digest(&digest::SHA256, &bytes); | ||||||
|  | @ -320,7 +324,7 @@ impl Sending { | ||||||
|     #[tracing::instrument(skip(db))] |     #[tracing::instrument(skip(db))] | ||||||
|     async fn handle_event( |     async fn handle_event( | ||||||
|         kind: OutgoingKind, |         kind: OutgoingKind, | ||||||
|         pdu_ids: Vec<IVec>, |         pdu_ids: Vec<Vec<u8>>, | ||||||
|         db: &Database, |         db: &Database, | ||||||
|     ) -> std::result::Result<OutgoingKind, (OutgoingKind, Error)> { |     ) -> std::result::Result<OutgoingKind, (OutgoingKind, Error)> { | ||||||
|         match &kind { |         match &kind { | ||||||
|  |  | ||||||
|  | @ -2,7 +2,6 @@ use argon2::{Config, Variant}; | ||||||
| use cmp::Ordering; | use cmp::Ordering; | ||||||
| use rand::prelude::*; | use rand::prelude::*; | ||||||
| use ruma::serde::{try_from_json_map, CanonicalJsonError, CanonicalJsonObject}; | use ruma::serde::{try_from_json_map, CanonicalJsonError, CanonicalJsonObject}; | ||||||
| use sled::IVec; |  | ||||||
| use std::{ | use std::{ | ||||||
|     cmp, |     cmp, | ||||||
|     convert::TryInto, |     convert::TryInto, | ||||||
|  | @ -70,10 +69,10 @@ pub fn calculate_hash(password: &str) -> Result<String, argon2::Error> { | ||||||
|     argon2::hash_encoded(password.as_bytes(), salt.as_bytes(), &hashing_config) |     argon2::hash_encoded(password.as_bytes(), salt.as_bytes(), &hashing_config) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn common_elements( | pub fn common_elements<'a>( | ||||||
|     mut iterators: impl Iterator<Item = impl Iterator<Item = IVec>>, |     mut iterators: impl Iterator<Item = impl Iterator<Item = Vec<u8>>>, | ||||||
|     check_order: impl Fn(&IVec, &IVec) -> Ordering, |     check_order: impl Fn(&[u8], &[u8]) -> Ordering, | ||||||
| ) -> Option<impl Iterator<Item = IVec>> { | ) -> Option<impl Iterator<Item = Vec<u8>>> { | ||||||
|     let first_iterator = iterators.next()?; |     let first_iterator = iterators.next()?; | ||||||
|     let mut other_iterators = iterators.map(|i| i.peekable()).collect::<Vec<_>>(); |     let mut other_iterators = iterators.map(|i| i.peekable()).collect::<Vec<_>>(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue