//! Implement a set of RelayId. use std::collections::HashSet; use serde::de::Visitor; use tor_llcrypto::pk::{ed25519::Ed25519Identity, rsa::RsaIdentity}; use crate::{RelayId, RelayIdRef}; /// A set of relay identities, backed by `HashSet`. /// /// # Note /// /// I'd rather use `HashSet` entirely, but that doesn't let us index by /// RelayIdRef. #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct RelayIdSet { /// The Ed25519 members of this set. ed25519: HashSet, /// The RSA members of this set. rsa: HashSet, } impl RelayIdSet { /// Construct a new empty RelayIdSet. pub fn new() -> Self { Self::default() } /// Insert `key` into this set. /// /// Return true if it was not already there. pub fn insert>(&mut self, key: T) -> bool { let key: RelayId = key.into(); match key { RelayId::Ed25519(key) => self.ed25519.insert(key), RelayId::Rsa(key) => self.rsa.insert(key), } } /// Remove `key` from the set. /// /// Return true if `key` was present. pub fn remove<'a, T: Into>>(&mut self, key: T) -> bool { let key: RelayIdRef<'a> = key.into(); match key { RelayIdRef::Ed25519(key) => self.ed25519.remove(key), RelayIdRef::Rsa(key) => self.rsa.remove(key), } } /// Return true if `key` is a member of this set. pub fn contains<'a, T: Into>>(&self, key: T) -> bool { let key: RelayIdRef<'a> = key.into(); match key { RelayIdRef::Ed25519(key) => self.ed25519.contains(key), RelayIdRef::Rsa(key) => self.rsa.contains(key), } } /// Return an iterator over the members of this set. /// /// The ordering of the iterator is undefined; do not rely on it. pub fn iter(&self) -> impl Iterator> { self.ed25519 .iter() .map(|id| id.into()) .chain(self.rsa.iter().map(|id| id.into())) } /// Return the number of keys in this set. pub fn len(&self) -> usize { self.ed25519.len() + self.rsa.len() } /// Return true if there are not keys in this set. pub fn is_empty(&self) -> bool { self.ed25519.is_empty() && self.rsa.is_empty() } } impl> Extend for RelayIdSet { fn extend>(&mut self, iter: T) { for item in iter { self.insert(item); } } } impl FromIterator for RelayIdSet { fn from_iter>(iter: T) -> Self { let mut set = RelayIdSet::new(); set.extend(iter); set } } impl serde::Serialize for RelayIdSet { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { serializer.collect_seq(self.iter()) } } impl<'de> serde::Deserialize<'de> for RelayIdSet { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { /// A serde visitor to deserialize a sequence of RelayIds into a /// RelayIdSet. struct IdSetVisitor; impl<'de> Visitor<'de> for IdSetVisitor { type Value = RelayIdSet; fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "a list of relay identities") } fn visit_seq(self, mut seq: A) -> Result where A: serde::de::SeqAccess<'de>, { let mut set = RelayIdSet::new(); while let Some(key) = seq.next_element::()? { set.insert(key); } Ok(set) } } deserializer.deserialize_seq(IdSetVisitor) } } #[cfg(test)] mod test { // @@ begin test lint list maintained by maint/add_warning @@ #![allow(clippy::bool_assert_comparison)] #![allow(clippy::clone_on_copy)] #![allow(clippy::dbg_macro)] #![allow(clippy::mixed_attributes_style)] #![allow(clippy::print_stderr)] #![allow(clippy::print_stdout)] #![allow(clippy::single_char_pattern)] #![allow(clippy::unwrap_used)] #![allow(clippy::unchecked_duration_subtraction)] #![allow(clippy::useless_vec)] #![allow(clippy::needless_pass_by_value)] //! use super::*; use hex_literal::hex; use serde_test::{assert_tokens, Token}; #[test] fn basic_usage() { #![allow(clippy::cognitive_complexity)] let rsa1 = RsaIdentity::from(hex!("42656c6f7665642c207768617420617265206e61")); let rsa2 = RsaIdentity::from(hex!("6d657320627574206169723f43686f6f73652074")); let rsa3 = RsaIdentity::from(hex!("686f752077686174657665722073756974732074")); let ed1 = Ed25519Identity::from(hex!( "6865206c696e653a43616c6c206d652053617070686f2c2063616c6c206d6520" )); let ed2 = Ed25519Identity::from(hex!( "43686c6f7269732c2043616c6c206d65204c616c6167652c206f7220446f7269" )); let ed3 = Ed25519Identity::from(hex!( "732c204f6e6c792c206f6e6c792c2063616c6c206d65207468696e652e000000" )); let mut set = RelayIdSet::new(); assert_eq!(set.is_empty(), true); assert_eq!(set.len(), 0); set.insert(rsa1); set.insert(rsa2); set.insert(ed1); assert_eq!(set.is_empty(), false); assert_eq!(set.len(), 3); assert_eq!(set.contains(&rsa1), true); assert_eq!(set.contains(&rsa2), true); assert_eq!(set.contains(&rsa3), false); assert_eq!(set.contains(&ed1), true); assert_eq!(set.contains(&ed2), false); assert_eq!(set.contains(&ed3), false); let contents: HashSet<_> = set.iter().collect(); assert_eq!(contents.len(), set.len()); assert!(contents.contains(&RelayIdRef::from(&rsa1))); assert!(contents.contains(&RelayIdRef::from(&rsa2))); assert!(contents.contains(&RelayIdRef::from(&ed1))); assert_eq!(set.remove(&ed2), false); assert_eq!(set.remove(&ed1), true); assert_eq!(set.remove(&rsa3), false); assert_eq!(set.remove(&rsa1), true); assert_eq!(set.is_empty(), false); assert_eq!(set.len(), 1); assert_eq!(set.contains(&ed1), false); assert_eq!(set.contains(&rsa1), false); assert_eq!(set.contains(&rsa2), true); let contents2: Vec<_> = set.iter().collect(); assert_eq!(contents2, vec![RelayIdRef::from(&rsa2)]); let set2: RelayIdSet = set.iter().map(|id| id.to_owned()).collect(); assert_eq!(set, set2); let mut set3 = RelayIdSet::new(); set3.extend(set.iter().map(|id| id.to_owned())); assert_eq!(set2, set3); } #[test] fn serde_empty() { let set = RelayIdSet::new(); assert_tokens(&set, &[Token::Seq { len: Some(0) }, Token::SeqEnd]); } #[test] fn serde_singleton_rsa() { let mut set = RelayIdSet::new(); set.insert(RsaIdentity::from(hex!( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))); assert_tokens( &set, &[ Token::Seq { len: Some(1) }, Token::Str("$aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), Token::SeqEnd, ], ); } #[test] fn serde_singleton_ed25519() { let mut set = RelayIdSet::new(); set.insert(Ed25519Identity::from(hex!( "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" ))); assert_tokens( &set, &[ Token::Seq { len: Some(1) }, Token::String("ed25519:u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7s"), Token::SeqEnd, ], ); } }