├── .gitignore ├── .travis.yml ├── Cargo.toml ├── README.md └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | env: 3 | global: 4 | - secure: EL5Y260luFtRMKPFt6tRA3gAKq9kpYdKUlL5AmSxoIsuj994JwSoBriAyXmtYJBDnVKYx3ogTm3Sq1mXRdy97fJ3jBbYfDktYIGKCcSsDtY9lOox9M9oeyB+DKmpGytXPh2MxxxmD/BSriqDT4eoJecQEotHm4Vw0exQGFT+o4Q= 5 | os: 6 | - linux 7 | - osx 8 | script: 9 | - cargo build -v 10 | - cargo test -v 11 | - cargo doc -v 12 | after_script: 13 | - cd target 14 | - curl http://www.rust-ci.org/artifacts/put?t=$RUSTCI_TOKEN | sh 15 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "promise" 4 | version = "0.0.4" 5 | authors = ["Kevin Walter "] 6 | repository = "https://github.com/lucidd/rust-promise" 7 | description = """ 8 | A simple future/promise library for rust 9 | """ 10 | license = "MIT" 11 | 12 | [lib] 13 | 14 | name = "promise" 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rust-promise [![Build Status](https://travis-ci.org/lucidd/rust-promise.svg?branch=master)](https://travis-ci.org/lucidd/rust-promise) 2 | 3 | ## [Documentation](http://www.rust-ci.org/lucidd/rust-promise/doc/promise/) 4 | 5 | ## Examples 6 | 7 | ### Basics 8 | 9 | ```rust 10 | extern crate promise; 11 | 12 | use promise::Future; 13 | 14 | fn main() { 15 | let f = Future::from_fn(proc() "hello world!"); 16 | f.on_success(proc(value){ 17 | println!("{}", value) 18 | }); 19 | println!("end of main"); 20 | } 21 | ``` 22 | 23 | ### Composing Futures 24 | 25 | ```rust 26 | extern crate promise; 27 | 28 | use promise::Future; 29 | use std::time::duration::Duration; 30 | 31 | fn main() { 32 | let hello = Future::delay(proc() "hello", Duration::seconds(3)); 33 | let world = Future::from_fn(proc() "world"); 34 | let hw = Future::all(vec![hello, world]); 35 | hw.map(proc(f) format!("{} {}!", f[0], f[1])) 36 | .on_success(proc(value){ 37 | println!("{}", value) 38 | }); 39 | println!("end of main"); 40 | } 41 | ``` 42 | 43 | ```rust 44 | extern crate promise; 45 | 46 | use promise::Future; 47 | use std::time::duration::Duration; 48 | 49 | 50 | fn main() { 51 | let timeout = Future::delay(proc() Err("timeout"), Duration::seconds(2)); 52 | let f = Future::delay(proc() Ok("hello world!"), Duration::seconds(3)); 53 | let hw = Future::first_of(vec![f, timeout]); 54 | hw.on_success(proc(value){ 55 | println!("{}", value) 56 | }); 57 | println!("end of main"); 58 | } 59 | ``` 60 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(unboxed_closures)] 2 | extern crate test; 3 | 4 | use std::any::Any; 5 | use std::io::timer; 6 | use std::time::duration::Duration; 7 | use std::sync::mpsc::{ 8 | Select, 9 | Sender, 10 | SendError, 11 | Receiver, 12 | channel 13 | }; 14 | use std::collections::HashMap; 15 | use std::thread::Thread; 16 | 17 | pub enum FutureError{ 18 | TaskFailure(Box), 19 | HungUp 20 | } 21 | 22 | /// A promise is used to set the value of the associated Future 23 | pub struct Promise { 24 | sender: Sender> 25 | } 26 | 27 | impl Promise { 28 | 29 | fn new(tx: Sender>) -> Promise{ 30 | Promise{ sender: tx } 31 | } 32 | 33 | /// Completes the associated Future with value; 34 | pub fn resolve(self, value: T) -> Result<(), T> { 35 | match self.sender.send(Ok(value)) { 36 | Ok(x) => Ok(x), 37 | Err(SendError(Ok(val))) => Err(val), 38 | _ => unreachable!(), 39 | } 40 | } 41 | 42 | fn send(self, value: Result){ 43 | self.sender.send(value); 44 | } 45 | 46 | fn fail(self, error: FutureError) { 47 | self.sender.send(Err(error)); 48 | } 49 | 50 | } 51 | 52 | /// A future represents a value that is not yet available 53 | pub struct Future { 54 | receiver: Receiver> 55 | } 56 | 57 | 58 | impl Future{ 59 | 60 | fn new(rx: Receiver>) -> Future { 61 | Future{ receiver: rx } 62 | } 63 | 64 | pub fn first_of(futures: Vec>) -> Future { 65 | let (p, f) = promise::(); 66 | Thread::spawn(move || { 67 | let select = Select::new(); 68 | let mut handles = HashMap::new(); 69 | for future in futures.iter() { 70 | let handle = select.handle(&future.receiver); 71 | let id = handle.id(); 72 | handles.insert(handle.id(), handle); 73 | let h = handles.get_mut(&id).unwrap(); 74 | unsafe { 75 | h.add(); 76 | } 77 | } 78 | { 79 | let first = handles.get_mut(&select.wait()).unwrap(); 80 | p.send( 81 | match first.recv() { 82 | Ok(res) => res, 83 | Err(_) => Err(FutureError::HungUp), 84 | } 85 | ); 86 | } 87 | 88 | for (_, handle) in handles.iter_mut() { 89 | unsafe { 90 | handle.remove(); 91 | } 92 | } 93 | }); 94 | f 95 | } 96 | 97 | // Warning this function is pretty ugly mostly due to the move restrictions on handle for add 98 | // and remove. It needs to be rewritten at some point. 99 | pub fn all(futures: Vec>) -> Future> { 100 | let (p, f) = promise::>(); 101 | Thread::spawn(move || { 102 | let select = Select::new(); 103 | let mut handles = HashMap::new(); 104 | for (i, future) in futures.iter().enumerate() { 105 | let handle = select.handle(&future.receiver); 106 | let id = handle.id(); 107 | handles.insert(handle.id(), (i, handle)); 108 | let &mut (_, ref mut handle) = handles.get_mut(&id).unwrap(); 109 | unsafe { 110 | handle.add(); 111 | } 112 | } 113 | 114 | let mut results: Vec> = futures.iter().map(|_| None).collect(); 115 | let mut error: Option = None; 116 | 117 | for _ in range(0, futures.len()) { 118 | let id = select.wait(); 119 | { 120 | let &mut (i, ref mut handle) = handles.get_mut(&id).unwrap(); 121 | match handle.recv() { 122 | Ok(Ok(value)) => { 123 | *results.get_mut(i).unwrap() = Some(value); 124 | }, 125 | Ok(Err(err)) => { 126 | error = Some(err); 127 | break; 128 | }, 129 | Err(_) => { 130 | error = Some(FutureError::HungUp); 131 | break; 132 | }, 133 | } 134 | unsafe{ 135 | handle.remove(); 136 | } 137 | } 138 | handles.remove(&id); 139 | } 140 | 141 | for (_, &mut (_, ref mut handle)) in handles.iter_mut() { 142 | unsafe { 143 | handle.remove(); 144 | } 145 | } 146 | 147 | match error { 148 | Some(err) => p.fail(err), 149 | None => { 150 | let _ = p.resolve(results.into_iter().map(|v| v.unwrap()).collect()); 151 | } 152 | } 153 | }); 154 | f 155 | } 156 | 157 | /// Creates a Future that completes with val. 158 | pub fn value(val: T) -> Future { 159 | let (p, f) = promise::(); 160 | let _ = p.resolve(val); 161 | f 162 | } 163 | 164 | /// Creates a Future that resolves with the return value of func, 165 | /// If func fails the failure is propagated through TaskFailure. 166 | pub fn from_fn + Send>(func: F) -> Future { 167 | let (p, f) = promise::(); 168 | Thread::spawn(move || { 169 | let result = Thread::scoped(move || func()).join(); 170 | match result { 171 | Ok(val) => { 172 | let _ = p.resolve(val); 173 | }, 174 | Err(err) => {p.fail(FutureError::TaskFailure(err));}, 175 | }; 176 | }); 177 | f 178 | } 179 | 180 | /// Creates a Future just like from_fn that completes after a delay of duration. 181 | pub fn delay+Send>(func: F, duration: Duration) -> Future { 182 | Future::from_fn(move || { 183 | timer::sleep(duration); 184 | func() 185 | }) 186 | } 187 | 188 | /// If this Future completes with a value the new Future completes with func(value). 189 | /// If thie Future completes with an errorthe new Future completes with the same error. 190 | pub fn map+Send>(self, func: F) -> Future { 191 | let (p ,f) = promise::(); 192 | self.on_result(move |res| { 193 | match res { 194 | Ok(val) => { 195 | let result = Thread::scoped(move || func(val)).join(); 196 | match result { 197 | Ok(mapped) => { 198 | let _ = p.resolve(mapped); 199 | }, 200 | Err(err) => {p.fail(FutureError::TaskFailure(err));}, 201 | }; 202 | }, 203 | Err(err) => p.fail(err), 204 | }; 205 | }); 206 | f 207 | } 208 | 209 | /// Synchronously waits for the result of the Future and returns it. 210 | pub fn get(self) -> Result { 211 | match self.receiver.recv() { 212 | Ok(res) => res, 213 | Err(_) => Err(FutureError::HungUp), 214 | } 215 | } 216 | 217 | /// Registers a function f that is called with the result of the Future. 218 | /// This function does not block. 219 | pub fn on_result,), ()>+Send>(self, f: F) { 220 | Thread::spawn(move || { 221 | let result = self.get(); 222 | f(result); 223 | }); 224 | } 225 | 226 | /// Registers a function f that is called if the Future completes with a value. 227 | /// This function does not block. 228 | pub fn on_success+Send>(self, f: F) { 229 | Thread::spawn(move || { 230 | match self.get() { 231 | Ok(value) => f(value), 232 | _ => (), 233 | } 234 | }); 235 | } 236 | 237 | /// Registers a function f that is called if the Future completes with an error. 238 | /// This function does not block. 239 | pub fn on_failure+Send>(self, f: F) { 240 | Thread::spawn(move || { 241 | match self.get() { 242 | Err(err) => f(err), 243 | _ => () , 244 | } 245 | }); 246 | } 247 | 248 | /// Registers a function f that is called if the Future completes with a value. 249 | /// This function does not block. 250 | pub fn on_complete+Send, F: FnOnce<(FutureError,),()>+Send>(self, success: S, failure: F) { 251 | Thread::spawn(move || { 252 | match self.get() { 253 | Ok(value) => success(value), 254 | Err(err) => failure(err), 255 | } 256 | }); 257 | } 258 | } 259 | 260 | /// Creates a Future and the associated Promise to complete it. 261 | pub fn promise() -> (Promise, Future) { 262 | let (tx, rx) = channel(); 263 | (Promise::new(tx), Future::new(rx)) 264 | } 265 | 266 | 267 | #[cfg(test)] 268 | mod tests { 269 | use super::{promise, Future, FutureError}; 270 | use std::boxed::BoxAny; 271 | use std::time::duration::Duration; 272 | use std::io::timer; 273 | use std::sync::mpsc::{ 274 | channel 275 | }; 276 | use std::thread::Thread; 277 | 278 | #[test] 279 | fn test_future(){ 280 | let (p, f) = promise(); 281 | assert_eq!(p.resolve(123us), Ok(())); 282 | assert_eq!(f.get().ok(), Some(123us)); 283 | } 284 | 285 | #[test] 286 | fn test_future_hungup(){ 287 | let (p, f) = promise::(); 288 | Thread::spawn(move || { 289 | timer::sleep(Duration::seconds(1)); 290 | p; 291 | }); 292 | match f.get() { 293 | Err(FutureError::HungUp) => (), 294 | _ => panic!("should not happen"), 295 | } 296 | } 297 | 298 | #[test] 299 | fn test_future_from_fn(){ 300 | let f = Future::from_fn(move || 123us); 301 | assert_eq!(f.get().ok(), Some(123us)); 302 | } 303 | 304 | #[test] 305 | fn test_future_from_fn_fail(){ 306 | let f = Future::from_fn(move || { 307 | panic!("ooops"); 308 | 123us 309 | }); 310 | let err = match f.get() { 311 | Err(FutureError::TaskFailure(err)) => err, 312 | _ => panic!("should not happen"), 313 | }; 314 | assert!(err.is::<&'static str>()); 315 | assert_eq!(*err.downcast::<&'static str>().unwrap(), "ooops"); 316 | } 317 | 318 | #[test] 319 | fn test_future_delay(){ 320 | let f = Future::delay(move || 123us, Duration::seconds(3)); 321 | //TODO: test delay 322 | assert_eq!(f.get().ok(), Some(123us)); 323 | } 324 | 325 | #[test] 326 | fn test_future_first_of(){ 327 | let f1 = Future::delay(move || "slow", Duration::seconds(3)); 328 | let f2 = Future::from_fn(move || "fast"); 329 | let f3 = Future::first_of(vec![f1,f2]); 330 | assert_eq!(f3.get().ok(), Some("fast")); 331 | } 332 | 333 | #[test] 334 | fn test_future_all_failure(){ 335 | let f1 = Future::delay(move || "slow", Duration::seconds(3)); 336 | let f2 = Future::delay(move || panic!("medium"), Duration::seconds(1)); 337 | let f3 = Future::from_fn(move || "fast"); 338 | let f4 = Future::all(vec![f1,f2,f3]); 339 | let err = match f4.get() { 340 | Err(FutureError::TaskFailure(err)) => err, 341 | _ => panic!("should not happen"), 342 | }; 343 | assert_eq!(*err.downcast::<&'static str>().unwrap(), "medium"); 344 | } 345 | 346 | #[test] 347 | fn test_future_all_success(){ 348 | let f1 = Future::delay(move || "slow", Duration::seconds(3)); 349 | let f2 = Future::delay(move || "medium", Duration::seconds(1)); 350 | let f3 = Future::from_fn(move || "fast"); 351 | let f4 = Future::all(vec![f1,f2,f3]); 352 | assert_eq!(f4.get().ok().unwrap(), vec!["slow", "medium", "fast"]); 353 | } 354 | 355 | #[test] 356 | fn test_future_value(){ 357 | let f = Future::value(123us); 358 | assert_eq!(f.get().ok(), Some(123us)); 359 | } 360 | 361 | #[test] 362 | fn test_future_on_result(){ 363 | let (tx, rx) = channel(); 364 | let f = Future::delay(move || 123us, Duration::seconds(1)); 365 | f.on_result(move |x| { 366 | tx.send(x); 367 | }); 368 | assert_eq!(rx.recv().ok().unwrap().ok().unwrap(), 123us) 369 | } 370 | 371 | #[test] 372 | fn test_future_on_success(){ 373 | let (tx, rx) = channel(); 374 | let f = Future::delay(move || 123us, Duration::seconds(1)); 375 | f.on_success(move |x| { 376 | tx.send(x); 377 | }); 378 | assert_eq!(rx.recv().ok().unwrap(), 123us) 379 | } 380 | 381 | #[test] 382 | fn test_future_map(){ 383 | let (tx, rx) = channel(); 384 | let f = Future::value(3us); 385 | f.map(move |x| x*x) 386 | .on_success(move |x| { 387 | tx.send(x); 388 | }); 389 | assert_eq!(rx.recv().ok().unwrap(), 9us); 390 | } 391 | 392 | } 393 | --------------------------------------------------------------------------------