Skip to main content

oxilean_std/lazy/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use std::cell::OnceCell;
6use std::sync::{Arc, OnceLock};
7
8use super::functions::*;
9use std::collections::VecDeque;
10
11/// A lazy list (stream) node — a potentially infinite structure.
12pub enum LazyList<A> {
13    /// The empty stream.
14    Nil,
15    /// A head element and a deferred tail.
16    Cons(A, Box<dyn FnOnce() -> LazyList<A>>),
17}
18impl<A: Clone> LazyList<A> {
19    /// Create a `Nil` stream.
20    pub fn nil() -> Self {
21        LazyList::Nil
22    }
23    /// Create a `Cons` node.
24    pub fn cons(head: A, tail: impl FnOnce() -> LazyList<A> + 'static) -> Self {
25        LazyList::Cons(head, Box::new(tail))
26    }
27    /// Force the stream and collect the first `n` elements.
28    pub fn take(self, n: usize) -> Vec<A> {
29        let mut result = Vec::with_capacity(n);
30        let mut current = self;
31        while result.len() < n {
32            match current {
33                LazyList::Nil => break,
34                LazyList::Cons(h, t) => {
35                    result.push(h);
36                    current = t();
37                }
38            }
39        }
40        result
41    }
42    /// Check if the stream is empty.
43    pub fn is_nil(&self) -> bool {
44        matches!(self, LazyList::Nil)
45    }
46}
47/// A guarded recursive definition builder.
48///
49/// Implements Löb's principle: if we can build `A` assuming we already have
50/// a `â–¶A` (a "later" version), then we can produce `A` unconditionally.
51#[allow(dead_code)]
52pub struct GuardedFix<A> {
53    cell: OnceCell<A>,
54}
55#[allow(dead_code)]
56impl<A: Clone + 'static> GuardedFix<A> {
57    /// Create a guarded fixpoint by providing a step function.
58    ///
59    /// The step function receives a thunk for the recursive call.
60    pub fn evaluate(step: impl Fn(Box<dyn Fn() -> A>) -> A) -> A {
61        let placeholder: std::cell::RefCell<Option<A>> = std::cell::RefCell::new(None);
62        let result = step(Box::new(move || {
63            placeholder
64                .borrow()
65                .clone()
66                .expect("guarded: value not yet available")
67        }));
68        result
69    }
70    /// Check if the cell has been forced.
71    pub fn is_computed(&self) -> bool {
72        self.cell.get().is_some()
73    }
74}
75/// A thread-safe memoized value. The computation runs exactly once across threads.
76pub struct Memo<A> {
77    pub(super) lock: OnceLock<A>,
78    init: Arc<dyn Fn() -> A + Send + Sync>,
79}
80impl<A: Send + Sync + 'static> Memo<A> {
81    /// Create a new `Memo` with a given initialization function.
82    pub fn new(f: impl Fn() -> A + Send + Sync + 'static) -> Self {
83        Memo {
84            lock: OnceLock::new(),
85            init: Arc::new(f),
86        }
87    }
88    /// Get the memoized value, computing it if necessary.
89    pub fn get(&self) -> &A {
90        self.lock.get_or_init(|| (self.init)())
91    }
92    /// Return true if already computed.
93    pub fn is_initialized(&self) -> bool {
94        self.lock.get().is_some()
95    }
96}
97/// A batched lazy evaluator that processes multiple `Deferred<A>` values.
98///
99/// Useful when you have a list of deferred computations and want to force
100/// them all at once in a controlled manner.
101pub struct LazyBatch<A> {
102    items: Vec<Deferred<A>>,
103}
104impl<A: 'static> LazyBatch<A> {
105    /// Create an empty batch.
106    pub fn new() -> Self {
107        Self { items: Vec::new() }
108    }
109    /// Add a deferred item to the batch.
110    pub fn push(mut self, item: Deferred<A>) -> Self {
111        self.items.push(item);
112        self
113    }
114    /// Force all items and collect results.
115    pub fn force_all(self) -> Vec<A> {
116        self.items.into_iter().map(|d| d.force()).collect()
117    }
118    /// Return the number of items in the batch.
119    pub fn len(&self) -> usize {
120        self.items.len()
121    }
122    /// Check if the batch is empty.
123    pub fn is_empty(&self) -> bool {
124        self.items.is_empty()
125    }
126}
127/// A memoized function: wraps a computation and caches the result for each call.
128/// Useful when the same lazy value is referenced multiple times.
129pub struct MemoFn<A> {
130    cell: OnceCell<A>,
131    func: Box<dyn Fn() -> A>,
132}
133impl<A> MemoFn<A> {
134    /// Create a new `MemoFn`.
135    pub fn new(f: impl Fn() -> A + 'static) -> Self {
136        MemoFn {
137            cell: OnceCell::new(),
138            func: Box::new(f),
139        }
140    }
141    /// Get the memoized result, computing it on first call.
142    pub fn get(&self) -> &A {
143        self.cell.get_or_init(|| (self.func)())
144    }
145    /// Return true if already computed.
146    pub fn is_cached(&self) -> bool {
147        self.cell.get().is_some()
148    }
149}
150/// A deferred value that is computed from another lazy value.
151pub struct Deferred<A> {
152    inner: Box<dyn FnOnce() -> A>,
153}
154impl<A: 'static> Deferred<A> {
155    /// Defer a computation.
156    pub fn new(f: impl FnOnce() -> A + 'static) -> Self {
157        Deferred { inner: Box::new(f) }
158    }
159    /// Lift a value into `Deferred`.
160    pub fn pure(a: A) -> Self {
161        Deferred::new(move || a)
162    }
163    /// Force the deferred value.
164    pub fn force(self) -> A {
165        (self.inner)()
166    }
167    /// Map over the deferred value (still lazy).
168    pub fn map<B: 'static>(self, f: impl FnOnce(A) -> B + 'static) -> Deferred<B> {
169        Deferred::new(move || f(self.force()))
170    }
171    /// Bind: flat-map over a deferred value.
172    pub fn bind<B: 'static>(self, f: impl FnOnce(A) -> Deferred<B> + 'static) -> Deferred<B> {
173        Deferred::new(move || f(self.force()).force())
174    }
175    /// Zip two deferred values into a pair (still lazy).
176    pub fn zip<B: 'static>(self, other: Deferred<B>) -> Deferred<(A, B)> {
177        Deferred::new(move || (self.force(), other.force()))
178    }
179}
180/// A lazy state machine that transitions lazily.
181///
182/// Each transition is deferred until the state is actually needed.
183#[allow(dead_code)]
184pub struct LazyStateMachineRs<S, I> {
185    /// Current state (lazily wrapped).
186    state: Deferred<S>,
187    /// Transition function.
188    transition: Arc<dyn Fn(S, I) -> S + Send + Sync>,
189}
190#[allow(dead_code)]
191impl<S: Clone + 'static, I: 'static> LazyStateMachineRs<S, I> {
192    /// Create a new lazy state machine.
193    pub fn new(initial: S, transition: impl Fn(S, I) -> S + Send + Sync + 'static) -> Self {
194        Self {
195            state: Deferred::pure(initial),
196            transition: Arc::new(transition),
197        }
198    }
199    /// Perform a lazy transition with the given input.
200    pub fn step(self, input: I) -> Self {
201        let t = self.transition.clone();
202        let t2 = t.clone();
203        let new_state = self.state.map(move |s| t(s, input));
204        Self {
205            state: new_state,
206            transition: t2,
207        }
208    }
209    /// Force the current state.
210    pub fn current_state(self) -> S {
211        self.state.force()
212    }
213}
214/// A circular buffer implementing a sliding window over lazy streams.
215///
216/// Used for stream algorithms requiring recent history access.
217#[allow(dead_code)]
218pub struct LazyWindowRs<T> {
219    buf: std::collections::VecDeque<Deferred<T>>,
220    capacity: usize,
221}
222#[allow(dead_code)]
223impl<T: 'static> LazyWindowRs<T> {
224    /// Create a new lazy window with the given capacity.
225    pub fn new(capacity: usize) -> Self {
226        Self {
227            buf: std::collections::VecDeque::with_capacity(capacity),
228            capacity,
229        }
230    }
231    /// Push a deferred value into the window.
232    pub fn push(&mut self, val: Deferred<T>) {
233        if self.buf.len() == self.capacity {
234            self.buf.pop_front();
235        }
236        self.buf.push_back(val);
237    }
238    /// Force all values in the window.
239    pub fn force_all(self) -> Vec<T> {
240        self.buf.into_iter().map(|d| d.force()).collect()
241    }
242    /// Return the current number of elements in the window.
243    pub fn len(&self) -> usize {
244        self.buf.len()
245    }
246    /// Return true if the window is empty.
247    pub fn is_empty(&self) -> bool {
248        self.buf.is_empty()
249    }
250    /// Return the window capacity.
251    pub fn capacity(&self) -> usize {
252        self.capacity
253    }
254}
255/// A lazy natural number (conatural number) represented in Rust.
256///
257/// Can be either finite (a concrete `u64`) or infinite.
258#[allow(dead_code)]
259#[derive(Debug, Clone, PartialEq, Eq)]
260pub enum CoNatRs {
261    /// A finite conatural number.
262    Finite(u64),
263    /// The infinite conatural number (ω).
264    Infinity,
265}
266#[allow(dead_code)]
267impl CoNatRs {
268    /// The zero conatural number.
269    pub fn zero() -> Self {
270        CoNatRs::Finite(0)
271    }
272    /// The successor of a conatural number.
273    pub fn succ(self) -> Self {
274        match self {
275            CoNatRs::Finite(n) => CoNatRs::Finite(n + 1),
276            CoNatRs::Infinity => CoNatRs::Infinity,
277        }
278    }
279    /// Check if zero.
280    pub fn is_zero(&self) -> bool {
281        matches!(self, CoNatRs::Finite(0))
282    }
283    /// Check if infinite.
284    pub fn is_infinity(&self) -> bool {
285        matches!(self, CoNatRs::Infinity)
286    }
287    /// Convert to Option<u64>.
288    pub fn to_finite(self) -> Option<u64> {
289        match self {
290            CoNatRs::Finite(n) => Some(n),
291            CoNatRs::Infinity => None,
292        }
293    }
294    /// Add two conatural numbers.
295    pub fn add(self, other: CoNatRs) -> CoNatRs {
296        match (self, other) {
297            (CoNatRs::Infinity, _) | (_, CoNatRs::Infinity) => CoNatRs::Infinity,
298            (CoNatRs::Finite(a), CoNatRs::Finite(b)) => CoNatRs::Finite(a + b),
299        }
300    }
301    /// Minimum of two conatural numbers.
302    pub fn min(self, other: CoNatRs) -> CoNatRs {
303        match (self, other) {
304            (CoNatRs::Finite(a), CoNatRs::Finite(b)) => CoNatRs::Finite(a.min(b)),
305            (CoNatRs::Infinity, x) | (x, CoNatRs::Infinity) => x,
306        }
307    }
308}
309/// A `LazyOption<A>` wraps a potentially-absent lazy value.
310pub enum LazyOption<A> {
311    /// No value.
312    None,
313    /// A deferred value.
314    Some(Deferred<A>),
315}
316impl<A: 'static> LazyOption<A> {
317    /// Return the `None` variant.
318    pub fn none() -> Self {
319        LazyOption::None
320    }
321    /// Wrap a deferred computation.
322    pub fn some(f: impl FnOnce() -> A + 'static) -> Self {
323        LazyOption::Some(Deferred::new(f))
324    }
325    /// Lift an eager value.
326    pub fn pure(a: A) -> Self {
327        LazyOption::Some(Deferred::pure(a))
328    }
329    /// Return true if this is `None`.
330    pub fn is_none(&self) -> bool {
331        matches!(self, LazyOption::None)
332    }
333    /// Force into `Option<A>`.
334    pub fn force(self) -> Option<A> {
335        match self {
336            LazyOption::None => None,
337            LazyOption::Some(d) => Some(d.force()),
338        }
339    }
340    /// Map over the lazy option.
341    pub fn map<B: 'static>(self, f: impl FnOnce(A) -> B + 'static) -> LazyOption<B> {
342        match self {
343            LazyOption::None => LazyOption::None,
344            LazyOption::Some(d) => LazyOption::Some(d.map(f)),
345        }
346    }
347}
348/// A delay monad value in Rust: either immediately available or delayed.
349///
350/// Models the partiality / delay monad for potentially non-terminating computations.
351#[allow(dead_code)]
352pub enum DelayRs<A> {
353    /// The value is available now.
354    Now(A),
355    /// The computation needs one more step.
356    Later(Box<dyn FnOnce() -> DelayRs<A>>),
357}
358#[allow(dead_code)]
359impl<A: 'static> DelayRs<A> {
360    /// Inject a value immediately.
361    pub fn now(a: A) -> Self {
362        DelayRs::Now(a)
363    }
364    /// Delay by one step.
365    pub fn later(f: impl FnOnce() -> DelayRs<A> + 'static) -> Self {
366        DelayRs::Later(Box::new(f))
367    }
368    /// Force the computation, running at most `fuel` steps.
369    pub fn run(self, fuel: usize) -> Option<A> {
370        let mut current = self;
371        let mut remaining = fuel;
372        loop {
373            match current {
374                DelayRs::Now(a) => return Some(a),
375                DelayRs::Later(f) => {
376                    if remaining == 0 {
377                        return None;
378                    }
379                    remaining -= 1;
380                    current = f();
381                }
382            }
383        }
384    }
385    /// Map over a delayed value.
386    pub fn map<B: 'static>(self, f: impl FnOnce(A) -> B + 'static) -> DelayRs<B> {
387        match self {
388            DelayRs::Now(a) => DelayRs::Now(f(a)),
389            DelayRs::Later(g) => DelayRs::later(move || g().map(f)),
390        }
391    }
392    /// Bind over a delayed value.
393    pub fn bind<B: 'static>(self, f: impl FnOnce(A) -> DelayRs<B> + 'static) -> DelayRs<B> {
394        match self {
395            DelayRs::Now(a) => f(a),
396            DelayRs::Later(g) => DelayRs::later(move || g().bind(f)),
397        }
398    }
399}
400/// A pair of deferred computations.
401pub struct LazyPair<A, B> {
402    first: Deferred<A>,
403    second: Deferred<B>,
404}
405impl<A: 'static, B: 'static> LazyPair<A, B> {
406    /// Create a new lazy pair.
407    pub fn new(a: Deferred<A>, b: Deferred<B>) -> Self {
408        Self {
409            first: a,
410            second: b,
411        }
412    }
413    /// Force both elements.
414    pub fn force(self) -> (A, B) {
415        (self.first.force(), self.second.force())
416    }
417    /// Map over the first element.
418    pub fn map_first<C: 'static>(self, f: impl FnOnce(A) -> C + 'static) -> LazyPair<C, B> {
419        LazyPair {
420            first: self.first.map(f),
421            second: self.second,
422        }
423    }
424    /// Map over the second element.
425    pub fn map_second<C: 'static>(self, f: impl FnOnce(B) -> C + 'static) -> LazyPair<A, C> {
426        LazyPair {
427            first: self.first,
428            second: self.second.map(f),
429        }
430    }
431}
432/// A `Thunk<A>` is a lazily-evaluated value: the computation runs at most once.
433pub struct Thunk<A> {
434    pub(super) cell: OnceCell<A>,
435    init: Option<Box<dyn FnOnce() -> A>>,
436}
437impl<A> Thunk<A> {
438    /// Create a new thunk wrapping a deferred computation.
439    pub fn new(f: impl FnOnce() -> A + 'static) -> Self {
440        Thunk {
441            cell: OnceCell::new(),
442            init: Some(Box::new(f)),
443        }
444    }
445    /// Create an already-evaluated thunk.
446    pub fn evaluated(a: A) -> Self {
447        let cell = OnceCell::new();
448        let _ = cell.set(a);
449        Thunk { cell, init: None }
450    }
451    /// Force the thunk: run the computation if not yet evaluated.
452    pub fn force(&mut self) -> &A {
453        if self.cell.get().is_none() {
454            if let Some(f) = self.init.take() {
455                let _ = self.cell.set(f());
456            }
457        }
458        self.cell.get().expect("thunk init failed")
459    }
460    /// Return true if the thunk has already been forced.
461    pub fn is_evaluated(&self) -> bool {
462        self.cell.get().is_some()
463    }
464}