Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
lucidd committed Sep 22, 2014
0 parents commit 579b900
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
target
Cargo.lock

11 changes: 11 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
language: rust
os:
- linux
- osx
before_script:
- rustc -v
- cargo -V
script:
- cargo build -v
- cargo test -v
- cargo doc -v
9 changes: 9 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]

name = "promise"
version = "0.0.1"
authors = ["Kevin Walter <[email protected]>"]

[lib]

name = "promise"
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# rust-promise [![Build Status](https://travis-ci.org/lucidd/rust-promise.svg?branch=master)](https://travis-ci.org/lucidd/rust-promise)
188 changes: 188 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
extern crate test;

use std::any::Any;
use std::io::timer;
use std::time::duration::Duration;
use std::task::try;


pub enum FutureError{
TaskFailure(Box<Any+Send>),
HungUp
}

pub struct Promise<T> {
sender: Sender<Result<T, FutureError>>
}

impl<T: Send> Promise<T> {

fn new(tx: Sender<Result<T, FutureError>>) -> Promise<T>{
Promise{ sender: tx }
}

pub fn resolve(self, value: T) {
self.sender.send(Ok(value))
}

fn fail(self, error: FutureError) {
self.sender.send(Err(error))
}

}

pub struct Future<T> {
receiver: Receiver<Result<T, FutureError>>
}

impl<T: Send> Future<T>{

fn new(rx: Receiver<Result<T, FutureError>>) -> Future<T> {
Future{ receiver: rx }
}

pub fn value(val: T) -> Future<T> {
let (p, f) = promise::<T>();
p.resolve(val);
f
}

pub fn from_fn(func: proc(): Send -> T) -> Future<T> {
let (p, f) = promise::<T>();
spawn(proc() {
match try(func) {
Ok(val) => p.resolve(val),
Err(err) => p.fail(TaskFailure(err)),
};
});
f
}

pub fn delay(func: proc(): Send -> T, duration: Duration) -> Future<T> {
Future::from_fn(proc() {
timer::sleep(duration);
func()
})
}

pub fn map<B: Send>(self, func: proc(T): Send -> B) -> Future<B> {
let (p ,f) = promise::<B>();
self.on_complete(proc(res) {
match res {
Ok(val) => {
match try(proc() func(val)) {
Ok(mapped) => p.resolve(mapped),
Err(err) => p.fail(TaskFailure(err)),
};
},
Err(err) => p.fail(err),
};
});
f
}

pub fn get(self) -> Result<T, FutureError> {
match self.receiver.recv_opt() {
Ok(res) => res,
Err(_) => Err(HungUp),
}
}

pub fn on_complete(self, f: proc(Result<T, FutureError>):Send) {
spawn(proc(){
let result = self.get();
f(result);
});
}

}

pub fn promise<T :Send>() -> (Promise<T>, Future<T>) {
let (tx, rx) = channel();
(Promise::new(tx), Future::new(rx))
}


#[cfg(test)]
mod tests {
use super::{promise, Future, HungUp, TaskFailure};
use std::any::AnyRefExt;
use std::boxed::BoxAny;
use std::time::duration::Duration;
use std::io::timer;


#[test]
fn test_future(){
let (p, f) = promise();
p.resolve(123u);
assert_eq!(f.get().ok(), Some(123u));
}

#[test]
fn test_future2(){
let (p, f) = promise::<uint>();
spawn(proc(){
timer::sleep(Duration::seconds(1));
p;
});
match f.get() {
Err(HungUp) => (),
_ => fail!("should not happen"),
}
}

#[test]
fn test_future_from_fn(){
let f = Future::from_fn(proc() 123u);
assert_eq!(f.get().ok(), Some(123u));
}

#[test]
fn test_future_from_fn_fail(){
let f = Future::from_fn(proc() {
fail!("ooops");
123u
});
let err = match f.get() {
Err(TaskFailure(err)) => err,
_ => fail!("should not happen"),
};
assert!(err.is::<&'static str>());
assert_eq!(*err.downcast::<&'static str>().unwrap(), "ooops");
}

#[test]
fn test_future_delay(){
let f = Future::delay(proc() 123u, Duration::seconds(3));
//TODO: test delay
assert_eq!(f.get().ok(), Some(123u));
}

#[test]
fn test_future_value(){
let f = Future::value(123u);
assert_eq!(f.get().ok(), Some(123u));
}

#[test]
fn test_future_on_complete(){
let (tx, rx) = channel();
let f = Future::delay(proc() 123u, Duration::seconds(3));
f.on_complete(proc(x){
tx.send(x);
});
assert_eq!(rx.recv().ok(), Some(123u))
}

#[test]
fn test_future_map(){
let (tx, rx) = channel();
let f = Future::value(3u);
f.map(proc(x) x*x).on_complete(proc(x){
tx.send(x);
});
assert_eq!(rx.recv().ok(), Some(9u));
}

}

0 comments on commit 579b900

Please sign in to comment.