From 70cac9fbbb0ccdaedb79e27fde6b7ae6d6f4f53a Mon Sep 17 00:00:00 2001 From: Rain Jiang Date: Fri, 30 Jun 2023 23:25:40 +0000 Subject: [PATCH] use async trait to refactor the service --- service-async/Cargo.toml | 1 + service-async/examples/async_trait_demo.rs | 72 ++++++++++++++++++++++ service-async/examples/demo.rs | 60 ++++++++---------- service-async/src/boxed.rs | 71 ++++++++++----------- service-async/src/either.rs | 14 ++--- service-async/src/lib.rs | 33 ++++++---- service-async/src/map.rs | 18 +++--- 7 files changed, 169 insertions(+), 100 deletions(-) create mode 100644 service-async/examples/async_trait_demo.rs diff --git a/service-async/Cargo.toml b/service-async/Cargo.toml index 295cf5c..2ad2753 100644 --- a/service-async/Cargo.toml +++ b/service-async/Cargo.toml @@ -14,6 +14,7 @@ repository = "https://github.com/ihciah/service-async" [dependencies] param = { version = "0.1.2", path = "../param" } futures-util = "0.3" +async-trait = "0" [target.'cfg(unix)'.dev-dependencies] monoio = { version = "0.1.5" } diff --git a/service-async/examples/async_trait_demo.rs b/service-async/examples/async_trait_demo.rs new file mode 100644 index 0000000..57821d2 --- /dev/null +++ b/service-async/examples/async_trait_demo.rs @@ -0,0 +1,72 @@ +#![feature(return_position_impl_trait_in_trait)] +#![feature(type_alias_impl_trait)] +// #![feature(async_fn_in_trait)] + +// use std::{cell::UnsafeCell, future::Future, rc::Rc}; + +use async_trait::async_trait; + +#[async_trait] +pub trait Service: Sync + Send { + type Response; + // /// Errors produced by the service. + type Error; + async fn call(&self, req: Request) -> Result; +} + +struct A; +#[async_trait] +impl Service for A { + type Response = String; + type Error = (); + + async fn call(&self, req: String) -> Result { + Ok(format!("A -> {}", req)) + } +} + +struct B { + inner: S, +} +#[async_trait] +impl Service for B +where + S: Service, +{ + type Response = String; + type Error = (); + async fn call(&self, req: String) -> Result { + let req = format!("B -> {}", req); + self.inner.call(req).await + } +} + +pub trait Layer { + type Service; + fn layer(&self, inner: S) -> Self::Service; +} +struct LayerB; +impl Layer for LayerB +where + S: Service, +{ + type Service = B; + fn layer(&self, inner: S) -> Self::Service { + B { inner } + } +} + +#[monoio::main] +async fn main() { + let a = A; + let layer = LayerB; + let b = layer.layer(a); + let mut c = Vec::>>::new(); + c.push(Box::new(A)); + + let result = b.call(String::from("abcdfdssfd")).await; + println!("{:?}", result); + for d in c { + println!("d result: {:?}", d.call(String::from("abcd")).await) + } +} diff --git a/service-async/examples/demo.rs b/service-async/examples/demo.rs index ce9c82e..9c32b5e 100644 --- a/service-async/examples/demo.rs +++ b/service-async/examples/demo.rs @@ -6,6 +6,7 @@ use std::{ sync::atomic::{AtomicUsize, Ordering}, }; +use async_trait::async_trait; use service_async::{ layer::{layer_fn, FactoryLayer}, stack::FactoryStack, @@ -24,21 +25,17 @@ struct SvcA { not_pass_flag: bool, } +#[async_trait] impl Service<()> for SvcA { type Response = (); type Error = Infallible; - type Future<'cx> = impl Future> + 'cx - where - Self: 'cx; - - fn call(&self, _req: ()) -> Self::Future<'_> { - async move { - println!( - "SvcA called! pass_flag = {}, not_pass_flag = {}", - self.pass_flag, self.not_pass_flag - ); - Ok(()) - } + + async fn call(&self, _req: ()) -> Result { + println!( + "SvcA called! pass_flag = {}, not_pass_flag = {}", + self.pass_flag, self.not_pass_flag + ); + Ok(()) } } @@ -71,24 +68,20 @@ struct SvcB { inner: T, } +#[async_trait] impl Service for SvcB where T: Service<(), Error = Infallible>, { type Response = (); type Error = Infallible; - type Future<'cx> = impl Future> + 'cx - where - Self: 'cx; - - fn call(&self, req: usize) -> Self::Future<'_> { - async move { - let old = self.counter.fetch_add(req, Ordering::AcqRel); - let new = old + req; - println!("SvcB called! {old}->{new}"); - self.inner.call(()).await?; - Ok(()) - } + + async fn call(&self, req: usize) -> Result { + let old = self.counter.fetch_add(req, Ordering::AcqRel); + let new = old + req; + println!("SvcB called! {old}->{new}"); + self.inner.call(()).await?; + Ok(()) } } @@ -121,22 +114,19 @@ struct SvcC { inner: T, } +#[async_trait] impl Service for SvcC where T: Service, + I: Send + 'static, { type Response = (); type Error = Infallible; - type Future<'cx> = impl Future> + 'cx - where - Self: 'cx, I: 'cx; - fn call(&self, req: I) -> Self::Future<'_> { - async move { - println!("SvcC called!"); - self.inner.call(req).await?; - Ok(()) - } + async fn call(&self, req: I) -> Result { + println!("SvcC called!"); + self.inner.call(req).await?; + Ok(()) } } @@ -227,8 +217,8 @@ async fn main() { new_svc.call(10).await.unwrap(); // also, BoxService can use it in this way too - let new_svc = new_stack.make_via_ref(boxed_svc.downcast_ref()).unwrap(); - new_svc.call(10).await.unwrap(); + // let new_svc = new_stack.make_via_ref(Some(boxed_svc)).unwrap(); + // new_svc.call(10).await.unwrap(); // to make it more flexible, we can even make the factory a boxed type. // so we can insert different layers and get a same type. diff --git a/service-async/src/boxed.rs b/service-async/src/boxed.rs index b070a3e..486a687 100644 --- a/service-async/src/boxed.rs +++ b/service-async/src/boxed.rs @@ -3,14 +3,13 @@ use std::{ marker::PhantomData, }; +use async_trait::async_trait; pub use futures_util::future::LocalBoxFuture; use crate::{MakeService, Service}; pub struct BoxedService { - svc: *const (), - type_id: TypeId, - vtable: ServiceVtable, + svc: Box>, } impl BoxedService { @@ -19,51 +18,47 @@ impl BoxedService { S: Service + 'static, Request: 'static, { - let type_id = s.type_id(); - let svc = Box::into_raw(Box::new(s)) as *const (); - BoxedService { - svc, - type_id, - vtable: ServiceVtable { - call: call::, - drop: drop::, - }, - } + BoxedService { svc: Box::new(s) } } - pub fn downcast_ref(&self) -> Option<&T> { - let t = TypeId::of::(); - if self.type_id == t { - Some(unsafe { self.downcast_ref_unchecked() }) - } else { - None - } + pub fn get_inner(&self) -> &dyn Service { + self.svc.as_ref() } - /// # Safety - /// If you are sure the inner type is T, you can downcast it. - pub unsafe fn downcast_ref_unchecked(&self) -> &T { - &*(self.svc as *const () as *const T) - } + // pub fn downcast_ref(&self) -> Option<&T> { + // let t = TypeId::of::(); + // if self.type_id == t { + // Some(unsafe { self.downcast_ref_unchecked() }) + // } else { + // None + // } + // } + + // /// # Safety + // /// If you are sure the inner type is T, you can downcast it. + // pub unsafe fn downcast_ref_unchecked(&self) -> &T { + // &*(self.svc as *const () as *const T) + // } } -impl Drop for BoxedService { - #[inline] - fn drop(&mut self) { - unsafe { (self.vtable.drop)(self.svc) }; - } -} +// impl Drop for BoxedService { +// #[inline] +// fn drop(&mut self) { +// unsafe { (self.vtable.drop)(self.svc) }; +// } +// } -impl Service for BoxedService { +#[async_trait] +impl Service for BoxedService +where + Request: Send, +{ type Response = Response; type Error = E; - type Future<'cx> = LocalBoxFuture<'cx, Result> - where - Self: 'cx, Request: 'cx; #[inline] - fn call(&self, req: Request) -> Self::Future<'_> { - unsafe { (self.vtable.call)(self.svc, req) } + async fn call(&self, req: Request) -> Result { + self.svc.call(req).await } } @@ -140,7 +135,7 @@ where fn make_via_ref(&self, old: Option<&Self::Service>) -> Result { let svc = match old { - Some(inner) => self.inner.make_via_ref(inner.downcast_ref())?, + Some(inner) => self.inner.make_via_ref(None)?, None => self.inner.make()?, }; Ok(svc.into_boxed()) diff --git a/service-async/src/either.rs b/service-async/src/either.rs index f535171..e9e589d 100644 --- a/service-async/src/either.rs +++ b/service-async/src/either.rs @@ -1,5 +1,7 @@ use std::{error::Error, fmt::Display, future::Future, pin::Pin}; +use async_trait::async_trait; + use crate::{layer::FactoryLayer, MakeService, Service}; #[derive(Debug, Clone)] @@ -65,23 +67,21 @@ where } } +#[async_trait] impl Service for Either where A: Service, B: Service, + R: Send + 'static, { type Response = A::Response; type Error = A::Error; - type Future<'cx> = Either, B::Future<'cx>> - where - Self: 'cx, - R: 'cx; #[inline] - fn call(&self, req: R) -> Self::Future<'_> { + async fn call(&self, req: R) -> Result { match self { - Either::Left(s) => Either::Left(s.call(req)), - Either::Right(s) => Either::Right(s.call(req)), + Either::Left(s) => s.call(req).await, + Either::Right(s) => s.call(req).await, } } } diff --git a/service-async/src/lib.rs b/service-async/src/lib.rs index 5d46643..cabf7c1 100644 --- a/service-async/src/lib.rs +++ b/service-async/src/lib.rs @@ -15,20 +15,31 @@ pub use map::MapTargetService; mod boxed; pub use boxed::{BoxService, BoxServiceFactory, BoxedService}; -pub trait Service { - /// Responses given by the service. +// pub trait Service { +// /// Responses given by the service. +// type Response; +// /// Errors produced by the service. +// type Error; + +// /// The future response value. +// type Future<'cx>: Future> +// where +// Self: 'cx, +// Request: 'cx; + +// /// Process the request and return the response asynchronously. +// fn call(&self, req: Request) -> Self::Future<'_>; +// } + +use async_trait::async_trait; + +#[async_trait] +pub trait Service: Sync + Send { type Response; - /// Errors produced by the service. + // /// Errors produced by the service. type Error; - /// The future response value. - type Future<'cx>: Future> - where - Self: 'cx, - Request: 'cx; - - /// Process the request and return the response asynchronously. - fn call(&self, req: Request) -> Self::Future<'_>; + async fn call(&self, req: Request) -> Result; } pub trait MakeService { diff --git a/service-async/src/map.rs b/service-async/src/map.rs index 1a5a6c4..7331ed6 100644 --- a/service-async/src/map.rs +++ b/service-async/src/map.rs @@ -1,8 +1,10 @@ use std::future::Future; +use async_trait::async_trait; + use super::{MakeService, Service}; -pub trait MapTarget { +pub trait MapTarget: Send + Sync { type Target; fn map_target(&self, t: T) -> Self::Target; @@ -10,7 +12,7 @@ pub trait MapTarget { impl MapTarget for F where - F: Fn(T) -> U, + F: Fn(T) -> U + Send + Sync, { type Target = U; @@ -25,24 +27,22 @@ pub struct MapTargetService { pub inner: T, } +#[async_trait] impl Service for MapTargetService where F: MapTarget, T: Service, + R: Send + 'static, + F::Target: Send, { type Response = T::Response; type Error = T::Error; - type Future<'cx> = impl Future> + 'cx - where - Self: 'cx, - R: 'cx; - #[inline] - fn call(&self, req: R) -> Self::Future<'_> { + async fn call(&self, req: R) -> Result { let req = self.f.map_target(req); - self.inner.call(req) + self.inner.call(req).await } }