use std::{sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}, cmp::Ordering, hash::{Hash, Hasher}, mem::swap};
#[derive(Debug)]
pub struct SyncCell<T: ?Sized> {
data: RwLock<T>,
}
impl <T> SyncCell<T> {
pub const fn new(data: T) -> Self {
Self {
data: RwLock::new(data)
}
}
pub fn set(&self, value: T) {
match self.data.write() {
Ok(mut data) => *data = value,
Err(err) => panic!("Failed to set cell value. Lock was poisoned: {}", err),
}
}
pub fn into_inner(self) -> T {
match self.data.into_inner() {
Ok(data) => data,
Err(err) => panic!("Failed to get cell value. Lock was poisoned: {}", err),
}
}
pub fn replace(&self, mut value: T) -> T {
match self.data.write() {
Ok(mut data) => {
swap(&mut *data, &mut value);
value
},
Err(err) => panic!("Failed to set cell value. Lock was poisoned: {}", err),
}
}
}
impl <T: ?Sized> SyncCell<T> {
pub fn borrow(&self) -> RwLockReadGuard<T> {
match self.data.read() {
Ok(data) => data,
Err(err) => panic!("Failed to get cell value. Lock was poisoned: {}", err),
}
}
pub fn borrow_mut(&self) -> RwLockWriteGuard<T> {
match self.data.write() {
Ok(data) => data,
Err(err) => panic!("Failed to get cell value. Lock was poisoned: {}", err),
}
}
}
impl <T: Clone> SyncCell<T> {
pub fn get(&self) -> T {
match self.data.read() {
Ok(data) => data.clone(),
Err(err) => panic!("Failed to get cell value. Lock was poisoned: {}", err),
}
}
}
impl <T: Clone> Clone for SyncCell<T> {
fn clone(&self) -> Self {
Self::new(self.get())
}
}
impl <T: Default> Default for SyncCell<T> {
fn default() -> Self {
Self::new(T::default())
}
}
impl <T: PartialEq + ?Sized> PartialEq for SyncCell<T> {
fn eq(&self, other: &Self) -> bool {
self.borrow().eq(&*other.borrow())
}
}
impl <T: Eq + ?Sized> Eq for SyncCell<T> {
}
impl <T: PartialOrd + ?Sized> PartialOrd for SyncCell<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.borrow().partial_cmp(&*other.borrow())
}
}
impl <T: Ord + ?Sized> Ord for SyncCell<T> {
fn cmp(&self, other: &Self) -> Ordering {
self.borrow().cmp(&*other.borrow())
}
}
impl <T: Hash + ?Sized> Hash for SyncCell<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.borrow().hash(state)
}
}
impl <T> From<T> for SyncCell<T> {
fn from(value: T) -> Self {
Self::new(value)
}
}
pub struct HeldSyncCell<T> {
current_value: SyncCell<T>,
next_value: SyncCell<Option<T>>,
}
impl <T> HeldSyncCell<T> {
pub const fn new(data: T) -> Self {
Self {
current_value: SyncCell::new(data),
next_value: SyncCell::new(None),
}
}
pub fn set(&self, value: T) {
self.next_value.set(Some(value))
}
pub fn into_inner(self) -> T {
self.next_value.into_inner()
.unwrap_or(self.current_value.into_inner())
}
pub fn borrow(&self) -> RwLockReadGuard<T> {
self.current_value.borrow()
}
pub fn borrow_mut(&self) -> RwLockWriteGuard<T> {
self.current_value.borrow_mut()
}
pub fn has_update(&self) -> bool {
self.next_value.borrow().is_some()
}
pub fn update(&self) {
if let Some(next) = self.next_value.replace(None) {
self.current_value.set(next);
}
}
}
impl <T: Clone> HeldSyncCell<T> {
pub fn get(&self) -> T {
self.current_value.get()
}
}
impl <T: Clone> Clone for HeldSyncCell<T> {
fn clone(&self) -> Self {
Self::new(self.get())
}
}
impl <T: Default> Default for HeldSyncCell<T> {
fn default() -> Self {
Self::new(T::default())
}
}
impl <T: PartialEq> PartialEq for HeldSyncCell<T> {
fn eq(&self, other: &Self) -> bool {
self.borrow().eq(&*other.borrow())
}
}
impl <T: Eq> Eq for HeldSyncCell<T> {
}
impl <T: PartialOrd> PartialOrd for HeldSyncCell<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.borrow().partial_cmp(&*other.borrow())
}
}
impl <T: Ord> Ord for HeldSyncCell<T> {
fn cmp(&self, other: &Self) -> Ordering {
self.borrow().cmp(&*other.borrow())
}
}
impl <T: Hash> Hash for HeldSyncCell<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.borrow().hash(state)
}
}
impl <T> From<T> for HeldSyncCell<T> {
fn from(value: T) -> Self {
Self::new(value)
}
}
#[cfg(test)]
mod tests {
use core::panic;
use std::{thread, sync::Arc};
use crate::{SyncCell, HeldSyncCell};
#[test]
pub fn test_sync_cell_new() {
let _cell = SyncCell::new(1);
}
#[test]
pub fn test_sync_cell_set() {
let cell = SyncCell::new(2);
cell.set(3);
assert_eq!(3, cell.get())
}
#[test]
pub fn test_sync_cell_get() {
let cell = SyncCell::new(4);
assert_eq!(4, cell.get())
}
#[test]
pub fn test_sync_cell_replace() {
let cell = SyncCell::new(2);
let old = cell.replace(3);
assert_eq!(2, old);
assert_eq!(3, cell.get())
}
#[test]
#[should_panic]
pub fn test_sync_cell_replace_poisoned() {
let cell = Arc::new(SyncCell::new(4));
let cell2 = cell.clone();
let _ = thread::spawn(move || {
let _borrow = cell2.borrow();
panic!("Intentional panic.");
}).join();
let old = cell.replace(3);
assert_ne!(2, old);
assert_ne!(3, cell.get())
}
#[test]
pub fn test_sync_cell_into_inner() {
let cell = SyncCell::new(4);
assert_eq!(4, cell.into_inner())
}
#[test]
pub fn test_sync_cell_mutable_borrow() {
let cell = SyncCell::new(4);
let mut borrow = cell.borrow_mut();
*borrow = 5;
drop(borrow);
assert_eq!(5, cell.get())
}
#[test]
#[should_panic]
pub fn test_sync_cell_mutable_borrow_poisoned() {
let cell = Arc::new(SyncCell::new(4));
let cell2 = cell.clone();
let _ = thread::spawn(move || {
let _borrow = cell2.borrow();
panic!("Intentional panic.");
}).join();
let mut borrow = cell.borrow_mut();
*borrow = 5;
drop(borrow);
assert_ne!(5, cell.get())
}
#[test]
#[should_panic]
pub fn test_sync_cell_get_poisoned() {
let cell = Arc::new(SyncCell::new(4));
let cell2 = cell.clone();
let _ = thread::spawn(move || {
let _borrow = cell2.borrow();
panic!("Intentional panic.");
}).join();
assert_ne!(4, cell.get())
}
#[test]
#[should_panic]
pub fn test_sync_cell_set_poisoned() {
let cell = Arc::new(SyncCell::new(4));
let cell2 = cell.clone();
let _ = thread::spawn(move || {
let _borrow = cell2.borrow();
panic!("Intentional panic.");
}).join();
cell.set(5);
assert_ne!(5, cell.get());
}
#[test]
pub fn test_held_sync_cell_new() {
let _cell = HeldSyncCell::new(0);
}
#[test]
pub fn test_held_sync_cell_get() {
let cell = HeldSyncCell::new(1);
assert_eq!(1, cell.get())
}
#[test]
pub fn test_held_sync_cell_set_no_update() {
let cell = HeldSyncCell::new(1);
cell.set(2);
assert_eq!(true, cell.has_update());
assert_eq!(1, cell.get())
}
#[test]
pub fn test_held_sync_cell_set_update() {
let cell = HeldSyncCell::new(1);
cell.set(2);
cell.update();
assert_eq!(false, cell.has_update());
assert_eq!(2, cell.get())
}
#[test]
pub fn test_held_sync_cell_set_double_update() {
let cell = HeldSyncCell::new(1);
cell.set(2);
cell.update();
cell.update();
assert_eq!(false, cell.has_update());
assert_eq!(2, cell.get())
}
#[test]
pub fn test_held_sync_cell_no_set_update() {
let cell = HeldSyncCell::new(1);
cell.update();
assert_eq!(false, cell.has_update());
assert_eq!(1, cell.get())
}
#[test]
pub fn test_held_sync_cell_no_set() {
let cell = HeldSyncCell::new(1);
assert_eq!(false, cell.has_update());
assert_eq!(1, cell.get())
}
#[test]
pub fn test_held_sync_cell_into_inner() {
let cell = HeldSyncCell::new(4);
assert_eq!(4, cell.into_inner())
}
#[test]
pub fn test_held_sync_cell_set_into_inner() {
let cell = HeldSyncCell::new(4);
cell.set(5);
assert_eq!(5, cell.into_inner())
}
#[test]
pub fn test_held_sync_cell_set_update_into_inner() {
let cell = HeldSyncCell::new(4);
cell.set(5);
cell.update();
assert_eq!(5, cell.into_inner())
}
#[test]
pub fn test_held_sync_cell_mutable_borrow() {
let cell = HeldSyncCell::new(4);
let mut borrow = cell.borrow_mut();
*borrow = 5;
drop(borrow);
assert_eq!(5, cell.get())
}
#[test]
pub fn test_held_sync_cell_mutable_borrow_set() {
let cell = HeldSyncCell::new(4);
let mut borrow = cell.borrow_mut();
*borrow = 5;
cell.set(6);
drop(borrow);
assert_eq!(5, cell.get());
cell.update();
assert_eq!(6, cell.get());
}
}