first commit

This commit is contained in:
aaron-jack-manning 2022-06-17 22:01:01 +10:00
commit 1979161431
5 changed files with 264 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

7
Cargo.lock generated Normal file
View File

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "lazy-seq"
version = "0.1.0"

8
Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "lazy-seq"
version = "0.1.0"
edition = "2021"
description = "A crate for constructing lazily evaluated sequences."
license = "MIT OR Apache-2.0"
[dependencies]

3
README.md Normal file
View File

@ -0,0 +1,3 @@
# Lazy Seq
This crate contains Seq which is a lazily evaluated sequence of functions.

245
src/lib.rs Normal file
View File

@ -0,0 +1,245 @@
//! # Lazy Seq
//!
//! `lazy_seq` is a crate containing tools for lazily evaluated
//! collections, specifically Seq which is a collection of lazily
//! evaluated functions, and Lazy, which is the primitive used for lazy
//! evaluation.
/// Stores an operation which can be evaluated when required.
pub struct Lazy<T> {
f : Option<Box<dyn FnOnce() -> T>>,
val : Option<T>,
}
impl<T> Lazy<T> {
/// Constructs a new `Lazy<T>` from a closure implementing `FnOnce() -> T`.
pub fn new<F : FnOnce() -> T + 'static>(f : F) -> Lazy<T> {
Lazy {
f : Some(Box::new(f)),
val : None,
}
}
/// Forces evaluation of the underlying function.
pub fn force(&mut self) {
if self.f.is_some() {
let mut f = None;
std::mem::swap(&mut f, &mut self.f);
let f = f.unwrap();
let result = (f)();
self.val = Some(result);
}
}
/// Forces evaluation of the underlying function and returns the inside value, consuming
/// the `Lazy<T>`.
pub fn into_inner(mut self) -> T {
self.force();
let Lazy { f : _ , val } = self;
val.unwrap()
}
/// Returns an immutable reference to the result of the function.
pub fn as_ref(&mut self) -> &T {
self.force();
self.val.as_ref().unwrap()
}
}
impl<T> AsMut<T> for Lazy<T> {
/// Returns a mutable reference to the result of the function.
fn as_mut(&mut self) -> &mut T {
self.force();
self.val.as_mut().unwrap()
}
}
impl<T> Default for Lazy<T>
where T : Default {
fn default() -> Self {
Lazy {
f : None,
val : Some(T::default())
}
}
}
/// A lazily evaluated sequence of functions.
pub struct Seq<T>(Vec<Lazy<T>>);
impl<T> Seq<T> {
/// Constructs a new, empty `Seq<T>`.
pub fn new() -> Seq<T> {
Seq(Vec::new())
}
/// Returns `true` if the sequence contains no elements.
pub fn is_empty(&self) -> bool {
self.len() == 0
}
// Returns the number of elements the sequence can hold without reallocating.
pub fn capacity(&self) -> usize {
self.0.capacity()
}
/// Returns the number of elements in the sequence, also referred to as its length.
pub fn len(&self) -> usize {
self.0.len()
}
/// Constructs a new, empty `Seq<T>` with the specified capacity.
pub fn with_capacity(capacity : usize) -> Seq<T> {
Seq(Vec::with_capacity(capacity))
}
/// Appends the provided function to the back of the collection.
pub fn push<F : FnOnce() -> T + 'static>(&mut self, value : F) {
self.0.push(Lazy::new(value))
}
/// Forces evaluation of the last function in the sequence, returning the result.
pub fn pop(&mut self) -> Option<T> {
let lazy = self.0.pop();
lazy.map(|l| l.into_inner())
}
/// Evaluates all unevaluated functions within the Seq.
pub fn force_all(&mut self) {
for i in 0..self.0.len() {
self.0[i].force()
}
}
/// Converts a `Seq<T>` to a `Vec<T>` by forcing evaluation of all functions.
pub fn to_vec(self) -> Vec<T> {
let Seq(vec) = self;
vec
.into_iter()
.map(|x| x.into_inner())
.collect()
}
/// Converts a `Seq<T>` to a `Vec<Lazy<T>>` without evaluating any additional
/// functions.
pub fn to_lazy_vec(self) -> Vec<Lazy<T>> {
let Seq(vec) = self;
vec
}
/// Gets an immutable reference to the value at the specified index.
pub fn get(&mut self, index : usize) -> Option<&T> {
self.0.get_mut(index).map(|l| { l.force(); l.as_ref() })
}
/// Gets a mutable reference to the value at the specified index.
pub fn get_mut(&mut self, index : usize) -> Option<&mut T> {
self.0.get_mut(index).map(|l| { l.force(); l.as_mut() })
}
}
impl<T> From<Vec<Box<dyn FnOnce() -> T>>> for Seq<T> {
fn from(vec : Vec<Box<dyn FnOnce() -> T>>) -> Self {
Seq(
vec
.into_iter()
.map(|b| Lazy { f : Some(b), val : None })
.collect()
)
}
}
impl<T> From<Vec<T>> for Seq<T> {
fn from(vec : Vec<T>) -> Self {
Seq(
vec
.into_iter()
.map(|v| Lazy { f : None, val : Some(v) })
.collect()
)
}
}
impl<T> Default for Seq<T> {
fn default() -> Self {
Self::new()
}
}
/// Constructs a Seq from a literal in a similar way that vec! does for Vec.
#[macro_export]
macro_rules! seq {
() => (
lazy_seq::Seq::new()
);
($elem:expr; $n:expr) => (
{
let mut seq = Seq::with_capacity($n);
for _ in 0..$n {
seq.push($elem);
}
seq
}
);
($($x:expr),+ $(,)?) => (
{
let mut seq = Seq::new();
$(seq.push($x);)*
seq
}
);
}
#[cfg(test)]
mod tests {
use std::rc::Rc;
use std::cell::RefCell;
use crate::{Lazy, Seq, seq};
#[test]
pub fn lazy_correct() {
let counter = Rc::new(RefCell::new(0));
let counter_new = counter.clone();
let mut lazy = Lazy::new(
move || {
*counter_new.borrow_mut() += 1;
5 + 5
});
let result = lazy.as_ref();
assert_eq!(10, *result);
}
#[test]
pub fn seq_correct() {
let counter = Rc::new(RefCell::new(0));
let counter_new = counter.clone();
let mut seq = seq![
|| { 0 }; 9
];
assert_eq!(9, seq.len());
seq.push(move || {
*counter_new.borrow_mut() += 1;
println!("{:?}", counter_new);
5 + 5
});
assert_eq!(10, seq.len());
assert_eq!(0, *counter.borrow());
let _ = seq.get(9).unwrap();
assert_eq!(1, *counter.borrow());
seq.force_all();
let result = seq.pop();
assert_eq!(9, seq.len());
assert_eq!(1, *counter.borrow());
assert_eq!(10, result.unwrap());
}
}