Rocket change state to new_state


#1

Hi, I’m new to Rust, and so far compiler messages where good enough to keep me going. But now I encountered something I can’t deal with on my own.

I wanted to create a very simple app with Rocket framework. I don’t want to use database and since Rocket allows me to keep state I wanted to use that. But what one route does is change the state to completely new one.

#[get("/update")]
fn update(tld_vec: State<TLD>) -> &'static str {
    match get_update_from_url(&"") {
        Some(new_state) => {
>>>>        tld_vec.tld = new_state;
            "Updated"
        }
        None => "Update Failed",
    }
}

In the line above I don’t know change old to new state. I don’t know how to make tld_vec mutable, please help :slight_smile:

Here is full code: https://gist.github.com/sztosz/96cd0cbf3dda8f22f0de5eea693e1398

PS. It’s just a learning project, to see how can something like this be implemented in Rust (I have working implementation in Elixir), to see how many obstacles will I encounter when doing such trivial in terms of length, but no so trivial in logic project. I wan’t to evaluate if it’s even viable for me to learn Rust some more or just stick with Elixir for now, and although I know those have some different purpose, I it may be good to have the distributed fault tolerance of Elixir along with the memory safety and raw speed of Rust in my arsenal.


#2

fn update(tld_vec: State<TLD>)

Mutable version will be mut tld_vec: State<TLD>. The syntax of the arguments is similar to let, so it’s like let mut tld_vec: State<TLD> = value.

(Usually in Rust you’d pass mutable values using fn update(tld_vec: &mut State<TLD>), so that the ownership is not given to the function (which would free the value at the end of the function if the function doesn’t save it anywhere else), but in this case I see you’re handling input of a request, so it’s ok.)


#3

Unfortunately it’s not that simple. Whatever I try to do, wherever I try add mut it complains. It has to do something with how does Rocket manages state I believe :confused:


#4

I suppose it may be unsupported by Rocket’s macro parser? Try:

fn update(tld_vec: State<TLD>) -> &'static str {
let mut tld_vec = tld_vec;
…
}

In Rust you can shadow variables, and it’s legal to make a value mutable if you own it.


#5

I tried this:

#[get("/update")]
fn update(tld_vec: State<TLD>) -> &'static str {
    match get_update_from_url(&"") {
        Some(new_state) => {
            let mut tld_vec = tld_vec;
            tld_vec.tld = new_state;
            "Updated"
        }
        None => "Update Failed",
    }
}

and got this:

error: cannot assign to immutable field
  --> src/main.rs:38:13
   |
38 |             tld_vec.tld = new_state;
   |             ^^^^^^^^^^^^^^^^^^^^^^^ cannot mutably borrow immutable field

#6

It should work:

https://is.gd/WLN3a6

so it might be worth reporting this as a bug to Rocket.


#7

I had a good night sleep. And now I think it’s by design. That State is shared by probably infinite threads that can be spawned to answer HTTP requests. So It makes sense for it not being mutable. And If I needed mutable state it would be, probably, wiser to devise my own solution.

But I’ll ask on Rocket IRC over the weekend just to be sure, and if it’s a bug I will report it.

And thank you for your help :slight_smile:


#8

I think you’ll want a Mutex wrapped around your data to allow mutating it safely.


#9

I used in the end

struct TLD {
    tld: RwLock<Vec<String>>,
}

And in the functions using that struct
let found = state.tld.read().unwrap() and *state.tld.write().unwrap() = new_state;
And it’s working :slight_smile:

I tried to do it with AtomicPtr but had to use unsafe, and in the end my app exited without stacktrace but with return code 1 instead of 0 So i said to myself, that few days with rust is way too little to fiddle with unsafe :blush:


#10

Oh yeah, I should probably be using RwLock in my code, too! Thanks for posting about your solution :slight_smile: