use std::sync::Mutex;
pub struct Shared<T>(Mutex<T>);
impl<T> Shared<T> {
pub const fn new(value: T) -> Self {
Self(Mutex::new(value))
}
#[must_use]
pub fn get(&self) -> T
where
T: Clone,
{
self.0.lock().unwrap().clone()
}
pub fn set(&self, value: T) {
*self.0.lock().unwrap() = value;
}
pub fn update<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
f(&mut self.0.lock().unwrap())
}
}
impl<T: Default> Default for Shared<T> {
fn default() -> Self {
Self::new(T::default())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_then_get_round_trips() {
let s = Shared::new(7u32);
assert_eq!(s.get(), 7);
}
#[test]
fn set_overwrites() {
let s = Shared::new(1u32);
s.set(42);
assert_eq!(s.get(), 42);
}
#[test]
fn update_mutates_in_place_and_returns() {
let s = Shared::new(10u32);
let doubled = s.update(|v| {
*v *= 2;
*v
});
assert_eq!(doubled, 20);
assert_eq!(s.get(), 20);
}
#[test]
fn default_is_inner_default() {
let s: Shared<Option<String>> = Shared::default();
assert_eq!(s.get(), None);
}
#[test]
fn models_latest_tag_to_commits_handoff() {
let s: Shared<Option<String>> = Shared::default();
assert_eq!(s.get(), None);
s.set(Some("deadbeef".to_string()));
assert_eq!(s.get(), Some("deadbeef".to_string()));
}
}