#![warn(missing_docs)]
#![deny(unsafe_code)]
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque};
pub struct Fallback<T> {
data: Option<T>,
base_data: Option<T>,
}
impl<T> Fallback<T> {
pub const fn new(data: Option<T>, base_data: Option<T>) -> Self {
Self { data, base_data }
}
pub const fn is_some(&self) -> bool {
self.data.is_some() || self.base_data.is_some()
}
pub const fn as_ref(&self) -> Fallback<&T> {
Fallback::new(self.data.as_ref(), self.base_data.as_ref())
}
pub fn and_then<V>(self, mut f: impl FnMut(T) -> Option<V>) -> Option<V> {
self.data
.and_then(&mut f)
.or_else(|| self.base_data.and_then(&mut f))
}
pub fn fallback(self) -> Option<T> {
self.data.or(self.base_data)
}
pub fn map<V>(self, mut f: impl FnMut(T) -> V) -> Fallback<V> {
Fallback::new(self.data.map(&mut f), self.base_data.map(&mut f))
}
pub fn unzip(self) -> (Option<T>, Option<T>) {
(self.data, self.base_data)
}
}
impl<T> Fallback<Option<T>> {
pub fn flatten(self) -> Fallback<T> {
Fallback::new(self.data.flatten(), self.base_data.flatten())
}
}
#[doc(hidden)]
pub trait IsEmpty2 {
fn is_empty2(&self) -> bool;
}
impl IsEmpty2 for String {
fn is_empty2(&self) -> bool {
self.is_empty()
}
}
impl<T> IsEmpty2 for Vec<T> {
fn is_empty2(&self) -> bool {
self.is_empty()
}
}
impl<T> IsEmpty2 for VecDeque<T> {
fn is_empty2(&self) -> bool {
self.is_empty()
}
}
impl<T> IsEmpty2 for LinkedList<T> {
fn is_empty2(&self) -> bool {
self.is_empty()
}
}
impl<K, V> IsEmpty2 for HashMap<K, V> {
fn is_empty2(&self) -> bool {
self.is_empty()
}
}
impl<K, V> IsEmpty2 for BTreeMap<K, V> {
fn is_empty2(&self) -> bool {
self.is_empty()
}
}
impl<T> IsEmpty2 for HashSet<T> {
fn is_empty2(&self) -> bool {
self.is_empty()
}
}
impl<T> IsEmpty2 for BTreeSet<T> {
fn is_empty2(&self) -> bool {
self.is_empty()
}
}
impl<T> IsEmpty2 for BinaryHeap<T> {
fn is_empty2(&self) -> bool {
self.is_empty()
}
}
impl<T: IsEmpty2> Fallback<T> {
pub fn and_any(self) -> Option<T> {
self.and_then(|s| if s.is_empty2() { None } else { Some(s) })
}
}
impl<T> From<Fallback<T>> for Option<T> {
fn from(f: Fallback<T>) -> Self {
if f.data.is_some() {
f.data
} else {
f.base_data
}
}
}
#[doc(hidden)]
pub struct FallbackIter<A> {
data: A,
base_data: A,
}
impl<A: Iterator> Iterator for FallbackIter<A> {
type Item = Fallback<A::Item>;
fn next(&mut self) -> Option<Self::Item> {
let d = self.data.next();
let based = self.base_data.next();
if d.is_some() || based.is_some() {
Some(Fallback::new(d, based))
} else {
None
}
}
}
impl<T> IntoIterator for Fallback<Vec<T>> {
type Item = Fallback<T>;
type IntoIter = FallbackIter<<Vec<T> as IntoIterator>::IntoIter>;
fn into_iter(self) -> Self::IntoIter {
FallbackIter {
data: self.data.unwrap_or_default().into_iter(),
base_data: self.base_data.unwrap_or_default().into_iter(),
}
}
}
pub trait FallbackSpec: Sized {
type SpecType: From<Fallback<Self>>;
}
impl<T: FallbackSpec> Fallback<T> {
pub fn spec(self) -> T::SpecType {
T::SpecType::from(self)
}
}
pub use fallback_derive::FallbackSpec;
#[cfg(test)]
mod test {
use crate::*;
#[test]
fn some() {
assert!(!Fallback::<()>::new(None, None).is_some());
}
#[test]
fn option() {
let f = Fallback::new(None, Some(100));
assert_eq!(Option::from(f), Some(100));
}
}