use std::{
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
hash::{BuildHasher, Hash},
iter, mem,
ops::{Deref, DerefMut},
};
pub fn if_empty<V, C, Parser, Input>(
parse: Parser,
) -> impl FnOnce(&mut C, Input) -> syn::Result<()>
where
C: Container<V> + ?Sized,
Parser: FnOnce(Input) -> syn::Result<Option<V>>,
{
move |container, input| {
if container.is_empty() {
if let Some(val) = parse(input)? {
container.set(val);
}
}
Ok(())
}
}
pub trait Container<V> {
type Value;
#[must_use]
fn is_empty(&self) -> bool;
#[must_use]
fn has(&self, value: &V) -> bool;
fn replace(&mut self, value: V) -> Option<V>;
fn set(&mut self, value: V) {
drop(self.replace(value));
}
}
impl<V> Container<V> for Option<V> {
type Value = V;
fn is_empty(&self) -> bool {
self.is_none()
}
fn has(&self, _: &V) -> bool {
self.is_some()
}
fn replace(&mut self, val: V) -> Self {
Self::replace(self, val)
}
}
impl<V> Container<V> for Required<V> {
type Value = V;
fn is_empty(&self) -> bool {
!self.is_present()
}
fn has(&self, _: &V) -> bool {
self.is_present()
}
fn replace(&mut self, val: V) -> Option<V> {
Self::replace(self, val)
}
}
impl<V: PartialEq> Container<V> for Vec<V> {
type Value = V;
fn is_empty(&self) -> bool {
Self::is_empty(self)
}
fn has(&self, val: &V) -> bool {
self.contains(val)
}
fn replace(&mut self, val: V) -> Option<V> {
#[allow(clippy::option_if_let_else)] if let Some(old) = self.iter_mut().find(|v| *v == &val) {
Some(mem::replace(old, val))
} else {
self.push(val);
None
}
}
}
impl<V, S> Container<V> for HashSet<V, S>
where
V: Eq + Hash,
S: BuildHasher,
{
type Value = V;
fn is_empty(&self) -> bool {
Self::is_empty(self)
}
fn has(&self, val: &V) -> bool {
self.contains(val)
}
fn replace(&mut self, val: V) -> Option<V> {
Self::replace(self, val)
}
}
impl<V: Ord> Container<V> for BTreeSet<V> {
type Value = V;
fn is_empty(&self) -> bool {
Self::is_empty(self)
}
fn has(&self, val: &V) -> bool {
self.contains(val)
}
fn replace(&mut self, val: V) -> Option<V> {
Self::replace(self, val)
}
}
impl<K, V, S> Container<(K, V)> for HashMap<K, V, S>
where
K: Eq + Hash,
S: BuildHasher,
{
type Value = (K, V);
fn is_empty(&self) -> bool {
Self::is_empty(self)
}
fn has(&self, val: &(K, V)) -> bool {
self.contains_key(&val.0)
}
fn replace(&mut self, val: (K, V)) -> Option<(K, V)> {
let prev = self.remove_entry(&val.0);
drop(self.insert(val.0, val.1));
prev
}
}
impl<K: Ord, V> Container<(K, V)> for BTreeMap<K, V> {
type Value = (K, V);
fn is_empty(&self) -> bool {
Self::is_empty(self)
}
fn has(&self, val: &(K, V)) -> bool {
self.contains_key(&val.0)
}
fn replace(&mut self, val: (K, V)) -> Option<(K, V)> {
let prev = self.remove_entry(&val.0);
drop(self.insert(val.0, val.1));
prev
}
}
#[derive(Clone, Copy, Debug)]
pub struct Required<T>(Option<T>);
#[doc(hidden)]
impl<T> Default for Required<T> {
fn default() -> Self {
Self(None)
}
}
impl<T> Required<T> {
#[must_use]
pub(crate) const fn is_present(&self) -> bool {
self.0.is_some()
}
#[must_use]
pub(crate) fn replace(&mut self, value: T) -> Option<T> {
self.0.replace(value)
}
#[must_use]
pub(crate) fn take(&mut self) -> Option<T> {
self.0.take()
}
#[must_use]
pub fn into_inner(self) -> T {
#[allow(clippy::expect_used)]
self.0.expect("Uninitialized `Required` value")
}
}
impl<T> Deref for Required<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
#[allow(clippy::expect_used)]
self.0.as_ref().expect("Uninitialized `Required` value")
}
}
impl<T> DerefMut for Required<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
#[allow(clippy::expect_used)]
self.0.as_mut().expect("Uninitialized `Required` value")
}
}
impl<T> IntoIterator for Required<T> {
type Item = T;
type IntoIter = iter::Once<T>;
fn into_iter(self) -> Self::IntoIter {
iter::once(self.into_inner())
}
}
impl<'a, T> IntoIterator for &'a Required<T> {
type Item = &'a T;
type IntoIter = iter::Once<&'a T>;
fn into_iter(self) -> Self::IntoIter {
iter::once(&*self)
}
}
impl<'a, T> IntoIterator for &'a mut Required<T> {
type Item = &'a mut T;
type IntoIter = iter::Once<&'a mut T>;
fn into_iter(self) -> Self::IntoIter {
iter::once(&mut *self)
}
}