Comments (5)
While explicitly cloning the state might seem like a good theoretical solution, in practice, the state could originate from a third-party library beyond the developer's scope, and the utilized state may lack implementation for the
Clone
and/orCopy
trait. In such cases, cloning is not feasible.
This would mean that the axum
example wouldn't work at all. It would simply fail to compile. This seems antithetic to the proposition of finesse.
Now, cloning works, but beginners to Rust and/or Rocket may not be aware that they need to dereference the state first before cloning, as demonstrated below:
You can also do client.inner().clone()
, which is arguably simpler and more explicit.
Following the approach adopted by Axum, implicitly cloning the state would be preferable if the state is inherently cloneable to begin with. Therefore, I would like to propose the following solution:
The approach you're suggesting would mean that only cloneable state can be shared, and that every time you try to access said state you must pay the price to clone. Axum likely cannot expose direct references to share state due to internal design constraints, but Rocket can and doesn't need to fallback to cloning. Rocket gives you a direct reference - this is superior in every way except perhaps the need to call .clone()
when that's what you actually want. Though even that can be refuted as running counter to the notion of zero-cost abstractions.
If you really want this abstraction, it's fairly straightforward to implement it yourself, actually:
use rocket::{Rocket, Ignite, State};
use rocket::outcome::{try_outcome, Outcome};
use rocket::request::{self, Request, FromRequest};
#[rocket::async_trait]
impl<'r, T: Send + Sync + Clone + 'static> FromRequest<'r> for Cloned<T> {
type Error = ();
async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
let state = try_outcome!(req.guard::<&State<T>>().await);
Outcome::Success(Cloned(state.inner().clone()))
}
}
You can even make it a Sentinel
:
impl<T: Send + Sync + 'static> Sentinel for Cloned<T> {
fn abort(rocket: &Rocket<Ignite>) -> bool {
<&State<T> as Sentinel>::abort(rocket)
}
}
Then you can do just as you wished:
async fn generate_content(Cloned(mut client): Cloned<Client>) -> String {
//...snip...
}
from rocket.
Instead of creating a brand new client in the handler, you could simply clone the existing reference you get from State
. This would be equivalent to what Axum does, except doing it, explicitly, instead of having it be hidden from you. Rocket does not hide potentially expensive operations from you.
Were you aware aware of this behavior from Axum? If so, what aside from the above, would you propose? And if not, does my response above quell the request?
from rocket.
Rocket does not hide potentially expensive operations from you.
Nice! I wasn't aware of that until now; I just learned it the hard way.
Now, cloning works, but beginners to Rust and/or Rocket may not be aware that they need to dereference the state first before cloning, as demonstrated below:
async fn generate_content(client: &State<Client>, input_text: String) -> String {
match (*client).clone().generate_content(&input_text).await {
Ok(response) => response,
Err(error) => error.to_string(),
}
}
While explicitly cloning the state might seem like a good theoretical solution, in practice, the state could originate from a third-party library beyond the developer's scope, and the utilized state may lack implementation for the Clone
and/or Copy
trait. In such cases, cloning is not feasible.
Following the approach adopted by Axum, implicitly cloning the state would be preferable if the state is inherently cloneable to begin with. Therefore, I would like to propose the following solution:
// Auto implement the `FromRequest` trait at compile time?
async fn generate_content(client: &mut State<Client>, input_text: String) -> String {
//...snip...
}
// or
async fn generate_content(State(mut client): &State<Client>, input_text: String) -> String {
//...snip...
}
If the user indicates that client
is mutable in the function argument, then allow borrowing as mutable or implicitly cloning the state.
Best
from rocket.
All that being said, none of this has much to do with mutability. Axum (or anything else in Rust) doesn't (and can't) magically let you share mutable state across threads. It's simply forbidden to share mutable state. You can, however, share state immutably that offers interior mutability, which effectively means using unsafe
to work-around this restriction. This is what types like Mutex<T>
do and libraries like dashmap
offer. But it's not what axum
does.
The reason your axum
example "works" is because it's cloning Client
, and you're getting an owned handle to the cloned object which you bind mutably. It's not doing anything interesting to allow you to share state mutably.
from rocket.
Rocket gives you a direct reference - this is superior in every way except perhaps the need to call .clone() when that's what you actually want. Though even that can be refuted as running counter to the notion of zero-cost abstractions.
That's actually a good point, and it aligns with the idea of keeping things efficient and giving the developer the ultimate power over things. Additionally, the example you provided about implementing the FromRequest
trait, it's kind of what I mentioned about with the "Auto implement the FromRequest
trait at compile time?" comment in the code, but automatically generate this implementation. I'm not sure how hard it would be to implement it, but it's definitely something we could improve on.
Now, despite my skill issues and even though I'm still figuring things out with Rocket, there's something that a lot of backend developers might be wondering about. Maybe we could update the docs about state to clear things up a bit. In any case, I just wanted to bring this up to your attention that sates mutability is something that a lot might be wondering about.
That's pretty much it, feel free to close the issue if you think it is already sorted out.
Best
from rocket.
Related Issues (20)
- Supply PanicInfo to Catchers where applicable HOT 2
- (Solved) Rocket database fairing panicking while connecting to dockerized postgres on MacOS Sonoma HOT 1
- how to return error as a Json from FromParam HOT 3
- Responder enums not serializing like expected HOT 1
- FileServer can serve pre-gzipped content if it exists on the filesystem HOT 1
- Cookies aren't read by get methods but it exists in the browser HOT 2
- HTTP3/QUIC support HOT 15
- Add HTMLStream HOT 5
- cookie removal and Microsoft Edge HOT 7
- Inject script to auto-reload browser when Rocket restarts
- Rocket App Hangs HOT 5
- DefaultListener::bindable() isnβt usable HOT 8
- Allow routes that match any method HOT 4
- Hyper and Rocket disagreeing on validity of URL HOT 3
- Allow from form macro to work on structs with range HOT 4
- Clippy Lint w/ FromForm derive HOT 7
- Possible Incompleteness HOT 1
- Possible Incompleteness HOT 1
- doc: change `&ContentType` with `&Accept` in the list of implementations of `FromRequest` HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rocket.