From 263b45e1b4e72d6c99fc27e41d0c5e1d134f363b Mon Sep 17 00:00:00 2001 From: Lucas Fernandes Nogueira Date: Sun, 13 Mar 2022 11:20:35 -0300 Subject: [PATCH] refactor(core): return boolean on `Manager::manage` (#3682) --- .changes/state-manage-return-val.md | 5 ++ core/tauri/src/app.rs | 22 +++--- core/tauri/src/lib.rs | 104 ++++++++++++++++++++++++++-- core/tauri/src/state.rs | 1 + core/tauri/tests/restart/Cargo.lock | 45 ++++++------ 5 files changed, 140 insertions(+), 37 deletions(-) create mode 100644 .changes/state-manage-return-val.md diff --git a/.changes/state-manage-return-val.md b/.changes/state-manage-return-val.md new file mode 100644 index 000000000..6a661e7da --- /dev/null +++ b/.changes/state-manage-return-val.md @@ -0,0 +1,5 @@ +--- +"tauri": patch +--- + +**Breaking change:** The `Manager::manage` function now returns a bool indicating whether the type is already managed or not. diff --git a/core/tauri/src/app.rs b/core/tauri/src/app.rs index 8edf26880..096b9bfcc 100644 --- a/core/tauri/src/app.rs +++ b/core/tauri/src/app.rs @@ -782,10 +782,10 @@ impl Builder { /// This method can be called any number of times as long as each call /// refers to a different `T`. /// - /// Managed state can be retrieved by any request handler via the - /// [`State`](crate::State) request guard. In particular, if a value of type `T` + /// Managed state can be retrieved by any command handler via the + /// [`State`](crate::State) guard. In particular, if a value of type `T` /// is managed by Tauri, adding `State` to the list of arguments in a - /// request handler instructs Tauri to retrieve the managed value. + /// command handler instructs Tauri to retrieve the managed value. /// /// # Panics /// @@ -799,25 +799,29 @@ impl Builder { /// use std::{collections::HashMap, sync::Mutex}; /// use tauri::State; /// // here we use Mutex to achieve interior mutability - /// struct Storage(Mutex>); + /// struct Storage { + /// store: Mutex>, + /// } /// struct Connection; - /// struct DbConnection(Mutex>); + /// struct DbConnection { + /// db: Mutex>, + /// } /// /// #[tauri::command] /// fn connect(connection: State) { /// // initialize the connection, mutating the state with interior mutability - /// *connection.0.lock().unwrap() = Some(Connection {}); + /// *connection.db.lock().unwrap() = Some(Connection {}); /// } /// /// #[tauri::command] /// fn storage_insert(key: u64, value: String, storage: State) { /// // mutate the storage behind the Mutex - /// storage.0.lock().unwrap().insert(key, value); + /// storage.store.lock().unwrap().insert(key, value); /// } /// /// tauri::Builder::default() - /// .manage(Storage(Default::default())) - /// .manage(DbConnection(Default::default())) + /// .manage(Storage { store: Default::default() }) + /// .manage(DbConnection { db: Default::default() }) /// .invoke_handler(tauri::generate_handler![connect, storage_insert]) /// // on an actual app, remove the string argument /// .run(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json")) diff --git a/core/tauri/src/lib.rs b/core/tauri/src/lib.rs index ccec5cd3a..f6c50ad66 100644 --- a/core/tauri/src/lib.rs +++ b/core/tauri/src/lib.rs @@ -544,15 +544,107 @@ pub trait Manager: sealed::ManagerBase { } /// Add `state` to the state managed by the application. - /// See [`crate::Builder#manage`] for instructions. - fn manage(&self, state: T) + /// + /// This method can be called any number of times as long as each call + /// refers to a different `T`. + /// If a state for `T` is already managed, the function returns false and the value is ignored. + /// + /// Managed state can be retrieved by any command handler via the + /// [`State`](crate::State) guard. In particular, if a value of type `T` + /// is managed by Tauri, adding `State` to the list of arguments in a + /// command handler instructs Tauri to retrieve the managed value. + /// + /// # Panics + /// + /// Panics if state of type `T` is already being managed. + /// + /// # Mutability + /// + /// Since the managed state is global and must be [`Send`] + [`Sync`], mutations can only happen through interior mutability: + /// + /// ```rust,no_run + /// use std::{collections::HashMap, sync::Mutex}; + /// use tauri::State; + /// // here we use Mutex to achieve interior mutability + /// struct Storage { + /// store: Mutex>, + /// } + /// struct Connection; + /// struct DbConnection { + /// db: Mutex>, + /// } + /// + /// #[tauri::command] + /// fn connect(connection: State) { + /// // initialize the connection, mutating the state with interior mutability + /// *connection.db.lock().unwrap() = Some(Connection {}); + /// } + /// + /// #[tauri::command] + /// fn storage_insert(key: u64, value: String, storage: State) { + /// // mutate the storage behind the Mutex + /// storage.store.lock().unwrap().insert(key, value); + /// } + /// + /// tauri::Builder::default() + /// .manage(Storage { store: Default::default() }) + /// .manage(DbConnection { db: Default::default() }) + /// .invoke_handler(tauri::generate_handler![connect, storage_insert]) + /// // on an actual app, remove the string argument + /// .run(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json")) + /// .expect("error while running tauri application"); + /// ``` + /// + /// # Examples + /// + /// ```rust,no_run + /// use tauri::{Manager, State}; + /// + /// struct MyInt(isize); + /// struct MyString(String); + /// + /// #[tauri::command] + /// fn int_command(state: State) -> String { + /// format!("The stateful int is: {}", state.0) + /// } + /// + /// #[tauri::command] + /// fn string_command<'r>(state: State<'r, MyString>) { + /// println!("state: {}", state.inner().0); + /// } + /// + /// tauri::Builder::default() + /// .setup(|app| { + /// app.manage(MyInt(0)); + /// app.manage(MyString("tauri".into())); + /// // `MyInt` is already managed, so `manage()` returns false + /// assert!(!app.manage(MyInt(1))); + /// // read the `MyInt` managed state with the turbofish syntax + /// let int = app.state::(); + /// assert_eq!(int.0, 0); + /// // read the `MyString` managed state with the `State` guard + /// let val: State = app.state(); + /// assert_eq!(val.0, "tauri"); + /// Ok(()) + /// }) + /// .invoke_handler(tauri::generate_handler![int_command, string_command]) + /// // on an actual app, remove the string argument + /// .run(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json")) + /// .expect("error while running tauri application"); + /// ``` + fn manage(&self, state: T) -> bool where T: Send + Sync + 'static, { - self.manager().state().set(state); + self.manager().state().set(state) } - /// Gets the managed state for the type `T`. Panics if the type is not managed. + /// Retrieves the managed state for the type `T`. + /// + /// # Panics + /// + /// Panics if the state for the type `T` has not been previously [managed](Self::manage). + /// Use [try_state](Self::try_state) for a non-panicking version. fn state(&self) -> State<'_, T> where T: Send + Sync + 'static, @@ -565,7 +657,9 @@ pub trait Manager: sealed::ManagerBase { .expect("state() called before manage() for given type") } - /// Tries to get the managed state for the type `T`. Returns `None` if the type is not managed. + /// Attempts to retrieve the managed state for the type `T`. + /// + /// Returns `Some` if the state has previously been [managed](Self::manage). Otherwise returns `None`. fn try_state(&self) -> Option> where T: Send + Sync + 'static, diff --git a/core/tauri/src/state.rs b/core/tauri/src/state.rs index 5b262dd55..d42c47e75 100644 --- a/core/tauri/src/state.rs +++ b/core/tauri/src/state.rs @@ -70,6 +70,7 @@ impl StateManager { /// Gets the state associated with the specified type. pub fn get(&self) -> State<'_, T> { + self.0.get::(); State( self .0 diff --git a/core/tauri/tests/restart/Cargo.lock b/core/tauri/tests/restart/Cargo.lock index f8f718837..da596f21c 100644 --- a/core/tauri/tests/restart/Cargo.lock +++ b/core/tauri/tests/restart/Cargo.lock @@ -515,12 +515,11 @@ dependencies = [ [[package]] name = "deflate" -version = "0.8.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" +checksum = "c86f7e25f518f4b81808a2cf1c50996a61f5c2eb394b2393bd87f2a4780a432f" dependencies = [ "adler32", - "byteorder", ] [[package]] @@ -1422,15 +1421,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "miniz_oxide" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" -dependencies = [ - "adler32", -] - [[package]] name = "miniz_oxide" version = "0.4.4" @@ -1441,6 +1431,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "miniz_oxide" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" +dependencies = [ + "adler", +] + [[package]] name = "ndk" version = "0.4.0" @@ -1802,14 +1801,14 @@ dependencies = [ [[package]] name = "png" -version = "0.16.8" +version = "0.17.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" +checksum = "dc38c0ad57efb786dd57b9864e5b18bae478c00c824dc55a38bbc9da95dde3ba" dependencies = [ "bitflags", "crc32fast", - "deflate 0.8.6", - "miniz_oxide 0.3.7", + "deflate 1.0.0", + "miniz_oxide 0.5.1", ] [[package]] @@ -2509,7 +2508,7 @@ dependencies = [ [[package]] name = "tauri" -version = "1.0.0-rc.3" +version = "1.0.0-rc.4" dependencies = [ "anyhow", "bincode", @@ -2550,12 +2549,12 @@ dependencies = [ [[package]] name = "tauri-codegen" -version = "1.0.0-rc.2" +version = "1.0.0-rc.3" dependencies = [ "base64", "blake3", "ico", - "png 0.16.8", + "png 0.17.5", "proc-macro2", "quote", "serde", @@ -2570,7 +2569,7 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "1.0.0-rc.2" +version = "1.0.0-rc.3" dependencies = [ "heck 0.4.0", "proc-macro2", @@ -2582,7 +2581,7 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "0.3.2" +version = "0.3.3" dependencies = [ "gtk", "http", @@ -2599,7 +2598,7 @@ dependencies = [ [[package]] name = "tauri-runtime-wry" -version = "0.3.2" +version = "0.3.3" dependencies = [ "gtk", "tauri-runtime", @@ -2612,7 +2611,7 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "1.0.0-rc.2" +version = "1.0.0-rc.3" dependencies = [ "ctor", "heck 0.4.0",