use std::sync::Arc; use parking_lot::{ MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockUpgradableReadGuard, RwLockWriteGuard, }; #[derive(Debug, Clone)] pub struct Draft { inner: Arc)>>, } impl From for Draft { fn from(data: T) -> Self { Self { inner: Arc::new(RwLock::new((data, None))), } } } /// Implements draft management for `Box`, allowing for safe concurrent editing and committing of draft data. /// # Type Parameters /// - `T`: The underlying data type, which must implement `Clone` and `ToOwned`. /// /// # Methods /// - `data_mut`: Returns a mutable reference to the committed data. /// - `data_ref`: Returns an immutable reference to the committed data. /// - `draft_mut`: Creates or retrieves a mutable reference to the draft data, cloning the committed data if no draft exists. /// - `latest_ref`: Returns an immutable reference to the draft data if it exists, otherwise to the committed data. /// - `apply`: Commits the draft data, replacing the committed data and returning the old committed value if a draft existed. /// - `discard`: Discards the draft data and returns it if it existed. impl Draft> { /// 可写正式数据 pub fn data_mut(&self) -> MappedRwLockWriteGuard<'_, Box> { RwLockWriteGuard::map(self.inner.write(), |inner| &mut inner.0) } /// 返回正式数据的只读视图(不包含草稿) pub fn data_ref(&self) -> MappedRwLockReadGuard<'_, Box> { RwLockReadGuard::map(self.inner.read(), |inner| &inner.0) } /// 创建或获取草稿并返回可写引用 pub fn draft_mut(&self) -> MappedRwLockWriteGuard<'_, Box> { let guard = self.inner.upgradable_read(); if guard.1.is_none() { let mut guard = RwLockUpgradableReadGuard::upgrade(guard); guard.1 = Some(guard.0.clone()); return RwLockWriteGuard::map(guard, |inner| { inner.1.as_mut().unwrap_or_else(|| { unreachable!("Draft was just created above, this should never fail") }) }); } // 已存在草稿,升级为写锁映射 RwLockWriteGuard::map(RwLockUpgradableReadGuard::upgrade(guard), |inner| { inner .1 .as_mut() .unwrap_or_else(|| unreachable!("Draft should exist when guard.1.is_some()")) }) } /// 零拷贝只读视图:返回草稿(若存在)或正式值 pub fn latest_ref(&self) -> MappedRwLockReadGuard<'_, Box> { RwLockReadGuard::map(self.inner.read(), |inner| { inner.1.as_ref().unwrap_or(&inner.0) }) } /// 尝试获取最新只读视图,若当前持有写锁则返回 `None` pub fn try_latest_ref(&self) -> Option>> { self.inner .try_read() .map(|guard| RwLockReadGuard::map(guard, |inner| inner.1.as_ref().unwrap_or(&inner.0))) } /// 提交草稿,返回旧正式数据 pub fn apply(&self) -> Option> { let mut inner = self.inner.write(); inner .1 .take() .map(|draft| std::mem::replace(&mut inner.0, draft)) } /// 丢弃草稿,返回被丢弃的草稿 pub fn discard(&self) -> Option> { self.inner.write().1.take() } /// 异步修改正式数据,闭包直接获得 Box 所有权 pub async fn with_data_modify(&self, f: F) -> Result where T: Send + Sync + 'static, F: FnOnce(Box) -> Fut + Send, Fut: std::future::Future, R), E>> + Send, E: From, { // 克隆正式数据 let local = { let guard = self.inner.read(); guard.0.clone() }; // 异步闭包执行,返回修改后的 Box 和业务结果 R let (new_local, res) = f(local).await?; // 写回正式数据 let mut guard = self.inner.write(); guard.0 = new_local; Ok(res) } } #[test] fn test_draft_box() { use crate::config::IVerge; // 1. 创建 Draft> let verge = Box::new(IVerge { enable_auto_launch: Some(true), enable_tun_mode: Some(false), ..IVerge::default() }); let draft = Draft::from(verge); // 2. 读取正式数据(data_mut) { let data = draft.data_mut(); assert_eq!(data.enable_auto_launch, Some(true)); assert_eq!(data.enable_tun_mode, Some(false)); } // 3. 初次获取草稿(draft_mut 会自动 clone 一份) { let draft_view = draft.draft_mut(); assert_eq!(draft_view.enable_auto_launch, Some(true)); assert_eq!(draft_view.enable_tun_mode, Some(false)); } // 4. 修改草稿 { let mut d = draft.draft_mut(); d.enable_auto_launch = Some(false); d.enable_tun_mode = Some(true); } // 正式数据未变 assert_eq!(draft.data_mut().enable_auto_launch, Some(true)); assert_eq!(draft.data_mut().enable_tun_mode, Some(false)); // 草稿已变 { let latest = draft.latest_ref(); assert_eq!(latest.enable_auto_launch, Some(false)); assert_eq!(latest.enable_tun_mode, Some(true)); } // 5. 提交草稿 assert!(draft.apply().is_some()); // 第一次提交应有返回 assert!(draft.apply().is_none()); // 第二次提交返回 None // 正式数据已更新 { let data = draft.data_mut(); assert_eq!(data.enable_auto_launch, Some(false)); assert_eq!(data.enable_tun_mode, Some(true)); } // 6. 新建并修改下一轮草稿 { let mut d = draft.draft_mut(); d.enable_auto_launch = Some(true); } assert_eq!(draft.draft_mut().enable_auto_launch, Some(true)); // 7. 丢弃草稿 assert!(draft.discard().is_some()); // 第一次丢弃返回 Some assert!(draft.discard().is_none()); // 再次丢弃返回 None // 8. 草稿已被丢弃,新的 draft_mut() 会重新 clone assert_eq!(draft.draft_mut().enable_auto_launch, Some(false)); }