diff --git a/src-tauri/src/config/draft.rs b/src-tauri/src/config/draft.rs new file mode 100644 index 0000000..4e96462 --- /dev/null +++ b/src-tauri/src/config/draft.rs @@ -0,0 +1,112 @@ +use super::{IProfiles, IVerge}; +use parking_lot::{MappedMutexGuard, Mutex, MutexGuard}; +use serde_yaml::Mapping; +use std::sync::Arc; + +#[derive(Debug)] +pub struct Draft { + inner: Arc)>>, +} + +macro_rules! draft_define { + ($id: ident) => { + impl Draft<$id> { + pub fn data(&self) -> MappedMutexGuard<$id> { + MutexGuard::map(self.inner.lock(), |guard| &mut guard.0) + } + + pub fn draft(&self) -> MappedMutexGuard<$id> { + MutexGuard::map(self.inner.lock(), |mut inner| { + if inner.1.is_none() { + inner.1 = Some(inner.0.clone()); + } + + inner.1.as_mut().unwrap() + }) + } + + pub fn apply(&self) -> Option<$id> { + let mut inner = self.inner.lock(); + + match inner.1.take() { + Some(draft) => { + let old_value = inner.0.to_owned(); + inner.0 = draft.to_owned(); + Some(old_value) + } + None => None, + } + } + + pub fn discard(&self) -> Option<$id> { + let mut inner = self.inner.lock(); + inner.1.take() + } + } + + impl From<$id> for Draft<$id> { + fn from(data: $id) -> Self { + Draft { + inner: Arc::new(Mutex::new((data, None))), + } + } + } + }; +} + +draft_define!(IVerge); +draft_define!(Mapping); +draft_define!(IProfiles); + +#[test] +fn test_draft() { + let verge = IVerge { + enable_auto_launch: Some(true), + enable_tun_mode: Some(false), + ..IVerge::default() + }; + + let draft = Draft::from(verge); + + assert_eq!(draft.data().enable_auto_launch, Some(true)); + assert_eq!(draft.data().enable_tun_mode, Some(false)); + + assert_eq!(draft.draft().enable_auto_launch, Some(true)); + assert_eq!(draft.draft().enable_tun_mode, Some(false)); + + let mut d = draft.draft(); + d.enable_auto_launch = Some(false); + d.enable_tun_mode = Some(true); + drop(d); + + assert_eq!(draft.data().enable_auto_launch, Some(true)); + assert_eq!(draft.data().enable_tun_mode, Some(false)); + + assert_eq!(draft.draft().enable_auto_launch, Some(false)); + assert_eq!(draft.draft().enable_tun_mode, Some(true)); + + assert!(draft.apply().is_some()); + assert!(draft.apply().is_none()); + + assert_eq!(draft.data().enable_auto_launch, Some(false)); + assert_eq!(draft.data().enable_tun_mode, Some(true)); + + assert_eq!(draft.draft().enable_auto_launch, Some(false)); + assert_eq!(draft.draft().enable_tun_mode, Some(true)); + + let mut d = draft.draft(); + d.enable_auto_launch = Some(true); + drop(d); + + assert_eq!(draft.data().enable_auto_launch, Some(false)); + + assert_eq!(draft.draft().enable_auto_launch, Some(true)); + + assert!(draft.discard().is_some()); + + assert_eq!(draft.data().enable_auto_launch, Some(false)); + + assert!(draft.discard().is_none()); + + assert_eq!(draft.draft().enable_auto_launch, Some(false)); +}