pub struct Nutex<T: Sized> { /* private fields */ }Expand description
A nullable Mutex-like type based on tokio::sync::Mutex implementation.
Nutex stands for NUllable muTEX and it gives you
convenience to work with Optional values, such as connection that
cannot be set at the time when they was created:
you no more need to unwrap the value all the time in functions
that cannot be accessed without Mutex<Option<T>> value defining.
Note that locking Nutex requires to be certain that value is not None
and if you are not sure that function cannot be accessed without value defining
use Nutex::safe_lock or Nutex::safe_blocking_lock instead.
Otherwise if value is None, Nutex::locking will lead you to panic.
§Usage Examples
For example, you created an app and you want to access and process the user client data stored in mutex in the some function that may be called only if user is logged in.
With using the standard Tokio mutex you should unwrap the value all the time:
pub struct AppState {
pub client: Mutex<Option<Client>>,
// ...
}
#[tauri::command]
pub async fn send_message(
state: State<'_, AppState>,
message: String,
to: RecId
) -> Result<(), SendError> {
// ? You need to do THIS:
state
.client
.lock()
.await
.expect("User must be logged in, blah, blah, blah...")
.user_id()
.expect("User must be logged in, blah blah blah...")
.process()
.yet_another_process()
.et_cetera();
// ...
Ok(())
}
#[tauri::command]
pub async fn register(
state: State<'_, AppState>,
auth_data: AuthData,
) -> Result<(), ErrorResponse> {
// ? And THIS...
state.client.lock().await = Some(
Client::builder()
.register(auth_data)
.build()
.await?
.map_err(/* ... */)?;
)
// ...
Ok(())
}Double checking. Double headache.
But Nutex gives you this:
pub struct AppState {
pub client: Nutex<Client>,
// ...
}
#[tauri::command]
pub async fn send_message(
state: State<'_, AppState>,
message: String,
to: RecId
) -> Result<(), SendError> {
state
.client
.lock()
.await
.user_id()
.expect("User must be logged in, blah blah blah...")
.process();
// ...
Ok(())
}
#[tauri::command]
pub async fn register(
state: State<'_, AppState>,
auth_data: AuthData,
) -> Result<(), ErrorResponse> {
state.client.set(
Client::builder()
.register(auth_data)
.build()
.await?
.map_err(/* ... */)?;
// ...
).await;
Ok(())
}It simplifies the code a lot because Mutexes frequently
used with values that cannot be known at the time when
they are created.
§Examples
If you certainly know that value is not None, then you
can just lock the Nutex and access the value:
let nutex = Nutex::from(String::from("foo"));
*nutex.lock().await = String::from("bar");
assert_eq!(String::from("bar"), *nutex.lock().await);But if you’re not sure that it’s not None, prefer using Nutex::safe_lock:
if let Some(mut guard) = nutex.safe_lock().await {
*guard = String::from("foo");
}Other documentation about Nutex may be found in the tokio::sync::Mutex docs:
Nutex is just a wrapper for this anyway.
Implementations§
Source§impl<'a, T: Sized> Nutex<T>
impl<'a, T: Sized> Nutex<T>
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new Nutex that contains None.
Value may be set later by Nutex::set or
dereferencing Nutex::safe_lock.
Sourcepub async fn get(&self) -> T
pub async fn get(&self) -> T
Asynchronously gets the value snapshot. Because of result value is clone and not the immutable reference, it’s not reactive and cannot be observed later.
§Panics
- Panics if
Nutexvalue is not set. If you are not sure that calling function cannot be called without setting the value, useNutex::safe_getinstead.
Sourcepub fn blocking_get(&self) -> T
pub fn blocking_get(&self) -> T
Same as Nutex::get, but blocks the code execution until value is get.
Sourcepub async fn safe_get(&self) -> Option<T>
pub async fn safe_get(&self) -> Option<T>
“Safe” edition of the original Nutex::get method.
Note that “safe” doesn’t mean that original method usage is discouraged: this method may be used if you are not sure that value exist.
Although if more than half of your code contains this method,
think about the original tokio::sync::Mutex instead of Nutex.
Sourcepub fn safe_blocking_get(&self) -> Option<T>
pub fn safe_blocking_get(&self) -> Option<T>
Same as Nutex::safe_get, but blocks the code execution until value is get.
Sourcepub async fn set(&self, val: T)
pub async fn set(&self, val: T)
Sets the value in the Nutex, replacing inner None
to the Some(value).
Note that this method does nothing if value is already set:
if you need to mutate the value that Nutex contains,
use Nutex::lock or Nutex::blocking_lock instead.
Sourcepub fn blocking_set(&self, val: T)
pub fn blocking_set(&self, val: T)
Same as Nutex::set, but blocks the code execution until value is set.
Sourcepub fn blocking_clear(&self)
pub fn blocking_clear(&self)
Same as Nutex::clear, but blocks the code execution until value is cleared.
Sourcepub async fn lock(&'a self) -> NutexGuard<'a, T>
pub async fn lock(&'a self) -> NutexGuard<'a, T>
Locks this Nutex, causing the current task to yield until the lock has
been acquired. When the lock has been acquired, function returns a
NutexGuard.
If the Nutex is available to be acquired immediately, then this call
will typically not yield to the runtime. However, this is not guaranteed
under all circumstances.
§Panics
- Panics if
Nutexvalue is not set. If you are not sure that calling function cannot be called without setting the value, useNutex::safe_lockinstead.
Sourcepub async fn lock_expect(&'a self, msg: &str) -> NutexGuard<'a, T>
pub async fn lock_expect(&'a self, msg: &str) -> NutexGuard<'a, T>
Same as Nutex::lock, but if value is not set, it panics with a custom message.
Useful if panic impossibility reason is opaque and you should explain why panic is impossible.
Sourcepub fn blocking_lock(&'a self) -> NutexGuard<'a, T>
pub fn blocking_lock(&'a self) -> NutexGuard<'a, T>
Same as Nutex::lock, but blocks the code execution until Nutex is locked.
Sourcepub fn blocking_lock_expect(&'a self, msg: &str) -> NutexGuard<'a, T>
pub fn blocking_lock_expect(&'a self, msg: &str) -> NutexGuard<'a, T>
Same as Nutex::lock_expect, but blocks the code execution until Nutex is locked.
Sourcepub async fn safe_lock(&'a self) -> Option<NutexGuard<'a, T>>
pub async fn safe_lock(&'a self) -> Option<NutexGuard<'a, T>>
“Safe” edition of the original Nutex::lock method.
Note that “safe” doesn’t mean that original method usage is discouraged: this method may be used if you are not sure that value exist.
Although if more than half of your code contains this method,
think about the original tokio::sync::Mutex instead of Nutex.
Sourcepub fn safe_blocking_lock(&'a self) -> Option<NutexGuard<'a, T>>
pub fn safe_blocking_lock(&'a self) -> Option<NutexGuard<'a, T>>
Same as Nutex::safe_lock, but blocks the code execution until Nutex is locked.
Sourcepub fn try_lock(&'a self) -> Result<NutexGuard<'a, T>, TryLockError>
pub fn try_lock(&'a self) -> Result<NutexGuard<'a, T>, TryLockError>
Sourcepub async fn lock_then<U, F: AsyncFnOnce(NutexGuard<'a, T>) -> U>(
&'a self,
f: F,
) -> Option<U>
pub async fn lock_then<U, F: AsyncFnOnce(NutexGuard<'a, T>) -> U>( &'a self, f: F, ) -> Option<U>
Sourcepub fn blocking_lock_then<U, F: FnOnce(NutexGuard<'a, T>) -> U>(
&'a self,
f: F,
) -> Option<U>
pub fn blocking_lock_then<U, F: FnOnce(NutexGuard<'a, T>) -> U>( &'a self, f: F, ) -> Option<U>
Same as Nutex::lock_then, but if closure should be executed
it’ll block the code execution until its evaluation is done.
This method is also lazily evaluated that means closure won’t be executed
if Nutex contains None.
Sourcepub fn is_some(&self) -> bool
pub fn is_some(&self) -> bool
Atomic checker that inner value is not None.
Note that this method shouldn’t be used to check
that Nutex should be locked because it’s
not asynchronous that means that you may face
to the race condition.
Consider using Nutex::safe_lock or Nutex::safe_blocking_lock
with if let Some(val) statement, or
Nutex::lock_then/Nutex::blocking_lock_then
to evaluate the statement lazily.
Sourcepub fn into_inner(self) -> Option<T>
pub fn into_inner(self) -> Option<T>
Consumes the Nutex, returning the underlying data.