use std::any::Any;
use std::fmt;
use indexmap::IndexSet;
use super::hints::Flags;
use super::AsyncSetQuery;
use super::BoxVertexStream;
use super::Hints;
use crate::Result;
use crate::Vertex;
pub struct StaticSet(pub(crate) IndexSet<Vertex>, Hints);
impl StaticSet {
pub fn from_names(names: impl IntoIterator<Item = Vertex>) -> Self {
let names: IndexSet<Vertex> = names.into_iter().collect();
let hints = Hints::default();
if names.is_empty() {
hints.add_flags(Flags::EMPTY);
}
Self(names, hints)
}
pub fn empty() -> Self {
let names: IndexSet<Vertex> = Default::default();
let hints = Hints::default();
hints.add_flags(Flags::EMPTY);
Self(names, hints)
}
}
#[async_trait::async_trait]
impl AsyncSetQuery for StaticSet {
async fn iter(&self) -> Result<BoxVertexStream> {
let iter = self.0.clone().into_iter().map(Ok);
Ok(Box::pin(futures::stream::iter(iter)))
}
async fn iter_rev(&self) -> Result<BoxVertexStream> {
let iter = self.0.clone().into_iter().rev().map(Ok);
Ok(Box::pin(futures::stream::iter(iter)))
}
async fn count(&self) -> Result<u64> {
Ok(self.0.len().try_into()?)
}
async fn size_hint(&self) -> (u64, Option<u64>) {
let size = self.0.len() as u64;
(size, Some(size))
}
async fn is_empty(&self) -> Result<bool> {
Ok(self.0.is_empty())
}
async fn contains(&self, name: &Vertex) -> Result<bool> {
Ok(self.0.contains(name))
}
async fn contains_fast(&self, name: &Vertex) -> Result<Option<bool>> {
Ok(Some(self.0.contains(name)))
}
fn as_any(&self) -> &dyn Any {
self
}
fn hints(&self) -> &Hints {
&self.1
}
}
impl fmt::Debug for StaticSet {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.0.is_empty() {
return f.write_str("<empty>");
}
write!(f, "<static ")?;
let limit = f.width().unwrap_or(3);
f.debug_list().entries(self.0.iter().take(limit)).finish()?;
let remaining = self.0.len().max(limit) - limit;
if remaining > 0 {
write!(f, " + {} more>", remaining)?;
} else {
write!(f, ">")?;
}
Ok(())
}
}
#[cfg(not(fbcode_build))]
#[cfg(test)]
mod tests {
use std::collections::HashSet;
use super::super::tests::*;
use super::*;
fn static_set(a: &[u8]) -> StaticSet {
StaticSet::from_names(a.iter().map(|&b| to_name(b)))
}
#[test]
fn test_static_basic() -> Result<()> {
let set = static_set(b"\x11\x33\x22\x77\x22\x55\x11");
check_invariants(&set)?;
assert_eq!(shorten_iter(ni(set.iter())), ["11", "33", "22", "77", "55"]);
assert_eq!(
shorten_iter(ni(set.iter_rev())),
["55", "77", "22", "33", "11"]
);
assert!(!nb(set.is_empty())?);
assert_eq!(nb(set.count())?, 5);
assert_eq!(shorten_name(nb(set.first())?.unwrap()), "11");
assert_eq!(shorten_name(nb(set.last())?.unwrap()), "55");
assert_eq!(nb(set.size_hint()), (5, Some(5)));
Ok(())
}
#[test]
fn test_debug() {
let set = static_set(b"");
assert_eq!(dbg(set), "<empty>");
let set = static_set(b"\x11\x33\x22");
assert_eq!(dbg(set), "<static [1111, 3333, 2222]>");
let set = static_set(b"\xaa\x00\xaa\xdd\xee\xdd\x11\x22");
assert_eq!(dbg(&set), "<static [aaaa, 0000, dddd] + 3 more>");
assert_eq!(
format!("{:#?}", &set),
"<static [\n aaaa,\n 0000,\n dddd,\n] + 3 more>"
);
assert_eq!(
format!("{:5.2?}", &set),
"<static [aa, 00, dd, ee, 11] + 1 more>"
);
}
quickcheck::quickcheck! {
fn test_static_quickcheck(a: Vec<u8>) -> bool {
let set = static_set(&a);
check_invariants(&set).unwrap();
let count = nb(set.count()).unwrap() as usize;
assert!(count <= a.len());
let set2: HashSet<_> = a.iter().cloned().collect();
assert_eq!(count, set2.len());
true
}
}
}