How to match a mutex protected struct field with if-let?

Source: Playground

use std::sync::{Condvar, Mutex};

#[derive(Debug)]
pub struct Worker<'a> {
    new_cond: Condvar,
    workers: Vec<&'a str>,
}

#[derive(Debug)]
pub struct Master<'a> {
    address: &'a str,
    mu_workers: Mutex<Worker<'a>>,
}

impl<'a> Master<'a> {
    fn new(master: &'a str) -> Self {
        Master {
            address: master,
            mu_workers: Mutex::new(Worker {
                new_cond: Condvar::new(),
                workers: Vec::new(),
            }),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_master() {
        let master = Master::new("master");
        let mut lock = master.mu_workers.try_lock();
        if let Ok(ref mut mutex) = lock {
            mutex.mu_workers.push("Tom");   // Err: no field `mu_workers` on type `&mut std::sync::MutexGuard<'_, Worker<'_>>`
        } else {
            println!("try_lock failed");
        }
        
        assert_eq!(master.mu_workers.lock().unwrap().workers[0], "Tom")
    }
}

You either have to make workers a pub field or provide an accessor function:

use std::sync::{Condvar, Mutex};

#[derive(Debug)]
pub struct Worker<'a> {
    new_cond: Condvar,
    workers: Vec<&'a str>,
}

impl<'a> Worker<'a> {
       
    /*pub */ fn workers(&mut self) -> &mut Vec<&'a str> {
        &mut self.workers
    }
}

#[derive(Debug)]
pub struct Master<'a> {
    address: &'a str,
    mu_workers: Mutex<Worker<'a>>,
}

impl<'a> Master<'a> {
    fn new(master: &'a str) -> Self {
        Master {
            address: master,
            mu_workers: Mutex::new(Worker {
                new_cond: Condvar::new(),
                workers: Vec::new(),
            }),
        }
    }
 
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_master() {
        let master = Master::new("master");
        let mut lock = master.mu_workers.try_lock();
        if let Ok(ref mut mutex) = lock {
            mutex.workers().push("Tom");   // Err: no field `mu_workers` on type `&mut std::sync::MutexGuard<'_, Worker<'_>>`
            assert_eq!(mutex.workers()[0], "Tom")
        } else {
            println!("try_lock failed");
        }
    }
}

(playground)

Please also note that I have to move the assert inside the if let for this to work.

1 Like

@musicmatze Thank you, it works well.