use super::functions::*;
use std::collections::HashMap;
#[allow(dead_code)]
pub struct OptionComonad<T: Clone> {
value: Option<T>,
default: T,
}
impl<T: Clone> OptionComonad<T> {
#[allow(dead_code)]
pub fn new(value: Option<T>, default: T) -> Self {
Self { value, default }
}
#[allow(dead_code)]
pub fn extract(&self) -> T {
self.value.clone().unwrap_or_else(|| self.default.clone())
}
#[allow(dead_code)]
pub fn extend<B: Clone>(&self, f: impl Fn(&OptionComonad<T>) -> B) -> Option<B> {
Some(f(self))
}
#[allow(dead_code)]
pub fn duplicate_as_pair(&self) -> (T, Option<T>) {
(self.default.clone(), self.value.clone())
}
}
#[allow(dead_code)]
pub struct OptionMemo<K: std::hash::Hash + Eq, V: Clone> {
cache: std::collections::HashMap<K, Option<V>>,
}
impl<K: std::hash::Hash + Eq, V: Clone> OptionMemo<K, V> {
#[allow(dead_code)]
pub fn new() -> Self {
Self {
cache: std::collections::HashMap::new(),
}
}
#[allow(dead_code)]
pub fn get_or_compute(&mut self, key: K, f: impl FnOnce(&K) -> Option<V>) -> Option<V>
where
K: Clone,
{
if let Some(v) = self.cache.get(&key) {
return v.clone();
}
let v = f(&key);
self.cache.insert(key, v.clone());
v
}
#[allow(dead_code)]
pub fn clear(&mut self) {
self.cache.clear();
}
#[allow(dead_code)]
pub fn len(&self) -> usize {
self.cache.len()
}
#[allow(dead_code)]
pub fn is_empty(&self) -> bool {
self.cache.is_empty()
}
}
#[allow(dead_code)]
pub struct OptionIter<T>(pub(super) Option<T>);
impl<T> OptionIter<T> {
#[allow(dead_code)]
pub fn new(opt: Option<T>) -> Self {
Self(opt)
}
}
#[allow(dead_code)]
pub struct OptionFunctor<T>(pub Option<T>);
impl<T> OptionFunctor<T> {
#[allow(dead_code)]
pub fn new(v: Option<T>) -> Self {
Self(v)
}
#[allow(dead_code)]
pub fn fmap<U>(self, f: impl FnOnce(T) -> U) -> OptionFunctor<U> {
OptionFunctor(self.0.map(f))
}
#[allow(dead_code)]
pub fn fmap_id(self) -> OptionFunctor<T> {
OptionFunctor(self.0)
}
#[allow(dead_code)]
pub fn inner(self) -> Option<T> {
self.0
}
}
#[allow(dead_code)]
pub struct OptionApplicative;
impl OptionApplicative {
#[allow(dead_code)]
pub fn pure<T>(v: T) -> Option<T> {
Some(v)
}
#[allow(dead_code)]
pub fn ap<A, B>(f: Option<impl FnOnce(A) -> B>, a: Option<A>) -> Option<B> {
match (f, a) {
(Some(func), Some(val)) => Some(func(val)),
_ => None,
}
}
#[allow(dead_code)]
pub fn lift_a2<A, B, C>(f: impl FnOnce(A, B) -> C, a: Option<A>, b: Option<B>) -> Option<C> {
match (a, b) {
(Some(x), Some(y)) => Some(f(x, y)),
_ => None,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct OptionCache<K: PartialEq, V> {
entries: Vec<(K, Option<V>)>,
}
impl<K: PartialEq, V: Clone> OptionCache<K, V> {
pub fn new() -> Self {
Self {
entries: Vec::new(),
}
}
pub fn get_or_insert_with(&mut self, key: K, compute: impl FnOnce() -> Option<V>) -> Option<V>
where
K: Clone,
{
if let Some(entry) = self.entries.iter().find(|(k, _)| k == &key) {
return entry.1.clone();
}
let value = compute();
self.entries.push((key, value.clone()));
value
}
pub fn insert(&mut self, key: K, value: Option<V>)
where
K: Clone,
V: Clone,
{
if let Some(entry) = self.entries.iter_mut().find(|(k, _)| k == &key) {
entry.1 = value;
} else {
self.entries.push((key, value));
}
}
pub fn get(&self, key: &K) -> Option<Option<&V>> {
self.entries
.iter()
.find(|(k, _)| k == key)
.map(|(_, v)| v.as_ref())
}
pub fn invalidate(&mut self, key: &K) {
self.entries.retain(|(k, _)| k != key);
}
pub fn clear(&mut self) {
self.entries.clear();
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}
#[allow(dead_code)]
pub struct OptionChain<T> {
value: Option<T>,
}
impl<T> OptionChain<T> {
#[allow(dead_code)]
pub fn from(opt: Option<T>) -> Self {
Self { value: opt }
}
#[allow(dead_code)]
pub fn of(v: T) -> Self {
Self { value: Some(v) }
}
#[allow(dead_code)]
pub fn empty() -> Self {
Self { value: None }
}
#[allow(dead_code)]
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> OptionChain<U> {
OptionChain {
value: self.value.map(f),
}
}
#[allow(dead_code)]
pub fn flat_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> OptionChain<U> {
OptionChain {
value: self.value.and_then(f),
}
}
#[allow(dead_code)]
pub fn filter(self, pred: impl FnOnce(&T) -> bool) -> Self {
Self {
value: self.value.filter(pred),
}
}
#[allow(dead_code)]
pub fn or_else(self, fallback: Option<T>) -> Self {
Self {
value: self.value.or(fallback),
}
}
#[allow(dead_code)]
pub fn get(self) -> Option<T> {
self.value
}
#[allow(dead_code)]
pub fn get_or(self, default: T) -> T {
self.value.unwrap_or(default)
}
#[allow(dead_code)]
pub fn is_present(&self) -> bool {
self.value.is_some()
}
#[allow(dead_code)]
pub fn peek(&self) -> Option<&T> {
self.value.as_ref()
}
}
#[allow(dead_code)]
pub struct OptionWriter<T, W> {
value: Option<T>,
log: W,
}
impl<T, W: Default> OptionWriter<T, W> {
#[allow(dead_code)]
pub fn new(value: Option<T>, log: W) -> Self {
Self { value, log }
}
#[allow(dead_code)]
pub fn pure_some(value: T) -> Self {
Self {
value: Some(value),
log: W::default(),
}
}
#[allow(dead_code)]
pub fn none_with_log(log: W) -> Self {
Self { value: None, log }
}
#[allow(dead_code)]
pub fn is_some(&self) -> bool {
self.value.is_some()
}
}
#[allow(dead_code)]
pub struct OptionResultBridge;
impl OptionResultBridge {
#[allow(dead_code)]
pub fn to_result<T, E>(opt: Option<T>, err: E) -> Result<T, E> {
opt.ok_or(err)
}
#[allow(dead_code)]
pub fn to_result_with<T, E>(opt: Option<T>, f: impl FnOnce() -> E) -> Result<T, E> {
opt.ok_or_else(f)
}
#[allow(dead_code)]
pub fn from_result_ok<T, E>(r: Result<T, E>) -> Option<T> {
r.ok()
}
#[allow(dead_code)]
pub fn from_result_err<T, E>(r: Result<T, E>) -> Option<E> {
r.err()
}
#[allow(dead_code)]
pub fn transpose_result<T, E>(r: Result<Option<T>, E>) -> Option<Result<T, E>> {
match r {
Ok(Some(v)) => Some(Ok(v)),
Ok(None) => None,
Err(e) => Some(Err(e)),
}
}
}
#[allow(dead_code)]
pub struct OptionProfunctor<A, B> {
run: Box<dyn Fn(A) -> Option<B>>,
}
impl<A: 'static, B: 'static> OptionProfunctor<A, B> {
#[allow(dead_code)]
pub fn new(f: impl Fn(A) -> Option<B> + 'static) -> Self {
Self { run: Box::new(f) }
}
#[allow(dead_code)]
pub fn apply(&self, a: A) -> Option<B> {
(self.run)(a)
}
#[allow(dead_code)]
pub fn dimap<C: 'static, D: 'static>(
self,
pre: impl Fn(C) -> A + 'static,
post: impl Fn(B) -> D + 'static,
) -> OptionProfunctor<C, D> {
OptionProfunctor::new(move |c| (self.run)(pre(c)).map(|b| post(b)))
}
}
#[derive(Debug, Clone, Default)]
pub struct OptionMap<K: PartialEq, V> {
entries: Vec<(K, Option<V>)>,
}
impl<K: PartialEq, V> OptionMap<K, V> {
pub fn new() -> Self {
Self {
entries: Vec::new(),
}
}
pub fn set(&mut self, key: K, value: Option<V>) {
if let Some(entry) = self.entries.iter_mut().find(|(k, _)| k == &key) {
entry.1 = value;
} else {
self.entries.push((key, value));
}
}
pub fn get(&self, key: &K) -> Option<&V> {
self.entries
.iter()
.find(|(k, _)| k == key)
.and_then(|(_, v)| v.as_ref())
}
pub fn contains_key(&self, key: &K) -> bool {
self.entries.iter().any(|(k, _)| k == key)
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn some_keys(&self) -> Vec<&K> {
self.entries
.iter()
.filter(|(_, v)| v.is_some())
.map(|(k, _)| k)
.collect()
}
pub fn none_keys(&self) -> Vec<&K> {
self.entries
.iter()
.filter(|(_, v)| v.is_none())
.map(|(k, _)| k)
.collect()
}
pub fn iter(&self) -> impl Iterator<Item = &(K, Option<V>)> {
self.entries.iter()
}
}
#[allow(dead_code)]
pub struct OptionVec<T> {
pub(super) items: Vec<Option<T>>,
}
impl<T> OptionVec<T> {
#[allow(dead_code)]
pub fn new() -> Self {
Self { items: Vec::new() }
}
#[allow(dead_code)]
pub fn push(&mut self, item: Option<T>) {
self.items.push(item);
}
#[allow(dead_code)]
pub fn sequence(self) -> Option<Vec<T>> {
let mut result = Vec::with_capacity(self.items.len());
for item in self.items {
result.push(item?);
}
Some(result)
}
#[allow(dead_code)]
pub fn collect_some(self) -> Vec<T> {
self.items.into_iter().flatten().collect()
}
#[allow(dead_code)]
pub fn count_some(&self) -> usize {
self.items.iter().filter(|o| o.is_some()).count()
}
#[allow(dead_code)]
pub fn count_none(&self) -> usize {
self.items.iter().filter(|o| o.is_none()).count()
}
#[allow(dead_code)]
pub fn len(&self) -> usize {
self.items.len()
}
#[allow(dead_code)]
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
#[allow(dead_code)]
pub fn all_some(&self) -> bool {
self.items.iter().all(|o| o.is_some())
}
#[allow(dead_code)]
pub fn any_some(&self) -> bool {
self.items.iter().any(|o| o.is_some())
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct WeightedOption<T> {
pub weight: f64,
pub value: Option<T>,
}
impl<T> WeightedOption<T> {
pub fn some(weight: f64, value: T) -> Self {
Self {
weight,
value: Some(value),
}
}
pub fn none(weight: f64) -> Self {
Self {
weight,
value: None,
}
}
pub fn better(self, other: Self) -> Self {
if self.weight >= other.weight {
self
} else {
other
}
}
}