Skip to content

Commit 263b45e

Browse files
authored
refactor(core): return boolean on Manager::manage (#3682)
1 parent c81534e commit 263b45e

File tree

5 files changed

+137
-34
lines changed

5 files changed

+137
-34
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": patch
3+
---
4+
5+
**Breaking change:** The `Manager::manage` function now returns a bool indicating whether the type is already managed or not.

core/tauri/src/app.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -782,10 +782,10 @@ impl<R: Runtime> Builder<R> {
782782
/// This method can be called any number of times as long as each call
783783
/// refers to a different `T`.
784784
///
785-
/// Managed state can be retrieved by any request handler via the
786-
/// [`State`](crate::State) request guard. In particular, if a value of type `T`
785+
/// Managed state can be retrieved by any command handler via the
786+
/// [`State`](crate::State) guard. In particular, if a value of type `T`
787787
/// is managed by Tauri, adding `State<T>` to the list of arguments in a
788-
/// request handler instructs Tauri to retrieve the managed value.
788+
/// command handler instructs Tauri to retrieve the managed value.
789789
///
790790
/// # Panics
791791
///
@@ -799,25 +799,29 @@ impl<R: Runtime> Builder<R> {
799799
/// use std::{collections::HashMap, sync::Mutex};
800800
/// use tauri::State;
801801
/// // here we use Mutex to achieve interior mutability
802-
/// struct Storage(Mutex<HashMap<u64, String>>);
802+
/// struct Storage {
803+
/// store: Mutex<HashMap<u64, String>>,
804+
/// }
803805
/// struct Connection;
804-
/// struct DbConnection(Mutex<Option<Connection>>);
806+
/// struct DbConnection {
807+
/// db: Mutex<Option<Connection>>,
808+
/// }
805809
///
806810
/// #[tauri::command]
807811
/// fn connect(connection: State<DbConnection>) {
808812
/// // initialize the connection, mutating the state with interior mutability
809-
/// *connection.0.lock().unwrap() = Some(Connection {});
813+
/// *connection.db.lock().unwrap() = Some(Connection {});
810814
/// }
811815
///
812816
/// #[tauri::command]
813817
/// fn storage_insert(key: u64, value: String, storage: State<Storage>) {
814818
/// // mutate the storage behind the Mutex
815-
/// storage.0.lock().unwrap().insert(key, value);
819+
/// storage.store.lock().unwrap().insert(key, value);
816820
/// }
817821
///
818822
/// tauri::Builder::default()
819-
/// .manage(Storage(Default::default()))
820-
/// .manage(DbConnection(Default::default()))
823+
/// .manage(Storage { store: Default::default() })
824+
/// .manage(DbConnection { db: Default::default() })
821825
/// .invoke_handler(tauri::generate_handler![connect, storage_insert])
822826
/// // on an actual app, remove the string argument
823827
/// .run(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))

core/tauri/src/lib.rs

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -544,15 +544,107 @@ pub trait Manager<R: Runtime>: sealed::ManagerBase<R> {
544544
}
545545

546546
/// Add `state` to the state managed by the application.
547-
/// See [`crate::Builder#manage`] for instructions.
548-
fn manage<T>(&self, state: T)
547+
///
548+
/// This method can be called any number of times as long as each call
549+
/// refers to a different `T`.
550+
/// If a state for `T` is already managed, the function returns false and the value is ignored.
551+
///
552+
/// Managed state can be retrieved by any command handler via the
553+
/// [`State`](crate::State) guard. In particular, if a value of type `T`
554+
/// is managed by Tauri, adding `State<T>` to the list of arguments in a
555+
/// command handler instructs Tauri to retrieve the managed value.
556+
///
557+
/// # Panics
558+
///
559+
/// Panics if state of type `T` is already being managed.
560+
///
561+
/// # Mutability
562+
///
563+
/// Since the managed state is global and must be [`Send`] + [`Sync`], mutations can only happen through interior mutability:
564+
///
565+
/// ```rust,no_run
566+
/// use std::{collections::HashMap, sync::Mutex};
567+
/// use tauri::State;
568+
/// // here we use Mutex to achieve interior mutability
569+
/// struct Storage {
570+
/// store: Mutex<HashMap<u64, String>>,
571+
/// }
572+
/// struct Connection;
573+
/// struct DbConnection {
574+
/// db: Mutex<Option<Connection>>,
575+
/// }
576+
///
577+
/// #[tauri::command]
578+
/// fn connect(connection: State<DbConnection>) {
579+
/// // initialize the connection, mutating the state with interior mutability
580+
/// *connection.db.lock().unwrap() = Some(Connection {});
581+
/// }
582+
///
583+
/// #[tauri::command]
584+
/// fn storage_insert(key: u64, value: String, storage: State<Storage>) {
585+
/// // mutate the storage behind the Mutex
586+
/// storage.store.lock().unwrap().insert(key, value);
587+
/// }
588+
///
589+
/// tauri::Builder::default()
590+
/// .manage(Storage { store: Default::default() })
591+
/// .manage(DbConnection { db: Default::default() })
592+
/// .invoke_handler(tauri::generate_handler![connect, storage_insert])
593+
/// // on an actual app, remove the string argument
594+
/// .run(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
595+
/// .expect("error while running tauri application");
596+
/// ```
597+
///
598+
/// # Examples
599+
///
600+
/// ```rust,no_run
601+
/// use tauri::{Manager, State};
602+
///
603+
/// struct MyInt(isize);
604+
/// struct MyString(String);
605+
///
606+
/// #[tauri::command]
607+
/// fn int_command(state: State<MyInt>) -> String {
608+
/// format!("The stateful int is: {}", state.0)
609+
/// }
610+
///
611+
/// #[tauri::command]
612+
/// fn string_command<'r>(state: State<'r, MyString>) {
613+
/// println!("state: {}", state.inner().0);
614+
/// }
615+
///
616+
/// tauri::Builder::default()
617+
/// .setup(|app| {
618+
/// app.manage(MyInt(0));
619+
/// app.manage(MyString("tauri".into()));
620+
/// // `MyInt` is already managed, so `manage()` returns false
621+
/// assert!(!app.manage(MyInt(1)));
622+
/// // read the `MyInt` managed state with the turbofish syntax
623+
/// let int = app.state::<MyInt>();
624+
/// assert_eq!(int.0, 0);
625+
/// // read the `MyString` managed state with the `State` guard
626+
/// let val: State<MyString> = app.state();
627+
/// assert_eq!(val.0, "tauri");
628+
/// Ok(())
629+
/// })
630+
/// .invoke_handler(tauri::generate_handler![int_command, string_command])
631+
/// // on an actual app, remove the string argument
632+
/// .run(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
633+
/// .expect("error while running tauri application");
634+
/// ```
635+
fn manage<T>(&self, state: T) -> bool
549636
where
550637
T: Send + Sync + 'static,
551638
{
552-
self.manager().state().set(state);
639+
self.manager().state().set(state)
553640
}
554641

555-
/// Gets the managed state for the type `T`. Panics if the type is not managed.
642+
/// Retrieves the managed state for the type `T`.
643+
///
644+
/// # Panics
645+
///
646+
/// Panics if the state for the type `T` has not been previously [managed](Self::manage).
647+
/// Use [try_state](Self::try_state) for a non-panicking version.
556648
fn state<T>(&self) -> State<'_, T>
557649
where
558650
T: Send + Sync + 'static,
@@ -565,7 +657,9 @@ pub trait Manager<R: Runtime>: sealed::ManagerBase<R> {
565657
.expect("state() called before manage() for given type")
566658
}
567659

568-
/// Tries to get the managed state for the type `T`. Returns `None` if the type is not managed.
660+
/// Attempts to retrieve the managed state for the type `T`.
661+
///
662+
/// Returns `Some` if the state has previously been [managed](Self::manage). Otherwise returns `None`.
569663
fn try_state<T>(&self) -> Option<State<'_, T>>
570664
where
571665
T: Send + Sync + 'static,

core/tauri/src/state.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ impl StateManager {
7070

7171
/// Gets the state associated with the specified type.
7272
pub fn get<T: Send + Sync + 'static>(&self) -> State<'_, T> {
73+
self.0.get::<T>();
7374
State(
7475
self
7576
.0

core/tauri/tests/restart/Cargo.lock

Lines changed: 19 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)