1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use std::sync::Arc;
use crate::types::misc::LongIdent;
use crate::util::intern::InternCache;
use crate::{Error, Result};
use tor_llcrypto::pk::rsa::RsaIdentity;
#[derive(Clone, Debug, Default, Hash, Eq, PartialEq)]
pub struct RelayFamily(Vec<RsaIdentity>);
static FAMILY_CACHE: InternCache<RelayFamily> = InternCache::new();
impl RelayFamily {
pub fn new() -> Self {
RelayFamily::default()
}
pub fn push(&mut self, rsa_id: RsaIdentity) {
self.0.push(rsa_id);
}
fn normalize(&mut self) {
self.0.sort();
self.0.dedup();
}
pub fn intern(mut self) -> Arc<Self> {
self.normalize();
FAMILY_CACHE.intern(self)
}
pub fn contains(&self, rsa_id: &RsaIdentity) -> bool {
self.0.contains(rsa_id)
}
pub fn members(&self) -> impl Iterator<Item = &RsaIdentity> {
self.0.iter()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl std::str::FromStr for RelayFamily {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
let v: Result<Vec<RsaIdentity>> = s
.split(crate::parse::tokenize::is_sp)
.map(|e| e.parse::<LongIdent>().map(|v| v.into()))
.filter(Result::is_ok)
.collect();
Ok(RelayFamily(v?))
}
}
#[cfg(test)]
mod test {
#![allow(clippy::unwrap_used)]
use super::*;
use crate::Result;
#[test]
fn family() -> Result<()> {
let f = "nickname1 nickname2 $ffffffffffffffffffffffffffffffffffffffff=foo eeeeeeeeeeeeeeeeeeeEEEeeeeeeeeeeeeeeeeee ddddddddddddddddddddddddddddddddd $cccccccccccccccccccccccccccccccccccccccc~blarg ".parse::<RelayFamily>()?;
let v = vec![
RsaIdentity::from_bytes(
&hex::decode("ffffffffffffffffffffffffffffffffffffffff").unwrap()[..],
)
.unwrap(),
RsaIdentity::from_bytes(
&hex::decode("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee").unwrap()[..],
)
.unwrap(),
RsaIdentity::from_bytes(
&hex::decode("cccccccccccccccccccccccccccccccccccccccc").unwrap()[..],
)
.unwrap(),
];
assert_eq!(f.0, v);
Ok(())
}
#[test]
fn test_contains() -> Result<()> {
let family =
"ffffffffffffffffffffffffffffffffffffffff eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
.parse::<RelayFamily>()?;
let in_family = RsaIdentity::from_bytes(
&hex::decode("ffffffffffffffffffffffffffffffffffffffff").unwrap()[..],
)
.unwrap();
let not_in_family = RsaIdentity::from_bytes(
&hex::decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").unwrap()[..],
)
.unwrap();
assert!(family.contains(&in_family), "Relay not found in family");
assert!(
!family.contains(¬_in_family),
"Extra relay found in family"
);
Ok(())
}
}