js-promises 0.1.0

Bindings for JS promises
Documentation

use js_promises::*;

use std::panic;
use stdweb::{self, js, console};

fn panic_hook(info: &panic::PanicInfo) {
	let mut msg = info.to_string();
	let stack = js!{
		let err = new Error();
		return err.stack;
	};
	msg.push_str("\n\nStack:\n\n");
	msg.push_str(stack.as_str().unwrap_or("<Error.stack was not a string>"));
	msg.push_str("\n\n");
	
	console!(error, msg);
}

pub fn set_panic_hook() {
	panic::set_hook(Box::new(panic_hook));
}

fn http_req(url: &str) -> Promise<serde_json::Value,String> {
	let req = stdweb::web::XmlHttpRequest::new();
	req.open("GET", url).expect("open failed");
	
	let p = RawPromise::from_value(js!{
		return new Promise(function(resolve, reject) {
			let req = @{req.as_ref().clone()};
			req.addEventListener("load", resolve);
			req.addEventListener("abort", function() { reject("abort"); });
			req.addEventListener("error", function() { reject("error"); });
			req.addEventListener("timeout", function() { reject("timeout"); });
		});
	});
	req.send().unwrap();
	let p = p.then_to_typed::<serde_json::Value, String, _>(move |res| {
		console!(log, "got web result");
		let _ev = res.map_err(|v| v.into_string().unwrap())?;
		
		let body = req.response_text().unwrap().unwrap();
		let out = serde_json::from_str::<serde_json::Value>(&body).unwrap();
		console!(log, "returning deserialized result");
		return Ok(PromiseOk::Immediate(out));
	});
	
	return p;
}

fn main() {
	set_panic_hook();
	Promise::<String,String>::new_resolved(String::from("https://httpbin.org/get"))
		.and_then(|url| {
			console!(log, "url:", &url);
			let new_p = http_req(&url);
			console!(log, "have promise");
			
			return Ok(PromiseOk::Promise(new_p));
		})
		.and_then(|v| {
			console!(log, "req result:", format!("{:?}", v));
			let url_v = v.pointer("/url").ok_or(String::from("Expected url field in response"))?;
			let url = url_v.as_str().ok_or(String::from("url field in response was not a string"))?;
			if url == "https://httpbin.org/get" {
				return Ok(PromiseOk::Immediate(()));
			} else {
				return Err(format!("url field in response was incorrect, had value {:?}", url));
			}
		})
		.then::<(),(),_>(|res| {
			console!(log, "result:", format!("{:?}", res));
			Ok(PromiseOk::Immediate(()))
		});
}