Git Product home page Git Product logo

Comments (10)

uklotzde avatar uklotzde commented on July 18, 2024 1

Since the trait is supposed to be implemented only once in client code and not used for dynamic dispatch the non-boxed GAT version is more efficient.

If you need dynamic dispatch in your code you could probably do this behind a generic DynamicService trait and corresponding wrapper that simply delegates to your own, object safe trait.

from tokio-modbus.

uklotzde avatar uklotzde commented on July 18, 2024 1

async_trait doesn't work here because of the additional lifetime bound on &self. Try it and you will see. We can't add the required bound to the GAT in Service.

from tokio-modbus.

uklotzde avatar uklotzde commented on July 18, 2024

async fn is just syntactic sugar, which would implicitly box the returned future. I didn't check how Rust 1.75 behaves in this case and if it is already supported.

Using a generic associated type saves a heap allocation. I am not deeply familiar with the server skeletons and how this design might complicate the implementation.

from tokio-modbus.

benjamin-nw avatar benjamin-nw commented on July 18, 2024

I didn't check how Rust 1.75 behaves in this case and if it is already supported.

By reading the blog, the new desugar is:

trait HttpService {
    async fn fetch(&self, url: Url) -> HtmlBody;
//  ^^^^^^^^ desugars to:
//  fn fetch(&self, url: Url) -> impl Future<Output = HtmlBody>;
}

I am not deeply familiar with the server skeletons and how this design might complicate the implementation.

Me neither 😆 , but I think that only having 1 function and 1 (or 2) GAT would simplify greatly the usage of the trait, and the implementation.

/// A Modbus server service.
pub trait Service {
    /// Errors produced by the service.
    type Error;

    /// The future response value.
    type Future: Future<Output = Result<Response, Self::Error>> + Send + Sync + Unpin;

    /// Process the `req` and return the [`Response`] asynchronously.
    fn call(&self, req: Request<'static>) -> Self::Future;
}

Or if you think that the new async or async_trait is usable:

with rust 1.75:

/// A Modbus server service.
#[trait_variant::make(Service: Send)]
pub trait LocalService {
    /// Errors produced by the service.
    type Error;

    /// Process the `req` and return the [`Response`] asynchronously.
    async fn call(&self, req: Request<'static>) -> Result<Response, Self::Error>;
}

with async_trait:

/// A Modbus server service.
#[async_trait]
pub trait Service {
    /// Errors produced by the service.
    type Error;

    /// Process the `req` and return the [`Response`] asynchronously.
    async fn call(&self, req: Request<'static>) -> Result<Response, Self::Error>;
}

from tokio-modbus.

uklotzde avatar uklotzde commented on July 18, 2024

Maybe related: #244

from tokio-modbus.

uklotzde avatar uklotzde commented on July 18, 2024

Would #245 fix this issue?

from tokio-modbus.

benjamin-nw avatar benjamin-nw commented on July 18, 2024

If you are going to do it like this:

fn call(
    &self,
    req: Self::Request,
) -> Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;

We might just use async_trait because it desugar to a similar type but remove the boilerplate of having to add Box::pin(async move { // your code logic }) every time you implement the trait.

The original issue is to have an async block in order to able to call async fn in call.

I was thinking that maybe we can have 2 traits, one with async support and another without. But I saw that you want to change the project structure, so maybe this proposition can be in the mix too ?

from tokio-modbus.

benjamin-nw avatar benjamin-nw commented on July 18, 2024

Would #245 fix this issue?

For me yes, but the user needs to always add : Box::pin(async move {}) in the impl.

But I'm not sure if it enables dynamic dispatch 🤔 because async_trait does other stuff that might help with that

from tokio-modbus.

benjamin-nw avatar benjamin-nw commented on July 18, 2024

Oh, okay I see.

If we want to add async_trait we'll have to get rid of some of the GAT as I've written in my previous comment. But if you want to keep the GAT, I don't know if we can add it yeah.

from tokio-modbus.

benjamin-nw avatar benjamin-nw commented on July 18, 2024

The main issue is that it removes the Future GAT that is used pretty much everywhere in the server impl.

I need to try if I can use an async block with your #245 👍🏻 but I think it's possible now

from tokio-modbus.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.