ballsteve / xrust

XPath, XQuery, and XSLT for Rust
Apache License 2.0
89 stars 9 forks source link

Using RNode in async code doesn't work because of Rc #123

Open squeaktoy opened 3 days ago

squeaktoy commented 3 days ago

I am writing a project that uses xrust at https://git.sr.ht/~latex/streamlist I'm trying to use xrust in async code, and it's not working. How would I get this to work?

error: future cannot be sent between threads safely
   --> src/serve.rs:80:9
    |
80  | /         Box::pin(async move {
81  | |             let response: Response = future.await?;
82  | |             let stylesheet = RNode::new_document();
83  | |             let body = response.into_body();
...   |
188 | |             }
189 | |         })
    | |_____error: future cannot be sent between threads safely
   --> src/serve.rs:80:9
    |
80  | /         Box::pin(async move {
81  | |             let response: Response = future.await?;
82  | |             let stylesheet = RNode::new_document();
83  | |             let body = response.into_body();
...   |
188 | |             }
189 | |         })
    | |__________^ future created by async block is not `Send`
    |
    = help: within `{async block@src/serve.rs:80:18: 189:10}`, the trait `Send` is not implemented for `Rc<xrust::trees::smite::Node>`, whic
h is required by `{async block@src/serve.rs:80:18: 189:10}: Send`
note: future is not `Send` as this value is used across an await
   --> src/serve.rs:84:65
    |
82  |             let stylesheet = RNode::new_document();
    |                 ---------- has type `Rc<xrust::trees::smite::Node>` which is not `Send`
83  |             let body = response.into_body();
84  |             let bytes = match axum::body::to_bytes(body, 65536).await {
    |                                                                 ^^^^^ await occurs here, with `stylesheet` maybe used later
    = note: required for the cast from `Pin<Box<{async block@src/serve.rs:80:18: 189:10}>>` to `Pin<Box<dyn Future<Output = Result<Response<
Body>, <S as Service<Request<Body>>>::Error>> + Send>>`
_____^ future created by async block is not `Send`
    |
    = help: within `{async block@src/serve.rs:80:18: 189:10}`, the trait `Send` is not implemented for `Rc<xrust::trees::smite::Node>`, whic
h is required by `{async block@src/serve.rs:80:18: 189:10}: Send`
note: future is not `Send` as this value is used across an await
   --> src/serve.rs:84:65
    |
82  |             let stylesheet = RNode::new_document();
    |                 ---------- has type `Rc<xrust::trees::smite::Node>` which is not `Send`
83  |             let body = response.into_body();
84  |             let bytes = match axum::body::to_bytes(body, 65536).await {
    |                                                                 ^^^^^ await occurs here, with `stylesheet` maybe used later
    = note: required for the cast from `Pin<Box<{async block@src/serve.rs:80:18: 189:10}>>` to `Pin<Box<dyn Future<Output = Result<Response<
Body>, <S as Service<Request<Body>>>::Error>> + Send>>`
ballsteve commented 3 days ago

I haven't tried using Xrust in async code. It has not been designed for that use case. iow, it is single threaded. I'd say you would have to put calls to Xrust methods in a block that prevents it from being used in a multi-threaded fashion.

ballsteve commented 3 days ago

My question would be, what are you trying to achieve with your code?

squeaktoy commented 3 days ago

I'm trying to use xrust inside an axum middleware. The idea is that it interccepts ServeDir (directory serving over HTTP) for files that might be XSLT, and then perform the transformation with XML API response as input. axum is async though, and as such I need async primitives like Arc. xrust uses Rc which doesn't work inside async scopes.