1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! Helper type for making configurations mutable.

use std::sync::{Arc, RwLock};

/// A mutable configuration object.
///
/// Internally, this is just a `RwLock<Arc<T>>`; this type just defines some
/// convenience wrappers for it.
#[derive(Debug)]
pub struct MutCfg<T> {
    /// The interior configuration object.
    cfg: RwLock<Arc<T>>,
}

impl<T> MutCfg<T> {
    /// Return a new MutCfg with the provided value.
    pub fn new(config: T) -> Self {
        Self {
            cfg: RwLock::new(Arc::new(config)),
        }
    }

    /// Return the current configuration
    pub fn get(&self) -> Arc<T> {
        Arc::clone(&self.cfg.read().expect("poisoned lock"))
    }

    /// If this configuration object is still the same pointer as `old_config`,
    /// replace it with `new_config`.
    ///
    /// Returns `true` if it was in fact replaced.
    pub fn check_and_replace(&self, old_config: &Arc<T>, new_config: T) -> bool {
        let mut cfg = self.cfg.write().expect("poisoned lock");
        if Arc::ptr_eq(&cfg, old_config) {
            *cfg = Arc::new(new_config);
            true
        } else {
            false
        }
    }

    /// Replace this configuration with `new_config`.
    pub fn replace(&self, new_config: T) {
        *self.cfg.write().expect("poisoned lock") = Arc::new(new_config);
    }

    /// Replace the current configuration with the results of evaluating `func` on it.
    pub fn map_and_replace<F>(&self, func: F)
    where
        F: FnOnce(&Arc<T>) -> T,
    {
        let mut cfg = self.cfg.write().expect("poisoned lock");
        let new_cfg = func(&cfg);
        *cfg = Arc::new(new_cfg);
    }
}

impl<T: Default> Default for MutCfg<T> {
    fn default() -> Self {
        MutCfg::new(T::default())
    }
}

impl<T> From<T> for MutCfg<T> {
    fn from(config: T) -> MutCfg<T> {
        MutCfg::new(config)
    }
}

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

    #[test]
    fn basic_constructors() {
        let m = MutCfg::new(7_u32);
        assert_eq!(*m.get(), 7);
        let m: MutCfg<u32> = MutCfg::default();
        assert_eq!(*m.get(), 0);
        let m: MutCfg<u32> = 100.into();
        assert_eq!(*m.get(), 100);
    }

    #[test]
    fn mutate_with_existing_ref() {
        let m = MutCfg::new(100_u32);
        let old_ref = m.get();
        m.replace(101);
        assert_eq!(*old_ref, 100);
        assert_eq!(*m.get(), 101);
    }

    #[test]
    fn check_and_replace() {
        let m = MutCfg::new(100_u32);
        let different_100 = Arc::new(100_u32);
        // won't replace, since it is a different arc.
        assert!(!m.check_and_replace(&different_100, 200));
        let old_100 = m.get();
        assert_eq!(*old_100, 100);
        assert!(m.check_and_replace(&old_100, 200));
        assert_eq!(*m.get(), 200);
    }

    #[test]
    fn map_and_replace() {
        let m = MutCfg::new(100_u32);
        let m_old = m.get();
        m.map_and_replace(|old_val| **old_val * 20);
        assert_eq!(*m.get(), 2000);
        assert_eq!(*m_old, 100);
    }
}