use std::sync::{Arc, RwLock, Mutex};
use std::collections::HashMap;
pub trait LockValue<T> {
fn with_value<F, R>(&self, f: F) -> Option<R>
where
F: FnOnce(&T) -> R;
}
impl<T> LockValue<T> for Arc<RwLock<T>> {
fn with_value<F, R>(&self, f: F) -> Option<R>
where
F: FnOnce(&T) -> R,
{
self.read().ok().map(|guard| f(&*guard))
}
}
impl<T> LockValue<T> for Arc<Mutex<T>> {
fn with_value<F, R>(&self, f: F) -> Option<R>
where
F: FnOnce(&T) -> R,
{
self.lock().ok().map(|guard| f(&*guard))
}
}
impl<T> LockValue<T> for RwLock<T> {
fn with_value<F, R>(&self, f: F) -> Option<R>
where
F: FnOnce(&T) -> R,
{
self.read().ok().map(|guard| f(&*guard))
}
}
impl<T> LockValue<T> for Mutex<T> {
fn with_value<F, R>(&self, f: F) -> Option<R>
where
F: FnOnce(&T) -> R,
{
self.lock().ok().map(|guard| f(&*guard))
}
}
pub trait LockQueryExt<T, L>
where
L: LockValue<T>,
{
fn lock_iter(&self) -> Box<dyn Iterator<Item = LockedValueRef<'_, T, L>> + '_>;
}
pub struct LockedValueRef<'a, T, L>
where
L: LockValue<T>,
{
lock: &'a L,
_phantom: std::marker::PhantomData<T>,
}
impl<'a, T, L> LockedValueRef<'a, T, L>
where
L: LockValue<T>,
{
pub fn new(lock: &'a L) -> Self {
Self {
lock,
_phantom: std::marker::PhantomData,
}
}
pub fn with_value<F, R>(&self, f: F) -> Option<R>
where
F: FnOnce(&T) -> R,
{
self.lock.with_value(f)
}
pub fn map<F, R>(&self, f: F) -> Option<R>
where
F: FnOnce(&T) -> R,
{
self.lock.with_value(f)
}
pub fn matches<F>(&self, predicate: F) -> bool
where
F: FnOnce(&T) -> bool,
{
self.lock.with_value(predicate).unwrap_or(false)
}
}
impl<K, V> LockQueryExt<V, Arc<RwLock<V>>> for HashMap<K, Arc<RwLock<V>>>
where
K: Eq + std::hash::Hash,
{
fn lock_iter(&self) -> Box<dyn Iterator<Item = LockedValueRef<'_, V, Arc<RwLock<V>>>> + '_> {
Box::new(self.values().map(|lock| LockedValueRef::new(lock)))
}
}
impl<K, V> LockQueryExt<V, Arc<Mutex<V>>> for HashMap<K, Arc<Mutex<V>>>
where
K: Eq + std::hash::Hash,
{
fn lock_iter(&self) -> Box<dyn Iterator<Item = LockedValueRef<'_, V, Arc<Mutex<V>>>> + '_> {
Box::new(self.values().map(|lock| LockedValueRef::new(lock)))
}
}
impl<T> LockQueryExt<T, Arc<RwLock<T>>> for Vec<Arc<RwLock<T>>> {
fn lock_iter(&self) -> Box<dyn Iterator<Item = LockedValueRef<'_, T, Arc<RwLock<T>>>> + '_> {
Box::new(self.iter().map(|lock| LockedValueRef::new(lock)))
}
}
impl<T> LockQueryExt<T, Arc<Mutex<T>>> for Vec<Arc<Mutex<T>>> {
fn lock_iter(&self) -> Box<dyn Iterator<Item = LockedValueRef<'_, T, Arc<Mutex<T>>>> + '_> {
Box::new(self.iter().map(|lock| LockedValueRef::new(lock)))
}
}
impl<T> LockQueryExt<T, Arc<RwLock<T>>> for [Arc<RwLock<T>>] {
fn lock_iter(&self) -> Box<dyn Iterator<Item = LockedValueRef<'_, T, Arc<RwLock<T>>>> + '_> {
Box::new(self.iter().map(|lock| LockedValueRef::new(lock)))
}
}
impl<T> LockQueryExt<T, Arc<Mutex<T>>> for [Arc<Mutex<T>>] {
fn lock_iter(&self) -> Box<dyn Iterator<Item = LockedValueRef<'_, T, Arc<Mutex<T>>>> + '_> {
Box::new(self.iter().map(|lock| LockedValueRef::new(lock)))
}
}
pub struct LockFilterIter<'a, T, L, I, F>
where
L: LockValue<T> + 'a,
I: Iterator<Item = LockedValueRef<'a, T, L>>,
F: Fn(&T) -> bool,
{
iter: I,
predicate: F,
_phantom: std::marker::PhantomData<(&'a T, L)>,
}
impl<'a, T, L, I, F> Iterator for LockFilterIter<'a, T, L, I, F>
where
L: LockValue<T> + 'a,
I: Iterator<Item = LockedValueRef<'a, T, L>>,
F: Fn(&T) -> bool,
{
type Item = LockedValueRef<'a, T, L>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.find(|locked_ref| locked_ref.matches(&self.predicate))
}
}
pub trait LockIterExt<'a, T: 'a, L>: Iterator<Item = LockedValueRef<'a, T, L>> + Sized
where
L: LockValue<T> + 'a,
{
fn filter_locked<F>(self, predicate: F) -> LockFilterIter<'a, T, L, Self, F>
where
F: Fn(&T) -> bool,
{
LockFilterIter {
iter: self,
predicate,
_phantom: std::marker::PhantomData,
}
}
fn map_locked<F, R>(self, f: F) -> impl Iterator<Item = R> + 'a
where
F: Fn(&T) -> R + 'a,
Self: 'a,
{
self.filter_map(move |locked_ref| locked_ref.map(&f))
}
fn count_locked<F>(self, predicate: F) -> usize
where
F: Fn(&T) -> bool,
Self: 'a,
{
self.filter(|locked_ref| locked_ref.matches(&predicate))
.count()
}
fn find_locked<F>(mut self, predicate: F) -> Option<LockedValueRef<'a, T, L>>
where
F: Fn(&T) -> bool,
{
self.find(|locked_ref| locked_ref.matches(&predicate))
}
fn any_locked<F>(mut self, predicate: F) -> bool
where
F: Fn(&T) -> bool,
{
self.any(|locked_ref| locked_ref.matches(&predicate))
}
fn collect_cloned(self) -> Vec<T>
where
T: Clone,
Self: 'a,
{
self.filter_map(|locked_ref| {
locked_ref.with_value(|v| v.clone())
})
.collect()
}
}
impl<'a, T: 'a, L, I> LockIterExt<'a, T, L> for I
where
L: LockValue<T> + 'a,
I: Iterator<Item = LockedValueRef<'a, T, L>>,
{
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::{Arc, RwLock};
#[test]
fn test_rwlock_lock_value() {
let data = Arc::new(RwLock::new(42));
let result = data.with_value(|v| *v * 2);
assert_eq!(result, Some(84));
}
#[test]
fn test_mutex_lock_value() {
let data = Arc::new(Mutex::new("hello"));
let result = data.with_value(|v| v.len());
assert_eq!(result, Some(5));
}
#[test]
fn test_hashmap_lock_query() {
let mut map: HashMap<String, Arc<RwLock<i32>>> = HashMap::new();
map.insert("a".to_string(), Arc::new(RwLock::new(10)));
map.insert("b".to_string(), Arc::new(RwLock::new(20)));
map.insert("c".to_string(), Arc::new(RwLock::new(30)));
let sum: i32 = map
.lock_iter()
.map_locked(|v| *v)
.sum();
assert_eq!(sum, 60);
}
#[test]
fn test_lock_filter() {
let mut map: HashMap<String, Arc<RwLock<i32>>> = HashMap::new();
map.insert("a".to_string(), Arc::new(RwLock::new(10)));
map.insert("b".to_string(), Arc::new(RwLock::new(20)));
map.insert("c".to_string(), Arc::new(RwLock::new(30)));
let count = map
.lock_iter()
.count_locked(|v| *v > 15);
assert_eq!(count, 2);
}
#[test]
fn test_lock_any() {
let mut map: HashMap<String, Arc<RwLock<i32>>> = HashMap::new();
map.insert("a".to_string(), Arc::new(RwLock::new(10)));
map.insert("b".to_string(), Arc::new(RwLock::new(20)));
let has_large = map
.lock_iter()
.any_locked(|v| *v > 15);
assert!(has_large);
}
}