use log::debug;
use std::collections::HashMap;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use futures;
use futures::lock::Mutex;
use futures::Future;
use hyper::Uri;
use tower_service::Service;
mod streams;
pub use crate::streams::MockPollStream;
#[macro_export]
macro_rules! mock_connector (
($name:ident {
$($url:expr => $res:expr)*
}) => (
#[derive(Clone)]
pub struct $name($crate::HostToReplyConnector);
impl Default for $name {
fn default() -> Self {
let mut c = Self(Default::default());
$(c.0.m.insert($url.to_string(), $res.to_string());)*
c
}
}
impl tower_service::Service<hyper::Uri> for $name {
type Response = $crate::MockPollStream;
type Error = std::io::Error;
type Future = std::pin::Pin<Box<dyn std::future::Future<Output = Result<Self::Response, Self::Error>> + Send>>;
fn poll_ready(&mut self, cx: &mut std::task::Context<'_>) -> std::task::Poll<Result<(), Self::Error>> {
self.0.poll_ready(cx)
}
fn call(&mut self, req: hyper::Uri) -> Self::Future {
self.0.call(req)
}
}
)
);
#[derive(Default, Clone)]
pub struct HostToReplyConnector {
pub m: HashMap<String, String>,
}
impl Service<Uri> for HostToReplyConnector {
type Response = crate::MockPollStream;
type Error = std::io::Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: Uri) -> Self::Future {
debug!("HostToReplyConnector::connect({:?})", req);
match (|| {
self.m.get(&format!("{}://{}", req.scheme()?, req.host()?))
})() {
Some(res) => Box::pin(futures::future::ok(MockPollStream::new(
res.clone().into_bytes(),
))),
None => panic!("HostToReplyConnector doesn't know url {}", req),
}
}
}
#[macro_export]
macro_rules! mock_connector_in_order (
($name:ident {
$( $res:expr )*
}) => (
#[derive(Clone)]
pub struct $name($crate::SequentialConnector);
impl Default for $name {
fn default() -> $name {
Self($crate::SequentialConnector::new(vec![
$($res.to_string(),)*
]))
}
}
impl tower_service::Service<hyper::Uri> for $name {
type Response = $crate::MockPollStream;
type Error = std::io::Error;
type Future = std::pin::Pin<Box<dyn std::future::Future<Output = Result<Self::Response, Self::Error>> + Send>>;
fn poll_ready(&mut self, cx: &mut std::task::Context<'_>) -> std::task::Poll<Result<(), Self::Error>> {
self.0.poll_ready(cx)
}
fn call(&mut self, req: hyper::Uri) -> Self::Future {
self.0.call(req)
}
}
)
);
#[derive(Clone)]
pub struct SequentialConnector {
pub content: Arc<[String]>,
pub current: Arc<Mutex<usize>>,
}
impl SequentialConnector {
pub fn new(content: impl Into<Box<[String]>>) -> Self {
let content = content.into();
assert!(
content.len() != 0,
"Not a single streamer return value specified"
);
SequentialConnector {
content: content.into(),
current: Arc::new(Mutex::new(0)),
}
}
}
impl Service<Uri> for SequentialConnector {
type Response = crate::MockPollStream;
type Error = std::io::Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: Uri) -> Self::Future {
debug!("SequentialConnector::connect({:?})", req);
let content = self.content.clone();
let current = self.current.clone();
Box::pin(async move {
let mut current = current.lock().await;
let data = content[*current].clone().into_bytes();
*current = *current + 1;
Ok(MockPollStream::new(data))
})
}
}