use std::fmt;
use futures::Future;
use crate::service::Service;
pub fn service_fn<F>(f: F) -> ServiceFn<F> {
ServiceFn { f }
}
#[derive(Copy, Clone)]
pub struct ServiceFn<F> {
f: F,
}
impl<Cx, F, Request, R, E> Service<Cx, Request> for ServiceFn<F>
where
F: for<'r> Callback<'r, Cx, Request, Response = R, Error = E>,
Request: 'static,
R: 'static,
E: 'static,
{
type Response = R;
type Error = E;
fn call(
&self,
cx: &mut Cx,
req: Request,
) -> impl Future<Output = Result<Self::Response, Self::Error>> {
(self.f).call(cx, req)
}
}
impl<F> fmt::Debug for ServiceFn<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ServiceFn")
.field("f", &format_args!("{}", std::any::type_name::<F>()))
.finish()
}
}
pub trait Callback<'r, Cx, Request> {
type Response;
type Error;
type Future: Future<Output = Result<Self::Response, Self::Error>> + Send + 'r;
fn call(&self, cx: &'r mut Cx, req: Request) -> Self::Future;
}
impl<'r, F, Fut, Cx, Request, R, E> Callback<'r, Cx, Request> for F
where
F: Fn(&'r mut Cx, Request) -> Fut,
Fut: Future<Output = Result<R, E>> + Send + 'r,
Cx: 'r,
{
type Response = R;
type Error = E;
type Future = Fut;
fn call(&self, cx: &'r mut Cx, req: Request) -> Self::Future {
self(cx, req)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn debug_impl_ok() {
use std::convert::Infallible;
#[derive(Debug)]
struct MotoreContext;
async fn handle(cx: &mut MotoreContext, request: String) -> Result<String, Infallible> {
println!("{cx:?}, {request:?}");
Ok::<_, Infallible>(request.to_uppercase())
}
let uppercase_service = service_fn(handle);
let _ = uppercase_service.call(&mut MotoreContext, "req".to_string());
assert_eq!(
"ServiceFn { f: motore::service::service_fn::tests::debug_impl_ok::handle }"
.to_string(),
format!("{uppercase_service:?}"),
);
}
}