use core::fmt;
use std::borrow::Borrow;
use std::collections::HashSet;
use std::hash::BuildHasher;
use std::hash::Hash;
use std::num::NonZeroUsize;
#[cfg(feature = "serde")]
use serde::Deserialize;
#[cfg(feature = "serde")]
use serde::Serialize;
use crate::iter::NonEmptyIterator;
use crate::FromNonEmptyIterator;
use crate::IntoIteratorExt;
use crate::IntoNonEmptyIterator;
use crate::Singleton;
#[macro_export]
macro_rules! nes {
($h:expr, $( $x:expr ),* $(,)?) => {{
let mut set = $crate::NESet::new($h);
$( set.insert($x); )*
set
}};
($h:expr) => {
$crate::NESet::new($h)
}
}
#[allow(clippy::unsafe_derive_deserialize)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(bound(
serialize = "T: Eq + Hash + Clone + Serialize, S: Clone + BuildHasher",
deserialize = "T: Eq + Hash + Deserialize<'de>, S: Default + BuildHasher"
)),
serde(into = "HashSet<T, S>", try_from = "HashSet<T, S>")
)]
#[derive(Clone)]
pub struct NESet<T, S = std::collections::hash_map::RandomState> {
inner: HashSet<T, S>,
}
impl<T, S> NESet<T, S> {
#[must_use]
pub fn capacity(&self) -> NonZeroUsize {
unsafe { NonZeroUsize::new_unchecked(self.inner.capacity()) }
}
#[must_use]
pub fn hasher(&self) -> &S {
self.inner.hasher()
}
pub fn iter(&self) -> std::collections::hash_set::Iter<'_, T> {
self.inner.iter()
}
pub fn nonempty_iter(&self) -> Iter<'_, T> {
Iter {
iter: self.inner.iter(),
}
}
#[must_use]
pub fn len(&self) -> NonZeroUsize {
unsafe { NonZeroUsize::new_unchecked(self.inner.len()) }
}
#[deprecated(since = "0.1.0", note = "A NESet is never empty.")]
#[must_use]
pub const fn is_empty(&self) -> bool {
false
}
}
impl<T> NESet<T>
where
T: Eq + Hash,
{
#[must_use]
pub fn new(value: T) -> Self {
let mut inner = HashSet::new();
inner.insert(value);
Self { inner }
}
#[must_use]
pub fn with_capacity(capacity: NonZeroUsize, value: T) -> NESet<T> {
let mut inner = HashSet::with_capacity(capacity.get());
inner.insert(value);
NESet { inner }
}
}
impl<T, S> NESet<T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
#[must_use]
pub fn try_from_set(set: HashSet<T, S>) -> Option<NESet<T, S>> {
if set.is_empty() {
None
} else {
Some(NESet { inner: set })
}
}
#[must_use]
pub fn contains<Q>(&self, value: &Q) -> bool
where
T: Borrow<Q>,
Q: Eq + Hash + ?Sized,
{
self.inner.contains(value)
}
pub fn difference<'a>(
&'a self,
other: &'a NESet<T, S>,
) -> std::collections::hash_set::Difference<'a, T, S> {
self.inner.difference(&other.inner)
}
#[must_use]
pub fn get<Q>(&self, value: &Q) -> Option<&T>
where
T: Borrow<Q>,
Q: Eq + Hash,
{
self.inner.get(value)
}
pub fn insert(&mut self, value: T) -> bool {
self.inner.insert(value)
}
pub fn intersection<'a>(
&'a self,
other: &'a NESet<T, S>,
) -> std::collections::hash_set::Intersection<'a, T, S> {
self.inner.intersection(&other.inner)
}
#[must_use]
pub fn is_disjoint(&self, other: &NESet<T, S>) -> bool {
self.inner.is_disjoint(&other.inner)
}
#[must_use]
pub fn is_subset(&self, other: &NESet<T, S>) -> bool {
self.inner.is_subset(&other.inner)
}
#[must_use]
pub fn is_superset(&self, other: &NESet<T, S>) -> bool {
self.inner.is_superset(&other.inner)
}
pub fn replace(&mut self, value: T) -> Option<T> {
self.inner.replace(value)
}
pub fn reserve(&mut self, additional: usize) {
self.inner.reserve(additional);
}
pub fn shrink_to_fit(&mut self) {
self.inner.shrink_to_fit();
}
pub fn union<'a>(&'a self, other: &'a NESet<T, S>) -> Union<'a, T, S> {
Union {
inner: self.inner.union(&other.inner),
}
}
#[must_use]
pub fn with_capacity_and_hasher(capacity: NonZeroUsize, hasher: S, value: T) -> NESet<T, S> {
let mut inner = HashSet::with_capacity_and_hasher(capacity.get(), hasher);
inner.insert(value);
NESet { inner }
}
#[must_use]
pub fn with_hasher(hasher: S, value: T) -> NESet<T, S> {
let mut inner = HashSet::with_hasher(hasher);
inner.insert(value);
NESet { inner }
}
}
impl<T, S> AsRef<HashSet<T, S>> for NESet<T, S> {
fn as_ref(&self) -> &HashSet<T, S> {
&self.inner
}
}
impl<T, S> AsMut<HashSet<T, S>> for NESet<T, S> {
fn as_mut(&mut self) -> &mut HashSet<T, S> {
&mut self.inner
}
}
impl<T, S> PartialEq for NESet<T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
fn eq(&self, other: &Self) -> bool {
self.len() == other.len() && self.intersection(other).count() == self.len().get()
}
}
impl<T, S> Eq for NESet<T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
}
impl<T, S> IntoNonEmptyIterator for NESet<T, S> {
type IntoNEIter = IntoIter<T>;
fn into_nonempty_iter(self) -> Self::IntoNEIter {
IntoIter {
iter: self.inner.into_iter(),
}
}
}
impl<'a, T, S> IntoNonEmptyIterator for &'a NESet<T, S> {
type IntoNEIter = Iter<'a, T>;
fn into_nonempty_iter(self) -> Self::IntoNEIter {
self.nonempty_iter()
}
}
impl<T, S> IntoIterator for NESet<T, S> {
type Item = T;
type IntoIter = std::collections::hash_set::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.inner.into_iter()
}
}
impl<'a, T, S> IntoIterator for &'a NESet<T, S> {
type Item = &'a T;
type IntoIter = std::collections::hash_set::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<T, S> FromNonEmptyIterator<T> for NESet<T, S>
where
T: Eq + Hash,
S: BuildHasher + Default,
{
fn from_nonempty_iter<I>(iter: I) -> Self
where
I: IntoNonEmptyIterator<Item = T>,
{
NESet {
inner: iter.into_nonempty_iter().into_iter().collect(),
}
}
}
#[must_use = "non-empty iterators are lazy and do nothing unless consumed"]
pub struct Iter<'a, T: 'a> {
iter: std::collections::hash_set::Iter<'a, T>,
}
impl<'a, T: 'a> IntoIterator for Iter<'a, T> {
type Item = &'a T;
type IntoIter = std::collections::hash_set::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter
}
}
impl<T> NonEmptyIterator for Iter<'_, T> {}
impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.iter.fmt(f)
}
}
#[must_use = "non-empty iterators are lazy and do nothing unless consumed"]
pub struct IntoIter<T> {
iter: std::collections::hash_set::IntoIter<T>,
}
impl<T> IntoIterator for IntoIter<T> {
type Item = T;
type IntoIter = std::collections::hash_set::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.iter
}
}
impl<T> NonEmptyIterator for IntoIter<T> {}
impl<T: fmt::Debug> fmt::Debug for IntoIter<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.iter.fmt(f)
}
}
#[must_use = "non-empty iterators are lazy and do nothing unless consumed"]
pub struct Union<'a, T: 'a, S: 'a> {
inner: std::collections::hash_set::Union<'a, T, S>,
}
impl<'a, T, S> IntoIterator for Union<'a, T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
type Item = &'a T;
type IntoIter = std::collections::hash_set::Union<'a, T, S>;
fn into_iter(self) -> Self::IntoIter {
self.inner
}
}
impl<T, S> NonEmptyIterator for Union<'_, T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
}
impl<T, S> fmt::Debug for Union<'_, T, S>
where
T: fmt::Debug + Eq + Hash,
S: BuildHasher,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
impl<T, S> From<NESet<T, S>> for HashSet<T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
fn from(s: NESet<T, S>) -> Self {
s.inner
}
}
impl<T: fmt::Debug, S> fmt::Debug for NESet<T, S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
impl<T, S> TryFrom<HashSet<T, S>> for NESet<T, S>
where
T: Eq + Hash,
S: BuildHasher + Default,
{
type Error = crate::Error;
fn try_from(set: HashSet<T, S>) -> Result<Self, Self::Error> {
let ne = set
.try_into_nonempty_iter()
.ok_or(crate::Error::Empty)?
.collect();
Ok(ne)
}
}
impl<T> Singleton for NESet<T>
where
T: Eq + Hash,
{
type Item = T;
fn singleton(item: Self::Item) -> Self {
NESet::new(item)
}
}
impl<T> Extend<T> for NESet<T>
where
T: Eq + Hash,
{
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
self.inner.extend(iter);
}
}
#[cfg(test)]
mod test {
use maplit::hashset;
#[test]
fn debug_impl() {
let expected = format!("{:?}", hashset! {0});
let actual = format!("{:?}", nes! {0});
assert_eq!(expected, actual);
}
#[test]
fn iter_debug_impl() {
let expected = format!("{:?}", hashset! {0}.iter());
let actual = format!("{:?}", nes! {0}.nonempty_iter());
assert_eq!(expected, actual);
}
}
#[cfg(feature = "serde")]
#[cfg(test)]
mod serde_tests {
use crate::NESet;
use std::collections::HashSet;
#[test]
fn json() {
let set0 = nes![1, 1, 2, 3, 2, 1, 4];
let j = serde_json::to_string(&set0).unwrap();
let set1 = serde_json::from_str(&j).unwrap();
assert_eq!(set0, set1);
let empty: HashSet<usize> = HashSet::new();
let j = serde_json::to_string(&empty).unwrap();
let bad = serde_json::from_str::<NESet<usize>>(&j);
assert!(bad.is_err());
}
}