From 9dca0867a183ad8698eef58ff423a2379f97d6c0 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Fri, 28 Mar 2025 15:38:33 +0000 Subject: [PATCH] Add Ref/RefMut::map_split Closes #337 --- src/mapref/multiple.rs | 26 ++++++------- src/mapref/one.rs | 84 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 95 insertions(+), 15 deletions(-) diff --git a/src/mapref/multiple.rs b/src/mapref/multiple.rs index 053eb18b..7ea3de92 100644 --- a/src/mapref/multiple.rs +++ b/src/mapref/multiple.rs @@ -3,13 +3,13 @@ use core::hash::Hash; use core::ops::{Deref, DerefMut}; use std::sync::Arc; -pub struct RefMulti<'a, K, V> { - _guard: Arc>, - k: &'a K, - v: &'a V, +pub struct RefMulti<'a, K, V: ?Sized> { + pub(super) _guard: Arc>, + pub(super) k: &'a K, + pub(super) v: &'a V, } -impl<'a, K: Eq + Hash, V> RefMulti<'a, K, V> { +impl<'a, K: Eq + Hash, V: ?Sized> RefMulti<'a, K, V> { pub(crate) fn new(guard: Arc>, k: &'a K, v: &'a V) -> Self { Self { _guard: guard, @@ -31,7 +31,7 @@ impl<'a, K: Eq + Hash, V> RefMulti<'a, K, V> { } } -impl<'a, K: Eq + Hash, V> Deref for RefMulti<'a, K, V> { +impl<'a, K: Eq + Hash, V: ?Sized> Deref for RefMulti<'a, K, V> { type Target = V; fn deref(&self) -> &V { @@ -39,13 +39,13 @@ impl<'a, K: Eq + Hash, V> Deref for RefMulti<'a, K, V> { } } -pub struct RefMutMulti<'a, K, V> { - _guard: Arc>, - k: &'a K, - v: &'a mut V, +pub struct RefMutMulti<'a, K, V: ?Sized> { + pub(super) _guard: Arc>, + pub(super) k: &'a K, + pub(super) v: &'a mut V, } -impl<'a, K: Eq + Hash, V> RefMutMulti<'a, K, V> { +impl<'a, K: Eq + Hash, V: ?Sized> RefMutMulti<'a, K, V> { pub(crate) fn new(guard: Arc>, k: &'a K, v: &'a mut V) -> Self { Self { _guard: guard, @@ -75,7 +75,7 @@ impl<'a, K: Eq + Hash, V> RefMutMulti<'a, K, V> { } } -impl<'a, K: Eq + Hash, V> Deref for RefMutMulti<'a, K, V> { +impl<'a, K: Eq + Hash, V: ?Sized> Deref for RefMutMulti<'a, K, V> { type Target = V; fn deref(&self) -> &V { @@ -83,7 +83,7 @@ impl<'a, K: Eq + Hash, V> Deref for RefMutMulti<'a, K, V> { } } -impl<'a, K: Eq + Hash, V> DerefMut for RefMutMulti<'a, K, V> { +impl<'a, K: Eq + Hash, V: ?Sized> DerefMut for RefMutMulti<'a, K, V> { fn deref_mut(&mut self) -> &mut V { self.value_mut() } diff --git a/src/mapref/one.rs b/src/mapref/one.rs index faf47d9c..ab49b8f7 100644 --- a/src/mapref/one.rs +++ b/src/mapref/one.rs @@ -1,7 +1,13 @@ -use crate::lock::{RwLockReadGuardDetached, RwLockWriteGuardDetached}; +use crate::{ + lock::{RwLockReadGuardDetached, RwLockWriteGuardDetached}, + mapref::multiple::{RefMulti, RefMutMulti}, +}; use core::hash::Hash; use core::ops::{Deref, DerefMut}; -use std::fmt::{Debug, Formatter}; +use std::{ + fmt::{Debug, Formatter}, + sync::Arc, +}; pub struct Ref<'a, K, V> { _guard: RwLockReadGuardDetached<'a>, @@ -55,6 +61,29 @@ impl<'a, K: Eq + Hash, V> Ref<'a, K, V> { Err(self) } } + + pub fn map_split( + self, + f: F, + ) -> (RefMulti<'a, K, A>, RefMulti<'a, K, B>) + where + F: FnOnce(&V) -> (&A, &B), + { + let (a, b) = f(self.v); + let guard = Arc::new(self._guard); + ( + RefMulti { + _guard: guard.clone(), + k: self.k, + v: a, + }, + RefMulti { + _guard: guard, + k: self.k, + v: b, + }, + ) + } } impl<'a, K: Eq + Hash + Debug, V: Debug> Debug for Ref<'a, K, V> { @@ -140,6 +169,29 @@ impl<'a, K: Eq + Hash, V> RefMut<'a, K, V> { v, }) } + + pub fn map_split( + self, + f: F, + ) -> (RefMutMulti<'a, K, A>, RefMutMulti<'a, K, B>) + where + F: FnOnce(&mut V) -> (&mut A, &mut B), + { + let (a, b) = f(self.v); + let guard = Arc::new(self.guard); + ( + RefMutMulti { + _guard: guard.clone(), + k: self.k, + v: a, + }, + RefMutMulti { + _guard: guard, + k: self.k, + v: b, + }, + ) + } } impl<'a, K: Eq + Hash + Debug, V: Debug> Debug for RefMut<'a, K, V> { @@ -373,6 +425,34 @@ mod tests { }; } + #[test] + fn ref_map_split() { + struct Data(String, String); + let data = DashMap::new(); + data.insert("test", Data("hello".to_string(), "world".to_string())); + if let Some(b_ref) = data.get("test") { + let (l_ref, r_ref) = b_ref.map_split(|d| (&d.0, &d.1)); + + assert_eq!(l_ref.value(), "hello"); + assert_eq!(r_ref.value(), "world"); + }; + } + + #[test] + fn ref_mut_map_split() { + let data = DashMap::new(); + data.insert("test", "hello world".to_string()); + if let Some(b_ref) = data.get_mut("test") { + let (mut l_ref, r_ref) = b_ref.map_split(|d| d.split_at_mut(5)); + + assert_eq!(l_ref.value(), "hello"); + assert_eq!(r_ref.value(), " world"); + l_ref.make_ascii_uppercase(); + }; + let Some(b_ref) = data.get("test") else { panic!("") }; + assert_eq!(b_ref.value(), "HELLO world"); + } + #[test] fn mapped_ref_again() { let data = DashMap::new();