use std::{collections::VecDeque, sync::Arc};
use tokio::sync::Mutex;
use tower_async_service::Service;
#[derive(Debug)]
pub struct Mock<Request, Response, Error> {
handle: SyncHandle<Request, Response, Error>,
}
pub(crate) fn spawn<Request, Response, Error>() -> (
Mock<Request, Response, Error>,
SyncHandle<Request, Response, Error>,
)
where
Request: Send + Sync,
Response: Send + Sync,
Error: Send + Sync,
{
let handle = Arc::new(Mutex::new(Handle::new()));
let mock = Mock {
handle: handle.clone(),
};
(mock, handle)
}
impl<Request, Response, Error> Service<Request> for Mock<Request, Response, Error> {
type Response = Response;
type Error = Error;
async fn call(&self, request: Request) -> Result<Self::Response, Self::Error> {
let mut handle = self.handle.lock().await;
handle.push_request(request);
handle.pop_result()
}
}
pub(crate) type SyncHandle<Request, Response, Error> = Arc<Mutex<Handle<Request, Response, Error>>>;
#[derive(Debug)]
pub(crate) struct Handle<Request, Response, Error> {
requests: VecDeque<Request>,
results: VecDeque<Result<Response, Error>>,
}
impl<Request, Response, Error> Handle<Request, Response, Error> {
pub(crate) fn new() -> Self {
Self {
requests: VecDeque::new(),
results: VecDeque::new(),
}
}
pub(crate) fn push_request(&mut self, request: Request) {
self.requests.push_back(request);
}
pub(crate) fn push_result(&mut self, result: Result<Response, Error>) {
self.results.push_back(result);
}
pub(crate) fn pop_request(&mut self) -> Request {
self.requests.pop_front().unwrap()
}
pub(crate) fn pop_result(&mut self) -> Result<Response, Error> {
self.results.pop_front().unwrap()
}
}
impl<Request, Response, Error> Default for Handle<Request, Response, Error> {
fn default() -> Self {
Self::new()
}
}