From 4037589000dc9fbcbbbb80efc8279f32c8b7b0de Mon Sep 17 00:00:00 2001 From: Tony Date: Fri, 4 Oct 2024 08:47:30 +0800 Subject: [PATCH] Add default (de)serialize fn --- plugins/store/src/lib.rs | 51 +++++++++++++++++++++++++++++++------- plugins/store/src/store.rs | 49 ++++++++++++++++++------------------ 2 files changed, 67 insertions(+), 33 deletions(-) diff --git a/plugins/store/src/lib.rs b/plugins/store/src/lib.rs index 0d97d493..48c6c6e4 100644 --- a/plugins/store/src/lib.rs +++ b/plugins/store/src/lib.rs @@ -40,10 +40,13 @@ struct ChangePayload<'a> { value: &'a JsonValue, } -pub struct StoreCollection { +#[derive(Debug)] +pub struct StoreState { stores: Mutex>, serialize_fns: HashMap, deserialize_fns: HashMap, + default_serialize: SerializeFn, + default_deserialize: DeserializeFn, } #[derive(Serialize, Deserialize)] @@ -56,7 +59,7 @@ enum AutoSave { #[tauri::command] async fn create_store( app: AppHandle, - store_collection: State<'_, StoreCollection>, + store_state: State<'_, StoreState>, path: PathBuf, auto_save: Option, serialize_fn_name: Option, @@ -77,7 +80,7 @@ async fn create_store( } if let Some(serialize_fn_name) = serialize_fn_name { - let serialize_fn = store_collection + let serialize_fn = store_state .serialize_fns .get(&serialize_fn_name) .ok_or_else(|| crate::Error::SerializeFunctionNotFound(serialize_fn_name))?; @@ -85,7 +88,7 @@ async fn create_store( } if let Some(deserialize_fn_name) = deserialize_fn_name { - let deserialize_fn = store_collection + let deserialize_fn = store_state .deserialize_fns .get(&deserialize_fn_name) .ok_or_else(|| crate::Error::DeserializeFunctionNotFound(deserialize_fn_name))?; @@ -99,10 +102,10 @@ async fn create_store( #[tauri::command] async fn get_store( app: AppHandle, - store_collection: State<'_, StoreCollection>, + store_state: State<'_, StoreState>, path: PathBuf, ) -> Result> { - let stores = store_collection.stores.lock().unwrap(); + let stores = store_state.stores.lock().unwrap(); Ok(stores.get(&resolve_store_path(app, path)).copied()) } @@ -224,7 +227,7 @@ impl> StoreExt for T { } fn get_store(&self, path: impl AsRef) -> Option>> { - let collection = self.state::(); + let collection = self.state::(); let stores = collection.stores.lock().unwrap(); stores .get(path.as_ref()) @@ -232,10 +235,24 @@ impl> StoreExt for T { } } +fn default_serialize( + cache: &HashMap, +) -> std::result::Result, Box> { + Ok(serde_json::to_vec(&cache)?) +} + +fn default_deserialize( + bytes: &[u8], +) -> std::result::Result, Box> { + serde_json::from_slice(bytes).map_err(Into::into) +} + pub struct Builder { phantom_data: PhantomData, serialize_fns: HashMap, deserialize_fns: HashMap, + default_serialize: SerializeFn, + default_deserialize: DeserializeFn, } impl Default for Builder { @@ -244,6 +261,8 @@ impl Default for Builder { phantom_data: Default::default(), serialize_fns: Default::default(), deserialize_fns: Default::default(), + default_serialize, + default_deserialize, } } } @@ -282,6 +301,18 @@ impl Builder { self } + /// Use this serialize function for stores by default + pub fn default_serialize_fn(mut self, serialize_fn: SerializeFn) -> Self { + self.default_serialize = serialize_fn; + self + } + + /// Use this deserialize function for stores by default + pub fn default_deserialize_fn(mut self, deserialize_fn: DeserializeFn) -> Self { + self.default_deserialize = deserialize_fn; + self + } + /// Builds the plugin. /// /// # Examples @@ -314,16 +345,18 @@ impl Builder { save, ]) .setup(move |app_handle, _api| { - app_handle.manage(StoreCollection { + app_handle.manage(StoreState { stores: Mutex::new(HashMap::new()), serialize_fns: self.serialize_fns, deserialize_fns: self.deserialize_fns, + default_serialize: self.default_serialize, + default_deserialize: self.default_deserialize, }); Ok(()) }) .on_event(|app_handle, event| { if let RunEvent::Exit = event { - let collection = app_handle.state::(); + let collection = app_handle.state::(); let stores = collection.stores.lock().unwrap(); for (path, rid) in stores.iter() { if let Ok(store) = app_handle.resources_table().get::>(*rid) { diff --git a/plugins/store/src/store.rs b/plugins/store/src/store.rs index 15a1d49a..b6e145a2 100644 --- a/plugins/store/src/store.rs +++ b/plugins/store/src/store.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use crate::{ChangePayload, StoreCollection}; +use crate::{ChangePayload, StoreState}; use serde_json::Value as JsonValue; use std::{ collections::HashMap, @@ -24,18 +24,6 @@ pub type SerializeFn = pub type DeserializeFn = fn(&[u8]) -> Result, Box>; -fn default_serialize( - cache: &HashMap, -) -> Result, Box> { - Ok(serde_json::to_vec(&cache)?) -} - -fn default_deserialize( - bytes: &[u8], -) -> Result, Box> { - serde_json::from_slice(bytes).map_err(Into::into) -} - pub(crate) fn resolve_store_path(app: AppHandle, path: impl AsRef) -> PathBuf { app.path() .resolve(path, BaseDirectory::AppData) @@ -50,6 +38,7 @@ pub struct StoreBuilder { serialize_fn: SerializeFn, deserialize_fn: DeserializeFn, auto_save: Option, + load_on_build: bool, } impl StoreBuilder { @@ -67,14 +56,18 @@ impl StoreBuilder { pub fn new, P: AsRef>(manager: &M, path: P) -> Self { let app = manager.app_handle().clone(); let path = resolve_store_path(app.clone(), path); + let state = app.state::(); + let serialize_fn = state.default_serialize; + let deserialize_fn = state.default_deserialize; Self { app, // Since Store.path is only exposed to the user in emit calls we may as well simplify it here already. path: dunce::simplified(&path).to_path_buf(), defaults: None, - serialize_fn: default_serialize, - deserialize_fn: default_deserialize, + serialize_fn, + deserialize_fn, auto_save: Some(Duration::from_millis(100)), + load_on_build: true, } } @@ -181,9 +174,15 @@ impl StoreBuilder { self } + /// Skip loading the store on build + pub fn skip_initial_load(mut self) -> Self { + self.load_on_build = false; + self + } + pub(crate) fn build_inner(mut self) -> crate::Result<(Arc>, ResourceId)> { - let collection = self.app.state::(); - let mut stores = collection.stores.lock().unwrap(); + let state = self.app.state::(); + let mut stores = state.stores.lock().unwrap(); if stores.contains_key(&self.path) { return Err(crate::Error::AlreadyExists(self.path)); @@ -196,7 +195,9 @@ impl StoreBuilder { self.serialize_fn, self.deserialize_fn, ); - let _ = store_inner.load(); + if self.load_on_build { + let _ = store_inner.load(); + } let store = Store { auto_save: self.auto_save, @@ -376,8 +377,8 @@ impl StoreInner { } fn emit_change_event(&self, key: &str, value: &JsonValue) -> crate::Result<()> { - let collection = self.app.state::(); - let stores = collection.stores.lock().unwrap(); + let state = self.app.state::(); + let stores = state.stores.lock().unwrap(); self.app.emit( "store://change", ChangePayload { @@ -409,8 +410,8 @@ pub struct Store { impl Resource for Store { fn close(self: Arc) { let store = self.store.lock().unwrap(); - let collection = store.app.state::(); - let mut stores = collection.stores.lock().unwrap(); + let state = store.app.state::(); + let mut stores = state.stores.lock().unwrap(); stores.remove(&store.path); } } @@ -508,8 +509,8 @@ impl Store { pub fn close_store(self) { let store = self.store.lock().unwrap(); let app = store.app.clone(); - let collection = app.state::(); - let stores = collection.stores.lock().unwrap(); + let state = app.state::(); + let stores = state.stores.lock().unwrap(); if let Some(rid) = stores.get(&store.path).copied() { drop(store); drop(stores);