feat: reconstruct ware source
This commit is contained in:
parent
9a474b7fd5
commit
e91056fee5
6 changed files with 282 additions and 2 deletions
86
ware/src/im.rs
Normal file
86
ware/src/im.rs
Normal file
|
@ -0,0 +1,86 @@
|
|||
//! An immutable version of ware. Does not use RefCells, instead
|
||||
//! relying on the user to return the modified variable in the closure.
|
||||
//!
|
||||
//! ## Example
|
||||
//! ```
|
||||
//! use ware::im::Ware;
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut chain: Ware<i32> = Ware::new();
|
||||
//! chain.wrap(Box::new(|num| num * 10));
|
||||
//! chain.wrap(Box::new(|num| num - 2));
|
||||
//! let result = chain.run(5);
|
||||
//! assert_eq!(result, 48);
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
/// A middleware chain.
|
||||
pub struct Ware<T> {
|
||||
/// The internal list of middleware functions.
|
||||
pub fns: Vec<Box<dyn Fn(T) -> T>>,
|
||||
}
|
||||
|
||||
impl<T> Ware<T> {
|
||||
/// Create a new middleware chain with a given type.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use ware::im::Ware;
|
||||
/// let mut chain: Ware<String> = Ware::new();
|
||||
/// ```
|
||||
pub fn new() -> Ware<T> {
|
||||
let vec: Vec<Box<dyn Fn(T) -> T>> = Vec::new();
|
||||
Ware { fns: vec }
|
||||
}
|
||||
|
||||
/// Add a new middleware function to the internal function list. This function
|
||||
/// must be of the `Fn` trait, take the specified type and return the same
|
||||
/// specified type. It also has to be boxed for memory safety reasons.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use ware::im::Ware;
|
||||
/// let mut chain: Ware<String> = Ware::new();
|
||||
/// chain.wrap(Box::new(|st| {
|
||||
/// let mut s = st.clone();
|
||||
/// s.push('a');
|
||||
/// s
|
||||
/// }))
|
||||
/// ```
|
||||
pub fn wrap(&mut self, func: Box<dyn Fn(T) -> T>) {
|
||||
self.fns.push(func);
|
||||
}
|
||||
|
||||
/// Run the registered middleware functions with the given value to pass
|
||||
/// through. Returns whatever the last registered middleware function
|
||||
/// returns.
|
||||
pub fn run(&self, arg: T) -> T {
|
||||
self.fns.iter().fold(arg, |acc, func| func(acc))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let value = 1;
|
||||
let mut w: Ware<i32> = Ware::new();
|
||||
w.wrap(Box::new(|num| num + 1));
|
||||
assert_eq!(w.run(value), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_is_immutable() {
|
||||
let value = 1;
|
||||
let closure = |num| {
|
||||
let num = num + 1;
|
||||
num
|
||||
};
|
||||
let mut w: Ware<i32> = Ware::new();
|
||||
w.wrap(Box::new(closure));
|
||||
assert_eq!(w.run(value), 2);
|
||||
assert_eq!(value, 1);
|
||||
}
|
||||
}
|
91
ware/src/lib.rs
Normal file
91
ware/src/lib.rs
Normal file
|
@ -0,0 +1,91 @@
|
|||
//! Ware provides mutable and immutable middleware abstractions. Basically, it means that
|
||||
//! you can pass one variable through a series of functions that all have the
|
||||
//! ability to modify this variable, therefore sending this modified version of
|
||||
//! it further down the chain.
|
||||
//!
|
||||
//! Ware is used like this:
|
||||
//!
|
||||
//! ```
|
||||
//! use ware::Ware;
|
||||
//! use std::ops::{Mul, Sub};
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut chain: Ware<i32> = Ware::new();
|
||||
//! chain.wrap(Box::new(|mut num| {
|
||||
//! *num = num.mul(5);
|
||||
//! }));
|
||||
//! chain.wrap(Box::new(|mut num| {
|
||||
//! *num = num.sub(2);
|
||||
//! }));
|
||||
//! let result = chain.run(5);
|
||||
//! assert_eq!(result, 23);
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use std::cell::{RefCell, RefMut};
|
||||
|
||||
pub mod im;
|
||||
/// Shorthand version of `RefMut<T>`, if you don't want to import `RefMut`.
|
||||
pub type WareArg<'a, T> = RefMut<'a, T>;
|
||||
|
||||
/// A middleware chain.
|
||||
pub struct Ware<T> {
|
||||
/// The internal list of middleware functions.
|
||||
pub fns: Vec<Box<dyn Fn(WareArg<T>) -> ()>>,
|
||||
}
|
||||
|
||||
impl<T> Ware<T> {
|
||||
/// Create a new middleware chain with a given type.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use ware::Ware;
|
||||
/// let mut chain: Ware<String> = Ware::new();
|
||||
/// ```
|
||||
pub fn new() -> Ware<T> {
|
||||
let vec: Vec<Box<dyn Fn(WareArg<T>) -> ()>> = Vec::new();
|
||||
Ware { fns: vec }
|
||||
}
|
||||
|
||||
/// Add a new middleware function to the internal function list. This function
|
||||
/// must be of the `Fn` trait, take a `WareArg<T>` and return a unit struct (aka. nothing).
|
||||
/// It also has to be boxed for memory safety reasons.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use ware::Ware;
|
||||
/// let mut chain: Ware<String> = Ware::new();
|
||||
/// chain.wrap(Box::new(|mut st| {
|
||||
/// st.push('a');
|
||||
/// }))
|
||||
/// ```
|
||||
pub fn wrap(&mut self, func: Box<dyn Fn(WareArg<T>) -> ()>) {
|
||||
self.fns.push(func);
|
||||
}
|
||||
|
||||
/// Run the registered middleware functions with the given value to pass
|
||||
/// through. Returns whatever the passed value will be after the last
|
||||
/// middleware function runs.
|
||||
pub fn run(&self, arg: T) -> T {
|
||||
let ware_arg = RefCell::new(arg);
|
||||
self.fns.iter().for_each(|func| func(ware_arg.borrow_mut()));
|
||||
ware_arg.into_inner()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::ops::Add;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let value = 1;
|
||||
let mut w: Ware<i32> = Ware::new();
|
||||
w.wrap(Box::new(|mut num| {
|
||||
*num = num.add(1);
|
||||
}));
|
||||
assert_eq!(w.run(value), 2);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue