#![crate_name="morphism"]
#![crate_type="lib"]
#![doc(html_root_url = "http://freebroccolo.github.io/morphism.rs/doc/morphism/")]
use std::collections::{
LinkedList,
VecDeque,
};
use std::marker::{
PhantomData,
};
use std::mem::{
transmute,
};
pub struct Morphism<'a, A, B = A> {
mfns: LinkedList<VecDeque<Box<Fn(*const ()) -> *const () + 'a>>>,
phan: PhantomData<(A, B)>,
}
#[allow(dead_code)]
enum Void {}
impl Morphism<'static, Void> {
#[inline]
pub fn new<'a, A>() -> Morphism<'a, A> {
Morphism {
mfns: {
let mut mfns = LinkedList::new();
mfns.push_back(VecDeque::new());
mfns
},
phan: PhantomData,
}
}
}
impl<'a, B, C> Morphism<'a, B, C> {
#[inline(always)]
pub unsafe fn unsafe_push_front<A, F>(&mut self, f: F) -> ()
where F: Fn(A) -> B + 'a,
{
match self {
&mut Morphism {
ref mut mfns,
..
}
=> {
let head = mfns.front_mut().unwrap();
let g = Box::new(move |ptr| {
transmute::<Box<B>, *const ()>(
Box::new(
f(*transmute::<*const (), Box<A>>(ptr))
)
)
});
head.push_front(g);
},
}
}
#[inline]
pub fn head<A, F>(self, f: F) -> Morphism<'a, A, C>
where F: Fn(A) -> B + 'a,
{
let mut self0 = self;
unsafe {
(&mut self0).unsafe_push_front(f);
transmute(self0)
}
}
#[inline]
pub fn push_front<F>(&mut self, f: F) -> ()
where F: Fn(B) -> B + 'a,
{
unsafe {
self.unsafe_push_front(f)
}
}
}
impl<'a, A, B> Morphism<'a, A, B> {
#[inline(always)]
pub unsafe fn unsafe_push_back<C, F>(&mut self, f: F) -> ()
where F: Fn(B) -> C + 'a,
{
match self {
&mut Morphism {
ref mut mfns,
..
}
=> {
let tail = mfns.back_mut().unwrap();
let g = Box::new(move |ptr| {
transmute::<Box<C>, *const ()>(
Box::new(
f(*transmute::<*const (), Box<B>>(ptr))
)
)
});
tail.push_back(g);
},
}
}
#[inline]
pub fn tail<C, F>(self, f: F) -> Morphism<'a, A, C>
where F: Fn(B) -> C + 'a,
{
let mut self0 = self;
unsafe {
(&mut self0).unsafe_push_back(f);
transmute(self0)
}
}
#[inline]
pub fn push_back<F>(&mut self, f: F) -> ()
where F: Fn(B) -> B + 'a,
{
unsafe {
self.unsafe_push_back(f)
}
}
#[inline]
pub fn then<C>(self, mut other: Morphism<'a, B, C>) -> Morphism<'a, A, C> {
match self {
Morphism {
mfns: mut lhs,
..
}
=> {
match other {
Morphism {
mfns: ref mut rhs,
..
}
=> {
Morphism {
mfns: {
lhs.append(rhs);
lhs
},
phan: PhantomData,
}
},
}
},
}
}
#[inline]
pub fn run(&self, x: A) -> B { unsafe {
let mut res = transmute::<Box<A>, *const ()>(Box::new(x));
for fns in self.mfns.iter() {
for f in fns.iter() {
res = f(res);
}
}
*transmute::<*const (), Box<B>>(res)
}}
}
#[cfg(test)]
mod tests
{
use super::Morphism;
#[test]
fn readme() {
let mut f = Morphism::new::<u64>();
for _ in 0..100000u64 {
f = f.tail(|x| x + 42u64);
}
let mut g = Morphism::new::<Option<u64>>();
for _ in 0..99999u64 {
g = g.tail(|x| x.map(|y| y - 42u64));
}
let g = g
.tail(|x| (x.map(|y| y + 1000u64), "welp".to_string()))
.tail(|(l, r)| (l.map(|y| y + 42u64), r))
.tail(|(l, r)| (l, l.is_some(), r))
.head(|x| Some(x));
let h = f.then(g);
assert_eq!(h.run(0u64), (Some(1084), true, "welp".to_string()));
assert_eq!(h.run(1000u64), (Some(2084), true, "welp".to_string()));
}
}