use std::cell::OnceCell;
use std::sync::{Arc, OnceLock};
use super::functions::*;
use std::collections::VecDeque;
pub enum LazyList<A> {
Nil,
Cons(A, Box<dyn FnOnce() -> LazyList<A>>),
}
impl<A: Clone> LazyList<A> {
pub fn nil() -> Self {
LazyList::Nil
}
pub fn cons(head: A, tail: impl FnOnce() -> LazyList<A> + 'static) -> Self {
LazyList::Cons(head, Box::new(tail))
}
pub fn take(self, n: usize) -> Vec<A> {
let mut result = Vec::with_capacity(n);
let mut current = self;
while result.len() < n {
match current {
LazyList::Nil => break,
LazyList::Cons(h, t) => {
result.push(h);
current = t();
}
}
}
result
}
pub fn is_nil(&self) -> bool {
matches!(self, LazyList::Nil)
}
}
#[allow(dead_code)]
pub struct GuardedFix<A> {
cell: OnceCell<A>,
}
#[allow(dead_code)]
impl<A: Clone + 'static> GuardedFix<A> {
pub fn evaluate(step: impl Fn(Box<dyn Fn() -> A>) -> A) -> A {
let placeholder: std::cell::RefCell<Option<A>> = std::cell::RefCell::new(None);
let result = step(Box::new(move || {
placeholder
.borrow()
.clone()
.expect("guarded: value not yet available")
}));
result
}
pub fn is_computed(&self) -> bool {
self.cell.get().is_some()
}
}
pub struct Memo<A> {
pub(super) lock: OnceLock<A>,
init: Arc<dyn Fn() -> A + Send + Sync>,
}
impl<A: Send + Sync + 'static> Memo<A> {
pub fn new(f: impl Fn() -> A + Send + Sync + 'static) -> Self {
Memo {
lock: OnceLock::new(),
init: Arc::new(f),
}
}
pub fn get(&self) -> &A {
self.lock.get_or_init(|| (self.init)())
}
pub fn is_initialized(&self) -> bool {
self.lock.get().is_some()
}
}
pub struct LazyBatch<A> {
items: Vec<Deferred<A>>,
}
impl<A: 'static> LazyBatch<A> {
pub fn new() -> Self {
Self { items: Vec::new() }
}
pub fn push(mut self, item: Deferred<A>) -> Self {
self.items.push(item);
self
}
pub fn force_all(self) -> Vec<A> {
self.items.into_iter().map(|d| d.force()).collect()
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
}
pub struct MemoFn<A> {
cell: OnceCell<A>,
func: Box<dyn Fn() -> A>,
}
impl<A> MemoFn<A> {
pub fn new(f: impl Fn() -> A + 'static) -> Self {
MemoFn {
cell: OnceCell::new(),
func: Box::new(f),
}
}
pub fn get(&self) -> &A {
self.cell.get_or_init(|| (self.func)())
}
pub fn is_cached(&self) -> bool {
self.cell.get().is_some()
}
}
pub struct Deferred<A> {
inner: Box<dyn FnOnce() -> A>,
}
impl<A: 'static> Deferred<A> {
pub fn new(f: impl FnOnce() -> A + 'static) -> Self {
Deferred { inner: Box::new(f) }
}
pub fn pure(a: A) -> Self {
Deferred::new(move || a)
}
pub fn force(self) -> A {
(self.inner)()
}
pub fn map<B: 'static>(self, f: impl FnOnce(A) -> B + 'static) -> Deferred<B> {
Deferred::new(move || f(self.force()))
}
pub fn bind<B: 'static>(self, f: impl FnOnce(A) -> Deferred<B> + 'static) -> Deferred<B> {
Deferred::new(move || f(self.force()).force())
}
pub fn zip<B: 'static>(self, other: Deferred<B>) -> Deferred<(A, B)> {
Deferred::new(move || (self.force(), other.force()))
}
}
#[allow(dead_code)]
pub struct LazyStateMachineRs<S, I> {
state: Deferred<S>,
transition: Arc<dyn Fn(S, I) -> S + Send + Sync>,
}
#[allow(dead_code)]
impl<S: Clone + 'static, I: 'static> LazyStateMachineRs<S, I> {
pub fn new(initial: S, transition: impl Fn(S, I) -> S + Send + Sync + 'static) -> Self {
Self {
state: Deferred::pure(initial),
transition: Arc::new(transition),
}
}
pub fn step(self, input: I) -> Self {
let t = self.transition.clone();
let t2 = t.clone();
let new_state = self.state.map(move |s| t(s, input));
Self {
state: new_state,
transition: t2,
}
}
pub fn current_state(self) -> S {
self.state.force()
}
}
#[allow(dead_code)]
pub struct LazyWindowRs<T> {
buf: std::collections::VecDeque<Deferred<T>>,
capacity: usize,
}
#[allow(dead_code)]
impl<T: 'static> LazyWindowRs<T> {
pub fn new(capacity: usize) -> Self {
Self {
buf: std::collections::VecDeque::with_capacity(capacity),
capacity,
}
}
pub fn push(&mut self, val: Deferred<T>) {
if self.buf.len() == self.capacity {
self.buf.pop_front();
}
self.buf.push_back(val);
}
pub fn force_all(self) -> Vec<T> {
self.buf.into_iter().map(|d| d.force()).collect()
}
pub fn len(&self) -> usize {
self.buf.len()
}
pub fn is_empty(&self) -> bool {
self.buf.is_empty()
}
pub fn capacity(&self) -> usize {
self.capacity
}
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CoNatRs {
Finite(u64),
Infinity,
}
#[allow(dead_code)]
impl CoNatRs {
pub fn zero() -> Self {
CoNatRs::Finite(0)
}
pub fn succ(self) -> Self {
match self {
CoNatRs::Finite(n) => CoNatRs::Finite(n + 1),
CoNatRs::Infinity => CoNatRs::Infinity,
}
}
pub fn is_zero(&self) -> bool {
matches!(self, CoNatRs::Finite(0))
}
pub fn is_infinity(&self) -> bool {
matches!(self, CoNatRs::Infinity)
}
pub fn to_finite(self) -> Option<u64> {
match self {
CoNatRs::Finite(n) => Some(n),
CoNatRs::Infinity => None,
}
}
pub fn add(self, other: CoNatRs) -> CoNatRs {
match (self, other) {
(CoNatRs::Infinity, _) | (_, CoNatRs::Infinity) => CoNatRs::Infinity,
(CoNatRs::Finite(a), CoNatRs::Finite(b)) => CoNatRs::Finite(a + b),
}
}
pub fn min(self, other: CoNatRs) -> CoNatRs {
match (self, other) {
(CoNatRs::Finite(a), CoNatRs::Finite(b)) => CoNatRs::Finite(a.min(b)),
(CoNatRs::Infinity, x) | (x, CoNatRs::Infinity) => x,
}
}
}
pub enum LazyOption<A> {
None,
Some(Deferred<A>),
}
impl<A: 'static> LazyOption<A> {
pub fn none() -> Self {
LazyOption::None
}
pub fn some(f: impl FnOnce() -> A + 'static) -> Self {
LazyOption::Some(Deferred::new(f))
}
pub fn pure(a: A) -> Self {
LazyOption::Some(Deferred::pure(a))
}
pub fn is_none(&self) -> bool {
matches!(self, LazyOption::None)
}
pub fn force(self) -> Option<A> {
match self {
LazyOption::None => None,
LazyOption::Some(d) => Some(d.force()),
}
}
pub fn map<B: 'static>(self, f: impl FnOnce(A) -> B + 'static) -> LazyOption<B> {
match self {
LazyOption::None => LazyOption::None,
LazyOption::Some(d) => LazyOption::Some(d.map(f)),
}
}
}
#[allow(dead_code)]
pub enum DelayRs<A> {
Now(A),
Later(Box<dyn FnOnce() -> DelayRs<A>>),
}
#[allow(dead_code)]
impl<A: 'static> DelayRs<A> {
pub fn now(a: A) -> Self {
DelayRs::Now(a)
}
pub fn later(f: impl FnOnce() -> DelayRs<A> + 'static) -> Self {
DelayRs::Later(Box::new(f))
}
pub fn run(self, fuel: usize) -> Option<A> {
let mut current = self;
let mut remaining = fuel;
loop {
match current {
DelayRs::Now(a) => return Some(a),
DelayRs::Later(f) => {
if remaining == 0 {
return None;
}
remaining -= 1;
current = f();
}
}
}
}
pub fn map<B: 'static>(self, f: impl FnOnce(A) -> B + 'static) -> DelayRs<B> {
match self {
DelayRs::Now(a) => DelayRs::Now(f(a)),
DelayRs::Later(g) => DelayRs::later(move || g().map(f)),
}
}
pub fn bind<B: 'static>(self, f: impl FnOnce(A) -> DelayRs<B> + 'static) -> DelayRs<B> {
match self {
DelayRs::Now(a) => f(a),
DelayRs::Later(g) => DelayRs::later(move || g().bind(f)),
}
}
}
pub struct LazyPair<A, B> {
first: Deferred<A>,
second: Deferred<B>,
}
impl<A: 'static, B: 'static> LazyPair<A, B> {
pub fn new(a: Deferred<A>, b: Deferred<B>) -> Self {
Self {
first: a,
second: b,
}
}
pub fn force(self) -> (A, B) {
(self.first.force(), self.second.force())
}
pub fn map_first<C: 'static>(self, f: impl FnOnce(A) -> C + 'static) -> LazyPair<C, B> {
LazyPair {
first: self.first.map(f),
second: self.second,
}
}
pub fn map_second<C: 'static>(self, f: impl FnOnce(B) -> C + 'static) -> LazyPair<A, C> {
LazyPair {
first: self.first,
second: self.second.map(f),
}
}
}
pub struct Thunk<A> {
pub(super) cell: OnceCell<A>,
init: Option<Box<dyn FnOnce() -> A>>,
}
impl<A> Thunk<A> {
pub fn new(f: impl FnOnce() -> A + 'static) -> Self {
Thunk {
cell: OnceCell::new(),
init: Some(Box::new(f)),
}
}
pub fn evaluated(a: A) -> Self {
let cell = OnceCell::new();
let _ = cell.set(a);
Thunk { cell, init: None }
}
pub fn force(&mut self) -> &A {
if self.cell.get().is_none() {
if let Some(f) = self.init.take() {
let _ = self.cell.set(f());
}
}
self.cell.get().expect("thunk init failed")
}
pub fn is_evaluated(&self) -> bool {
self.cell.get().is_some()
}
}