Search code examples
rustrust-rocket

How to change a State in Rocket framework for Rust?


I'm trying to make State type work, which should represent the state of a server. Unfortunately I receive this error:

error[E0596]: cannot borrow data in dereference of `rocket::State<FunnyDatabase>` as mutable
 --> src\routes.rs:9:25
  |
9 |     if let Some(room) = rooms.0.iter_mut().find(|room| room.name == room_id) {
  |                         ^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
  |
  = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `rocket::State<FunnyDatabase>`

For the fragment:

#[post("/join_room/<room_id>/<player_name>")]
pub fn join_room(room_id: String, player_name: String, rooms: &State<FunnyDatabase>) -> (Status, (ContentType, String)) { 
    if let Some(room) = rooms.0.iter_mut().find(|room| room.name == room_id) {
        room.players.push_back(Player{ name: player_name.clone(), card: "UNKNOWN".to_string() });
    }
...

Where FunnyDatabase is a mock of a database:

pub struct FunnyDatabase(pub LinkedList<Room>);

State should be managed:

rocket::build()
    .manage(FunnyDatabase(LinkedList::<Room>::new()))
...

Room is a simple struct:

pub struct Room {
    pub name: String,
    pub players: LinkedList<Player>
}

How can I solve the issue, how can I understand how to deal with this kind of issues?

I am using Rocket version "0.5.0-rc.3" and Rust version 1.68.2

I've tried forcing the type to be mutable but unfortunately it does not work. I've searched for hours information about changing the state in this framework and found nothing about it. The documentation only mentions retrieving the state but nothing about changing it. Search engine does not provide any results. Is this structure effectively a legacy code? Should I use something else to achieve my goal of storing a collection of Room in which is a collection of Player?

I'll appreciate your guidance!


Solution

  • You need to use a type with interior mutability. For example, Mutex.

    pub struct Room {
        pub name: String,
        pub players: Mutex<LinkedList<Player>>
    }
    

    Then you can modify your list by locking the mutex.

    if let Some(room) = rooms.0.iter().find(|room| room.name == room_id) {
        room.players.lock().unwrap().push_back(Player {
            name: player_name.clone(),
            card: "UNKNOWN".to_string()
        });
    }
    

    There's also RwLock, and many more interior mutability primitives outside the standard library, such as those in parking_lot.