1use std::any::Any;
9use std::fmt;
10
11use indexmap::IndexSet;
12
13use super::hints::Flags;
14use super::AsyncNameSetQuery;
15use super::BoxVertexStream;
16use super::Hints;
17use crate::Result;
18use crate::VertexName;
19
20pub struct StaticSet(pub(crate) IndexSet<VertexName>, Hints);
22
23impl StaticSet {
24 pub fn from_names(names: impl IntoIterator<Item = VertexName>) -> Self {
25 let names: IndexSet<VertexName> = names.into_iter().collect();
26 let hints = Hints::default();
27 if names.is_empty() {
28 hints.add_flags(Flags::EMPTY);
29 }
30 Self(names, hints)
31 }
32
33 pub fn empty() -> Self {
34 let names: IndexSet<VertexName> = Default::default();
35 let hints = Hints::default();
36 hints.add_flags(Flags::EMPTY);
37 Self(names, hints)
38 }
39}
40
41#[async_trait::async_trait]
42impl AsyncNameSetQuery for StaticSet {
43 async fn iter(&self) -> Result<BoxVertexStream> {
44 let iter = self.0.clone().into_iter().map(Ok);
45 Ok(Box::pin(futures::stream::iter(iter)))
46 }
47
48 async fn iter_rev(&self) -> Result<BoxVertexStream> {
49 let iter = self.0.clone().into_iter().rev().map(Ok);
50 Ok(Box::pin(futures::stream::iter(iter)))
51 }
52
53 async fn count(&self) -> Result<usize> {
54 Ok(self.0.len())
55 }
56
57 async fn is_empty(&self) -> Result<bool> {
58 Ok(self.0.is_empty())
59 }
60
61 async fn contains(&self, name: &VertexName) -> Result<bool> {
62 Ok(self.0.contains(name))
63 }
64
65 async fn contains_fast(&self, name: &VertexName) -> Result<Option<bool>> {
66 Ok(Some(self.0.contains(name)))
67 }
68
69 fn as_any(&self) -> &dyn Any {
70 self
71 }
72
73 fn hints(&self) -> &Hints {
74 &self.1
75 }
76}
77
78impl fmt::Debug for StaticSet {
79 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
80 if self.0.is_empty() {
81 return f.write_str("<empty>");
82 }
83 write!(f, "<static ")?;
84 let limit = f.width().unwrap_or(3);
86 f.debug_list().entries(self.0.iter().take(limit)).finish()?;
87 let remaining = self.0.len().max(limit) - limit;
88 if remaining > 0 {
89 write!(f, " + {} more>", remaining)?;
90 } else {
91 write!(f, ">")?;
92 }
93 Ok(())
94 }
95}
96
97#[cfg(not(fbcode_build))]
99#[cfg(test)]
100mod tests {
101 use std::collections::HashSet;
102
103 use super::super::tests::*;
104 use super::*;
105
106 fn static_set(a: &[u8]) -> StaticSet {
107 StaticSet::from_names(a.iter().map(|&b| to_name(b)))
108 }
109
110 #[test]
111 fn test_static_basic() -> Result<()> {
112 let set = static_set(b"\x11\x33\x22\x77\x22\x55\x11");
113 check_invariants(&set)?;
114 assert_eq!(shorten_iter(ni(set.iter())), ["11", "33", "22", "77", "55"]);
115 assert_eq!(
116 shorten_iter(ni(set.iter_rev())),
117 ["55", "77", "22", "33", "11"]
118 );
119 assert!(!nb(set.is_empty())?);
120 assert_eq!(nb(set.count())?, 5);
121 assert_eq!(shorten_name(nb(set.first())?.unwrap()), "11");
122 assert_eq!(shorten_name(nb(set.last())?.unwrap()), "55");
123 Ok(())
124 }
125
126 #[test]
127 fn test_debug() {
128 let set = static_set(b"");
129 assert_eq!(format!("{:?}", set), "<empty>");
130
131 let set = static_set(b"\x11\x33\x22");
132 assert_eq!(format!("{:?}", set), "<static [1111, 3333, 2222]>");
133
134 let set = static_set(b"\xaa\x00\xaa\xdd\xee\xdd\x11\x22");
135 assert_eq!(
136 format!("{:?}", &set),
137 "<static [aaaa, 0000, dddd] + 3 more>"
138 );
139 assert_eq!(
141 format!("{:#?}", &set),
142 "<static [\n aaaa,\n 0000,\n dddd,\n] + 3 more>"
143 );
144 assert_eq!(
146 format!("{:5.2?}", &set),
147 "<static [aa, 00, dd, ee, 11] + 1 more>"
148 );
149 }
150
151 quickcheck::quickcheck! {
152 fn test_static_quickcheck(a: Vec<u8>) -> bool {
153 let set = static_set(&a);
154 check_invariants(&set).unwrap();
155
156 let count = nb(set.count()).unwrap();
157 assert!(count <= a.len());
158
159 let set2: HashSet<_> = a.iter().cloned().collect();
160 assert_eq!(count, set2.len());
161
162 true
163 }
164 }
165}