I want to implement two different structures that have references to each other, can mutate each other, and are thread-safe.
I can introduce the following example:
pub struct Player {
pub x: f32,
pub y: f32,
game: Option<Game>, // Reference to `Game`
}
impl Player {
pub fn new(x: f32, y: f32) -> Self {
Player { x, y, game: None}
}
// Some functions that can change `self`, `game`, and `map`
}
pub struct Game {
pub map: GameMap,
players: Vec<Player>, // Reference to `Player`
}
impl Game {
pub fn new() -> Self {
Game { map: GameMap::new(), players: Vec::new()}
}
pub fn register_player(&mut self, player: Player) {
todo!();
}
}
I'd like to have a similar interface:
fn main() {
let mut p1 = Player::new(0.0, 0.0);
let mut p2 = Player::new(100.0, 100.0);
let mut game = Game::new();
game.register_player(p1);
game.register_player(p2);
p1.forward(); // changes its coordinates using `map` from `game`
p2.shoot(); // changes the `map` and possibly another player
}
I can't use std::rc::Rc and std::cell::RefCell because my goal is to write thread-safety code. I tried std::sync::{Arc, Mutex}, but it's not succeeded yet. How could I solve this challenge?
UPD Here I add the code where I tried to use mutex
use std::sync::{Arc, Mutex};
pub struct Player {
pub x: f32,
pub y: f32,
game: Option<Arc<Mutex<Game>>>,
}
impl Player {
pub fn create(x: f32, y: f32) -> Arc<Mutex<Self>> {
let mut player = Player {
x,
y,
game: None,
};
Arc::new(Mutex::new(player))
}
pub fn mount_game(&mut self, game: Arc<Mutex<Game>>) {
self.game = Some(game);
}
}
pub struct Game {
players: Vec<Arc<Mutex<Player>>>,
}
impl Game {
pub fn create() -> Arc<Mutex<Self>> {
let mut game = Game {
players: Vec::new(),
};
Arc::new(Mutex::new(game))
}
pub fn register_player(&self, game_arc: Arc<Mutex<Self>>, player_arc: Arc<Mutex<Player>>) {
let mut game = game_arc.lock().unwrap();
game.players.push(Arc::clone(&player_arc));
player_arc.lock().unwrap().mount_game(Arc::clone(&game_arc));
}
}
fn main() {
let mut p1 = Player::create(0.0, 0.0);
let mut p2 = Player::create(0.0, 0.0);
let mut game = Game::create();
game.lock().unwrap().register_player(Arc::clone(&game), Arc::clone(&p1));
game.lock().unwrap().register_player(Arc::clone(&game), Arc::clone(&p2));
}
Arc<Mutex<_>>because that is the right type for thread-safe interior mutability. (Though there may still be other types that would work better for your use case.)Arc<Mutex<_>>with my context to code mutable cross-references, it'd be unbelievable