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