use futures::{Future, Stream, future};
use hyper::client::{Client, Connect};
use hyper::{Error as HyperError, Uri};
use std::collections::HashMap;
use std::fmt::Display;
use std::str::FromStr;
use ::models::Forecast;
use ::{Error, Options, internal, utils};
pub trait DarkskyHyperRequester {
fn get_forecast<'a, 'b, T: AsRef<str>>(
&'a self,
token: T,
latitude: f64,
longitude: f64,
) -> Box<Future<Item = Forecast, Error = Error> + 'b>;
fn get_forecast_with_options<'a, 'b, F, T>(
&'a self,
token: T,
latitude: f64,
longitude: f64,
options: F,
) -> Box<Future<Item = Forecast, Error = Error> + 'b>
where F: FnOnce(Options) -> Options, T: AsRef<str>;
fn get_forecast_time_machine<D, F, T>(
&self,
token: T,
latitude: f64,
longitude: f64,
time: D,
options: F,
) -> Box<Future<Item = Forecast, Error = Error>>
where D: Display, F: FnOnce(Options) -> Options, T: AsRef<str>;
}
impl<B, C: Connect> DarkskyHyperRequester for Client<C, B>
where B: Stream<Error = HyperError> + 'static, B::Item: AsRef<[u8]> {
fn get_forecast<'a, 'b, T: AsRef<str>>(
&'a self,
token: T,
latitude: f64,
longitude: f64,
) -> Box<Future<Item = Forecast, Error = Error> + 'b> {
let url = utils::uri(token.as_ref(), latitude, longitude);
let uri = match Uri::from_str(&url) {
Ok(v) => v,
Err(why) => return Box::new(future::err(Error::Uri(why))),
};
Box::new(self.get(uri)
.and_then(|res| res.body().concat2())
.from_err()
.map(internal::from_chunk)
.and_then(|x| x))
}
fn get_forecast_with_options<'a, 'b, F, T>(
&'a self,
token: T,
latitude: f64,
longitude: f64,
options: F,
) -> Box<Future<Item = Forecast, Error = Error> + 'b>
where F: FnOnce(Options) -> Options, T: AsRef<str> {
let options = options(Options(HashMap::new())).0;
let constructed = utils::uri_optioned(
token.as_ref(),
latitude,
longitude,
None,
options,
);
let url = match constructed {
Ok(v) => v,
Err(why) => return Box::new(future::err(why)),
};
let uri = match Uri::from_str(&url) {
Ok(v) => v,
Err(why) => return Box::new(future::err(Error::Uri(why))),
};
Box::new(self.get(uri)
.and_then(|res| res.body().concat2())
.from_err()
.map(internal::from_chunk)
.and_then(|x| x))
}
fn get_forecast_time_machine<D, F, T>(
&self,
token: T,
latitude: f64,
longitude: f64,
time: D,
options: F,
) -> Box<Future<Item = Forecast, Error = Error>>
where D: Display, F: FnOnce(Options) -> Options, T: AsRef<str> {
let time = time.to_string();
forecast_optioned(self, token, latitude, longitude, Some(time), options)
}
}
fn forecast_optioned<B, C, F, T>(
client: &Client<C, B>,
token: T,
latitude: f64,
longitude: f64,
time: Option<String>,
options: F,
) -> Box<Future<Item = Forecast, Error = Error>>
where B: Stream<Error = HyperError> + 'static,
B::Item: AsRef<[u8]>,
C: Connect,
F: FnOnce(Options) -> Options,
T: AsRef<str> {
let options = options(Options(HashMap::new())).0;
let constructed = utils::uri_optioned(
token.as_ref(),
latitude,
longitude,
time,
options,
);
let url = match constructed {
Ok(v) => v,
Err(why) => return Box::new(future::err(why)),
};
let uri = match Uri::from_str(&url) {
Ok(v) => v,
Err(why) => return Box::new(future::err(Error::Uri(why))),
};
Box::new(client.get(uri)
.and_then(|res| res.body().concat2())
.from_err()
.map(internal::from_chunk)
.and_then(|x| x))
}