use crate::{Map, MapKeys};
use core::borrow::Borrow;
use core::fmt::{Debug, Formatter, Result as FmtResult};
use core::hash::Hash;
use core::iter::FusedIterator;
#[derive(Clone)]
pub struct Set<T: 'static> {
pub(crate) map: Map<T, ()>,
}
impl<T: Debug> Debug for Set<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.debug_set().entries(self.entries()).finish()
}
}
impl<T> Default for Set<T> {
#[inline]
fn default() -> Self {
Self {
map: Map::default(),
}
}
}
impl<T> Set<T> {
#[doc(hidden)]
#[must_use]
pub const fn from_baked_map(map: Map<T, ()>) -> Self {
Self { map }
}
#[inline]
pub fn get<Q>(&self, value: &Q) -> Option<&T>
where
Q: Hash + Eq + ?Sized,
T: Borrow<Q>,
{
self.map.get_entry(value).map(|(v, ())| v)
}
#[inline]
pub fn contains<Q>(&self, value: &Q) -> bool
where
Q: Hash + Eq + ?Sized,
T: Borrow<Q>,
{
self.map.contains_key(value)
}
#[must_use]
#[inline]
pub fn len(&self) -> usize {
self.map.len()
}
#[must_use]
#[inline]
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
#[must_use]
#[inline]
pub fn entries(&self) -> SetEntries<'_, T> {
SetEntries {
inner: self.map.keys(),
}
}
}
impl<T> PartialEq for Set<T>
where
T: Eq + Hash,
{
fn eq(&self, other: &Self) -> bool {
self.map == other.map
}
}
impl<T> Eq for Set<T> where T: Eq + Hash {}
#[derive(Clone, Debug)]
pub struct SetEntries<'a, T> {
inner: MapKeys<'a, T, ()>,
}
impl<'a, T> Iterator for SetEntries<'a, T> {
type Item = &'a T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl<T> ExactSizeIterator for SetEntries<'_, T> {}
impl<T> FusedIterator for SetEntries<'_, T> {}
#[expect(
clippy::into_iter_without_iter,
reason = "the by-reference iterator is `Set::entries`"
)]
impl<'a, T> IntoIterator for &'a Set<T> {
type Item = &'a T;
type IntoIter = SetEntries<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.entries()
}
}
#[cfg(all(test, feature = "construct"))]
mod test {
use super::Set;
use std::collections::HashSet;
type Value = u8;
#[test]
fn empty() {
let set: Set<Value> = Set::from([]);
assert_eq!(set, Set::default());
assert_eq!(set.len(), 0);
assert!(set.is_empty());
for value in Value::MIN..=Value::MAX {
assert!(set.get(&value).is_none());
assert!(!set.contains(&value));
}
}
#[test]
fn single() {
let set = Set::from([Value::MAX]);
assert_eq!(set.len(), 1);
assert!(!set.is_empty());
for value in Value::MIN..Value::MAX {
assert!(set.get(&value).is_none());
assert!(!set.contains(&value));
}
assert_eq!(set.get(&Value::MAX), Some(&Value::MAX));
assert!(set.contains(&Value::MAX));
}
#[test]
fn multiple() {
let values: Vec<_> = vec![1, 3, 9];
let present: HashSet<_> = values.iter().copied().collect();
let set: Set<_> = values.into_iter().collect();
assert_eq!(set.len(), 3);
assert!(!set.is_empty());
for value in Value::MIN..=Value::MAX {
if present.contains(&value) {
assert_eq!(set.get(&value), Some(&value));
assert!(set.contains(&value));
} else {
assert!(set.get(&value).is_none());
assert!(!set.contains(&value));
}
}
}
#[test]
fn set_iterators() {
let set = Set::from([1u8, 2, 3]);
assert_eq!(set.entries().len(), 3);
let mut values: Vec<_> = set.entries().copied().collect();
values.sort_unstable();
assert_eq!(values, [1, 2, 3]);
let mut by_ref: Vec<_> = (&set).into_iter().copied().collect();
by_ref.sort_unstable();
assert_eq!(by_ref, values);
}
#[test]
fn equality() {
let a = Set::from([1u8, 2, 3]);
let b = Set::from([3u8, 2, 1]);
let differs = Set::from([1u8, 2, 4]);
assert_eq!(a, b);
assert_ne!(a, differs);
}
#[test]
fn borrow_str_lookup() {
let set: Set<_> = ["alpha", "beta"].into_iter().map(str::to_owned).collect();
assert!(set.contains("alpha"));
assert_eq!(set.get("alpha").map(String::as_str), Some("alpha"));
assert!(set.contains("beta"));
assert_eq!(set.get("beta").map(String::as_str), Some("beta"));
assert!(!set.contains("gamma"));
assert_eq!(set.get("gamma"), None);
}
#[test]
#[should_panic = "duplicate key present"]
fn panic_duplicate_value() {
drop(Set::from([Value::MAX, Value::MAX]));
}
}