How to use mutex as a member of a struct?

use std::{collections::VecDeque, sync::Arc};
use tokio::sync::Mutex;

struct Human {
    name: [u8; 20],
    old: u32,
}

struct Company {
    employees: VecDeque<Human>,
    mutex: Arc<Mutex<VecDeque<Human>>>,
}

impl Company {
    pub fn new() -> Company {
        let mut com = Company {
            employees: VecDeque::new(),
            mutex: Arc::new(Mutex::new(VecDeque::new())),
        };

        com.mutex = Arc::new(Mutex::new(com.employees));
        com // err: partial move occurs because `com.employees` has type `VecDeque<Human>`, which does not implement the `Copy` trait
    }

    pub async fn push(&self, human: Human)
    {
        let mut employees = self.mutex.lock().await;
        employees.push_back(human);
    }
}

The problem is not the mutex, the problem is self-referential structs. In short, try not to do it.

1 Like

The reason you can't do that particular thing is because it would allow you to create two mutable references to the same VecDeque at the same time, which is never supposed to be possible. You would be able to do it through steps like these:

let Company {employees, mutex} = &mut com;
let mut guard = mutex.try_lock().unwrap();
let ref1: &mut VecDeque<Human> = employees;
let ref2: &mut VecDeque<Human> = &mut guard;
/// ref1 and ref2 would point to the same place if your code compiled

It's not entirely clear what you're trying to accomplish here, but I'm going to take a guess that you don't actually need the employees field. I'm guessing you put it there because you thought you needed to do that in order to give the struct ownership over the VecDeque. An Arc already has ownership, so you can get rid of that field entirely and just have the Arc<Mutex<VecDeque<Human>>>.

2 Likes

This is separate from the question, but you may be interested in ArrayString, unless you work with a different encoding than UTF-8.

1 Like