Skip to main content

oxilean_std/option/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use super::functions::*;
6use std::collections::HashMap;
7
8/// OptionComonad represents a comonadic structure for Option with a fixed default.
9#[allow(dead_code)]
10pub struct OptionComonad<T: Clone> {
11    value: Option<T>,
12    default: T,
13}
14impl<T: Clone> OptionComonad<T> {
15    #[allow(dead_code)]
16    pub fn new(value: Option<T>, default: T) -> Self {
17        Self { value, default }
18    }
19    /// extract: comonadic extract (returns default if None).
20    #[allow(dead_code)]
21    pub fn extract(&self) -> T {
22        self.value.clone().unwrap_or_else(|| self.default.clone())
23    }
24    /// extend: comonadic extend.
25    #[allow(dead_code)]
26    pub fn extend<B: Clone>(&self, f: impl Fn(&OptionComonad<T>) -> B) -> Option<B> {
27        Some(f(self))
28    }
29    #[allow(dead_code)]
30    pub fn duplicate_as_pair(&self) -> (T, Option<T>) {
31        (self.default.clone(), self.value.clone())
32    }
33}
34/// Memoizing wrapper around a function returning `Option<T>`.
35///
36/// Caches computed results to avoid recomputing them.
37#[allow(dead_code)]
38pub struct OptionMemo<K: std::hash::Hash + Eq, V: Clone> {
39    cache: std::collections::HashMap<K, Option<V>>,
40}
41impl<K: std::hash::Hash + Eq, V: Clone> OptionMemo<K, V> {
42    /// Create an empty memo table.
43    #[allow(dead_code)]
44    pub fn new() -> Self {
45        Self {
46            cache: std::collections::HashMap::new(),
47        }
48    }
49    /// Get the memoized result for `key`, computing it with `f` if necessary.
50    #[allow(dead_code)]
51    pub fn get_or_compute(&mut self, key: K, f: impl FnOnce(&K) -> Option<V>) -> Option<V>
52    where
53        K: Clone,
54    {
55        if let Some(v) = self.cache.get(&key) {
56            return v.clone();
57        }
58        let v = f(&key);
59        self.cache.insert(key, v.clone());
60        v
61    }
62    /// Clear the memo table.
63    #[allow(dead_code)]
64    pub fn clear(&mut self) {
65        self.cache.clear();
66    }
67    /// Number of memoized entries.
68    #[allow(dead_code)]
69    pub fn len(&self) -> usize {
70        self.cache.len()
71    }
72    /// Check if empty.
73    #[allow(dead_code)]
74    pub fn is_empty(&self) -> bool {
75        self.cache.is_empty()
76    }
77}
78/// An iterator that yields the value inside `Some` once, or nothing for `None`.
79#[allow(dead_code)]
80pub struct OptionIter<T>(pub(super) Option<T>);
81impl<T> OptionIter<T> {
82    /// Create an iterator from an option.
83    #[allow(dead_code)]
84    pub fn new(opt: Option<T>) -> Self {
85        Self(opt)
86    }
87}
88/// OptionFunctor provides a functor over Option values.
89#[allow(dead_code)]
90pub struct OptionFunctor<T>(pub Option<T>);
91impl<T> OptionFunctor<T> {
92    #[allow(dead_code)]
93    pub fn new(v: Option<T>) -> Self {
94        Self(v)
95    }
96    #[allow(dead_code)]
97    pub fn fmap<U>(self, f: impl FnOnce(T) -> U) -> OptionFunctor<U> {
98        OptionFunctor(self.0.map(f))
99    }
100    #[allow(dead_code)]
101    pub fn fmap_id(self) -> OptionFunctor<T> {
102        OptionFunctor(self.0)
103    }
104    #[allow(dead_code)]
105    pub fn inner(self) -> Option<T> {
106        self.0
107    }
108}
109/// OptionApplicative provides applicative structure over Option values.
110#[allow(dead_code)]
111pub struct OptionApplicative;
112impl OptionApplicative {
113    #[allow(dead_code)]
114    pub fn pure<T>(v: T) -> Option<T> {
115        Some(v)
116    }
117    #[allow(dead_code)]
118    pub fn ap<A, B>(f: Option<impl FnOnce(A) -> B>, a: Option<A>) -> Option<B> {
119        match (f, a) {
120            (Some(func), Some(val)) => Some(func(val)),
121            _ => None,
122        }
123    }
124    #[allow(dead_code)]
125    pub fn lift_a2<A, B, C>(f: impl FnOnce(A, B) -> C, a: Option<A>, b: Option<B>) -> Option<C> {
126        match (a, b) {
127            (Some(x), Some(y)) => Some(f(x, y)),
128            _ => None,
129        }
130    }
131}
132/// A simple cache mapping keys to optional computed values.
133///
134/// If a key is present and `Some`, the cached value is returned.
135/// If a key is absent, the computation is run and cached.
136#[derive(Debug, Clone, Default)]
137pub struct OptionCache<K: PartialEq, V> {
138    entries: Vec<(K, Option<V>)>,
139}
140impl<K: PartialEq, V: Clone> OptionCache<K, V> {
141    /// Create an empty cache.
142    pub fn new() -> Self {
143        Self {
144            entries: Vec::new(),
145        }
146    }
147    /// Get or compute a value for `key`.
148    ///
149    /// If the key is already cached, returns the cached value.
150    /// Otherwise runs `compute` and caches the result.
151    pub fn get_or_insert_with(&mut self, key: K, compute: impl FnOnce() -> Option<V>) -> Option<V>
152    where
153        K: Clone,
154    {
155        if let Some(entry) = self.entries.iter().find(|(k, _)| k == &key) {
156            return entry.1.clone();
157        }
158        let value = compute();
159        self.entries.push((key, value.clone()));
160        value
161    }
162    /// Explicitly insert a value for a key.
163    pub fn insert(&mut self, key: K, value: Option<V>)
164    where
165        K: Clone,
166        V: Clone,
167    {
168        if let Some(entry) = self.entries.iter_mut().find(|(k, _)| k == &key) {
169            entry.1 = value;
170        } else {
171            self.entries.push((key, value));
172        }
173    }
174    /// Look up a cached value.
175    pub fn get(&self, key: &K) -> Option<Option<&V>> {
176        self.entries
177            .iter()
178            .find(|(k, _)| k == key)
179            .map(|(_, v)| v.as_ref())
180    }
181    /// Invalidate (remove) an entry.
182    pub fn invalidate(&mut self, key: &K) {
183        self.entries.retain(|(k, _)| k != key);
184    }
185    /// Clear the entire cache.
186    pub fn clear(&mut self) {
187        self.entries.clear();
188    }
189    /// Number of cached entries.
190    pub fn len(&self) -> usize {
191        self.entries.len()
192    }
193    /// Returns `true` if the cache is empty.
194    pub fn is_empty(&self) -> bool {
195        self.entries.is_empty()
196    }
197}
198/// A builder-style wrapper for chaining option operations.
199///
200/// Provides a fluent API for building complex option expressions.
201#[allow(dead_code)]
202pub struct OptionChain<T> {
203    value: Option<T>,
204}
205impl<T> OptionChain<T> {
206    /// Start a chain from an option value.
207    #[allow(dead_code)]
208    pub fn from(opt: Option<T>) -> Self {
209        Self { value: opt }
210    }
211    /// Start a chain from a value (wraps in Some).
212    #[allow(dead_code)]
213    pub fn of(v: T) -> Self {
214        Self { value: Some(v) }
215    }
216    /// Start an empty chain.
217    #[allow(dead_code)]
218    pub fn empty() -> Self {
219        Self { value: None }
220    }
221    /// Apply a map operation.
222    #[allow(dead_code)]
223    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> OptionChain<U> {
224        OptionChain {
225            value: self.value.map(f),
226        }
227    }
228    /// Apply a flatmap operation.
229    #[allow(dead_code)]
230    pub fn flat_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> OptionChain<U> {
231        OptionChain {
232            value: self.value.and_then(f),
233        }
234    }
235    /// Apply a filter operation.
236    #[allow(dead_code)]
237    pub fn filter(self, pred: impl FnOnce(&T) -> bool) -> Self {
238        Self {
239            value: self.value.filter(pred),
240        }
241    }
242    /// Provide a fallback value.
243    #[allow(dead_code)]
244    pub fn or_else(self, fallback: Option<T>) -> Self {
245        Self {
246            value: self.value.or(fallback),
247        }
248    }
249    /// Extract the final value.
250    #[allow(dead_code)]
251    pub fn get(self) -> Option<T> {
252        self.value
253    }
254    /// Extract with a default.
255    #[allow(dead_code)]
256    pub fn get_or(self, default: T) -> T {
257        self.value.unwrap_or(default)
258    }
259    /// Check if this chain has a value.
260    #[allow(dead_code)]
261    pub fn is_present(&self) -> bool {
262        self.value.is_some()
263    }
264    /// Peek at the inner value without consuming.
265    #[allow(dead_code)]
266    pub fn peek(&self) -> Option<&T> {
267        self.value.as_ref()
268    }
269}
270/// OptionWriter pairs an Option value with an accumulated log/writer monad value.
271#[allow(dead_code)]
272pub struct OptionWriter<T, W> {
273    value: Option<T>,
274    log: W,
275}
276impl<T, W: Default> OptionWriter<T, W> {
277    #[allow(dead_code)]
278    pub fn new(value: Option<T>, log: W) -> Self {
279        Self { value, log }
280    }
281    #[allow(dead_code)]
282    pub fn pure_some(value: T) -> Self {
283        Self {
284            value: Some(value),
285            log: W::default(),
286        }
287    }
288    #[allow(dead_code)]
289    pub fn none_with_log(log: W) -> Self {
290        Self { value: None, log }
291    }
292    #[allow(dead_code)]
293    pub fn is_some(&self) -> bool {
294        self.value.is_some()
295    }
296}
297/// Utilities for converting between Option and Result in a typed fashion.
298#[allow(dead_code)]
299pub struct OptionResultBridge;
300impl OptionResultBridge {
301    /// Convert `Option<T>` to `Result<T, E>` with a supplied error.
302    #[allow(dead_code)]
303    pub fn to_result<T, E>(opt: Option<T>, err: E) -> Result<T, E> {
304        opt.ok_or(err)
305    }
306    /// Convert `Option<T>` to `Result<T, E>` with a lazy error.
307    #[allow(dead_code)]
308    pub fn to_result_with<T, E>(opt: Option<T>, f: impl FnOnce() -> E) -> Result<T, E> {
309        opt.ok_or_else(f)
310    }
311    /// Convert `Result<T, E>` to `Option<T>`, discarding the error.
312    #[allow(dead_code)]
313    pub fn from_result_ok<T, E>(r: Result<T, E>) -> Option<T> {
314        r.ok()
315    }
316    /// Convert `Result<T, E>` to `Option<E>`, discarding the success.
317    #[allow(dead_code)]
318    pub fn from_result_err<T, E>(r: Result<T, E>) -> Option<E> {
319        r.err()
320    }
321    /// Transpose `Result<Option<T>, E>` to `Option<Result<T, E>>`.
322    #[allow(dead_code)]
323    pub fn transpose_result<T, E>(r: Result<Option<T>, E>) -> Option<Result<T, E>> {
324        match r {
325            Ok(Some(v)) => Some(Ok(v)),
326            Ok(None) => None,
327            Err(e) => Some(Err(e)),
328        }
329    }
330}
331/// OptionProfunctor represents a profunctor-shaped wrapper over Option.
332#[allow(dead_code)]
333pub struct OptionProfunctor<A, B> {
334    run: Box<dyn Fn(A) -> Option<B>>,
335}
336impl<A: 'static, B: 'static> OptionProfunctor<A, B> {
337    #[allow(dead_code)]
338    pub fn new(f: impl Fn(A) -> Option<B> + 'static) -> Self {
339        Self { run: Box::new(f) }
340    }
341    #[allow(dead_code)]
342    pub fn apply(&self, a: A) -> Option<B> {
343        (self.run)(a)
344    }
345    #[allow(dead_code)]
346    pub fn dimap<C: 'static, D: 'static>(
347        self,
348        pre: impl Fn(C) -> A + 'static,
349        post: impl Fn(B) -> D + 'static,
350    ) -> OptionProfunctor<C, D> {
351        OptionProfunctor::new(move |c| (self.run)(pre(c)).map(|b| post(b)))
352    }
353}
354/// A mapping from keys to optional values.
355///
356/// Wraps a `Vec<(K, Option<V>)>` and provides convenient access methods.
357#[derive(Debug, Clone, Default)]
358pub struct OptionMap<K: PartialEq, V> {
359    entries: Vec<(K, Option<V>)>,
360}
361impl<K: PartialEq, V> OptionMap<K, V> {
362    /// Create an empty `OptionMap`.
363    pub fn new() -> Self {
364        Self {
365            entries: Vec::new(),
366        }
367    }
368    /// Set the value for `key` (may be `None` to mark as missing).
369    pub fn set(&mut self, key: K, value: Option<V>) {
370        if let Some(entry) = self.entries.iter_mut().find(|(k, _)| k == &key) {
371            entry.1 = value;
372        } else {
373            self.entries.push((key, value));
374        }
375    }
376    /// Get the value for `key`, or `None` if not present or explicitly set to `None`.
377    pub fn get(&self, key: &K) -> Option<&V> {
378        self.entries
379            .iter()
380            .find(|(k, _)| k == key)
381            .and_then(|(_, v)| v.as_ref())
382    }
383    /// Returns `true` if the key exists (even if mapped to `None`).
384    pub fn contains_key(&self, key: &K) -> bool {
385        self.entries.iter().any(|(k, _)| k == key)
386    }
387    /// Number of entries.
388    pub fn len(&self) -> usize {
389        self.entries.len()
390    }
391    /// Returns `true` if empty.
392    pub fn is_empty(&self) -> bool {
393        self.entries.is_empty()
394    }
395    /// Collect all keys with `Some` values.
396    pub fn some_keys(&self) -> Vec<&K> {
397        self.entries
398            .iter()
399            .filter(|(_, v)| v.is_some())
400            .map(|(k, _)| k)
401            .collect()
402    }
403    /// Collect all keys with `None` values.
404    pub fn none_keys(&self) -> Vec<&K> {
405        self.entries
406            .iter()
407            .filter(|(_, v)| v.is_none())
408            .map(|(k, _)| k)
409            .collect()
410    }
411    /// Iterate over all entries.
412    pub fn iter(&self) -> impl Iterator<Item = &(K, Option<V>)> {
413        self.entries.iter()
414    }
415}
416/// A collection of option values with batch operations.
417#[allow(dead_code)]
418pub struct OptionVec<T> {
419    pub(super) items: Vec<Option<T>>,
420}
421impl<T> OptionVec<T> {
422    /// Create a new OptionVec.
423    #[allow(dead_code)]
424    pub fn new() -> Self {
425        Self { items: Vec::new() }
426    }
427    /// Push an option.
428    #[allow(dead_code)]
429    pub fn push(&mut self, item: Option<T>) {
430        self.items.push(item);
431    }
432    /// Sequence: succeed only if all are Some.
433    #[allow(dead_code)]
434    pub fn sequence(self) -> Option<Vec<T>> {
435        let mut result = Vec::with_capacity(self.items.len());
436        for item in self.items {
437            result.push(item?);
438        }
439        Some(result)
440    }
441    /// Collect only the Some values.
442    #[allow(dead_code)]
443    pub fn collect_some(self) -> Vec<T> {
444        self.items.into_iter().flatten().collect()
445    }
446    /// Count the Some values.
447    #[allow(dead_code)]
448    pub fn count_some(&self) -> usize {
449        self.items.iter().filter(|o| o.is_some()).count()
450    }
451    /// Count the None values.
452    #[allow(dead_code)]
453    pub fn count_none(&self) -> usize {
454        self.items.iter().filter(|o| o.is_none()).count()
455    }
456    /// Total number of items.
457    #[allow(dead_code)]
458    pub fn len(&self) -> usize {
459        self.items.len()
460    }
461    /// True if empty.
462    #[allow(dead_code)]
463    pub fn is_empty(&self) -> bool {
464        self.items.is_empty()
465    }
466    /// True if all items are Some.
467    #[allow(dead_code)]
468    pub fn all_some(&self) -> bool {
469        self.items.iter().all(|o| o.is_some())
470    }
471    /// True if any item is Some.
472    #[allow(dead_code)]
473    pub fn any_some(&self) -> bool {
474        self.items.iter().any(|o| o.is_some())
475    }
476}
477/// An option value tagged with a weight (used for ranked alternatives).
478#[derive(Debug, Clone, PartialEq)]
479pub struct WeightedOption<T> {
480    /// The weight (higher is better).
481    pub weight: f64,
482    /// The value, if present.
483    pub value: Option<T>,
484}
485impl<T> WeightedOption<T> {
486    /// Create a `WeightedOption` with a value.
487    pub fn some(weight: f64, value: T) -> Self {
488        Self {
489            weight,
490            value: Some(value),
491        }
492    }
493    /// Create a `WeightedOption` with no value.
494    pub fn none(weight: f64) -> Self {
495        Self {
496            weight,
497            value: None,
498        }
499    }
500    /// Select the higher-weight option.
501    pub fn better(self, other: Self) -> Self {
502        if self.weight >= other.weight {
503            self
504        } else {
505            other
506        }
507    }
508}