diff --git a/any_spawner/src/lib.rs b/any_spawner/src/lib.rs index b094f51762..1d6dcbefa6 100644 --- a/any_spawner/src/lib.rs +++ b/any_spawner/src/lib.rs @@ -472,9 +472,8 @@ fn handle_uninitialized_spawn(_fut: PinnedFuture<()>) { #[cfg(all(debug_assertions, not(feature = "tracing")))] { panic!( - "At {}, tried to spawn a Future with Executor::spawn() before a \ - global executor was initialized.", - caller + "At {caller}, tried to spawn a Future with Executor::spawn() before a \ + global executor was initialized." ); } // In release builds (without tracing), call the specific no-op function. @@ -503,9 +502,8 @@ fn handle_uninitialized_spawn_local(_fut: PinnedLocalFuture<()>) { #[cfg(all(debug_assertions, not(feature = "tracing")))] { panic!( - "At {}, tried to spawn a Future with Executor::spawn_local() \ - before a global executor was initialized.", - caller + "At {caller}, tried to spawn a Future with Executor::spawn_local() \ + before a global executor was initialized." ); } // In release builds (without tracing), call the specific no-op function (which usually panics). diff --git a/integrations/actix/src/lib.rs b/integrations/actix/src/lib.rs index 2851f24e47..61e54c4b21 100644 --- a/integrations/actix/src/lib.rs +++ b/integrations/actix/src/lib.rs @@ -1230,7 +1230,7 @@ fn static_path(options: &LeptosOptions, path: &str) -> String { // If the path ends with a trailing slash, we generate the path // as a directory with a index.html file inside. if path != "/" && path.ends_with("/") { - static_file_path(options, &format!("{}index", path)) + static_file_path(options, &format!("{path}index")) } else { static_file_path(options, path) } diff --git a/integrations/axum/src/lib.rs b/integrations/axum/src/lib.rs index 8d181f1f10..46305ae2db 100644 --- a/integrations/axum/src/lib.rs +++ b/integrations/axum/src/lib.rs @@ -1543,7 +1543,7 @@ fn static_path(options: &LeptosOptions, path: &str) -> String { // If the path ends with a trailing slash, we generate the path // as a directory with a index.html file inside. if path != "/" && path.ends_with("/") { - static_file_path(options, &format!("{}index", path)) + static_file_path(options, &format!("{path}index")) } else { static_file_path(options, path) } diff --git a/meta/src/lib.rs b/meta/src/lib.rs index 25354eeb52..fd6e67fa41 100644 --- a/meta/src/lib.rs +++ b/meta/src/lib.rs @@ -446,7 +446,7 @@ where tracing::warn!("{}", msg); #[cfg(not(feature = "tracing"))] - eprintln!("{}", msg); + eprintln!("{msg}"); } } diff --git a/reactive_graph/src/effect/immediate.rs b/reactive_graph/src/effect/immediate.rs index f68406e2db..b9f752bb01 100644 --- a/reactive_graph/src/effect/immediate.rs +++ b/reactive_graph/src/effect/immediate.rs @@ -369,7 +369,7 @@ mod inner { const MSG: &str = "ImmediateEffect recursed more than once."; match effect.defined_at() { Some(defined_at) => { - log_warning(format_args!("{MSG} Defined at: {}", defined_at)); + log_warning(format_args!("{MSG} Defined at: {defined_at}")); } None => { log_warning(format_args!("{MSG}")); diff --git a/reactive_graph/src/lib.rs b/reactive_graph/src/lib.rs index 3415931c7d..0395655340 100644 --- a/reactive_graph/src/lib.rs +++ b/reactive_graph/src/lib.rs @@ -121,7 +121,7 @@ pub fn log_warning(text: Arguments) { not(all(target_arch = "wasm32", target_os = "unknown")) ))] { - eprintln!("{}", text); + eprintln!("{text}"); } } diff --git a/reactive_graph/src/send_wrapper_ext.rs b/reactive_graph/src/send_wrapper_ext.rs index 94cdce2563..21e986a0a9 100644 --- a/reactive_graph/src/send_wrapper_ext.rs +++ b/reactive_graph/src/send_wrapper_ext.rs @@ -181,10 +181,10 @@ impl Debug for SendOption { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match &self.inner { Inner::Threadsafe(value) => { - write!(f, "SendOption::Threadsafe({:?})", value) + write!(f, "SendOption::Threadsafe({value:?})") } Inner::Local(value) => { - write!(f, "SendOption::Local({:?})", value) + write!(f, "SendOption::Local({value:?})") } } } diff --git a/reactive_graph/src/transition.rs b/reactive_graph/src/transition.rs index 5575592681..2dc3bd4d95 100644 --- a/reactive_graph/src/transition.rs +++ b/reactive_graph/src/transition.rs @@ -1,16 +1,53 @@ //! Utilities to wait for asynchronous primitives to resolve. use futures::{channel::oneshot, future::join_all}; -use or_poisoned::OrPoisoned; -use std::{ - future::Future, - sync::{mpsc, OnceLock, RwLock}, -}; +use pin_project_lite::pin_project; +use std::{cell::RefCell, future::Future, sync::mpsc}; -static TRANSITION: OnceLock>> = OnceLock::new(); +thread_local! { + static TRANSITION: RefCell> = const { RefCell::new(None) }; +} -fn global_transition() -> &'static RwLock> { - TRANSITION.get_or_init(|| RwLock::new(None)) +/// A Drop guard is needed because drop is called even in case of a panic +struct TransitionGuard<'a>(&'a mut Option); +impl<'a> TransitionGuard<'a> { + fn new(value: &'a mut Option) -> Self { + TRANSITION.with(|transaction| { + std::mem::swap(&mut *transaction.borrow_mut(), value) + }); + Self(value) + } +} +impl Drop for TransitionGuard<'_> { + fn drop(&mut self) { + TRANSITION.with(|transaction| { + std::mem::swap(&mut *transaction.borrow_mut(), self.0) + }); + } +} + +// A future wrapper, to use in async functions +pin_project! { + struct WithTransition{ + transition: Option, + #[pin] + inner: Fut + } +} +impl Future for WithTransition +where + Fut: Future, +{ + type Output = ::Output; + + fn poll( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll { + let this = self.project(); + let _guard = TransitionGuard::new(this.transition); + this.inner.poll(cx) + } } #[derive(Debug, Clone)] @@ -35,19 +72,16 @@ impl AsyncTransition { T: Future, { let (tx, rx) = mpsc::channel(); - let global_transition = global_transition(); - let inner = TransitionInner { tx }; - let prev = Option::replace( - &mut *global_transition.write().or_poisoned(), - inner.clone(), - ); - let value = action().await; - _ = std::mem::replace( - &mut *global_transition.write().or_poisoned(), - prev, - ); + let transition = Some(TransitionInner { tx }); + let value = WithTransition { + transition, + inner: action(), + } + .await; + let mut pending = Vec::new(); - while let Ok(tx) = rx.try_recv() { + // This should never block since all tx instances have been dropped + while let Ok(tx) = rx.recv() { pending.push(tx); } join_all(pending).await; @@ -55,16 +89,13 @@ impl AsyncTransition { } pub(crate) fn register(rx: oneshot::Receiver<()>) { - if let Some(tx) = global_transition() - .read() - .or_poisoned() - .as_ref() - .map(|n| &n.tx) - { - // if it's an Err, that just means the Receiver was dropped - // i.e., the transition is no longer listening, in which case it doesn't matter if we - // successfully register with it or not - _ = tx.send(rx); - } + TRANSITION.with_borrow(|transition| { + if let Some(transition) = transition { + // if it's an Err, that just means the Receiver was dropped + // i.e., the transition is no longer listening, in which case it doesn't matter if we + // successfully register with it or not + _ = transition.tx.send(rx); + } + }) } } diff --git a/reactive_stores_macro/src/lib.rs b/reactive_stores_macro/src/lib.rs index 753469704a..d61892bd96 100644 --- a/reactive_stores_macro/src/lib.rs +++ b/reactive_stores_macro/src/lib.rs @@ -403,7 +403,7 @@ fn variant_to_tokens( let field_ident = field.ident.as_ref().unwrap(); let field_ty = &field.ty; let combined_ident = Ident::new( - &format!("{}_{}", ident, field_ident), + &format!("{ident}_{field_ident}"), field_ident.span(), ); @@ -481,7 +481,7 @@ fn variant_to_tokens( let field_ident = idx; let field_ty = &field.ty; let combined_ident = Ident::new( - &format!("{}_{}", ident, field_ident), + &format!("{ident}_{field_ident}"), ident.span(), ); diff --git a/server_fn/src/client.rs b/server_fn/src/client.rs index 5360722fe9..dbf974950b 100644 --- a/server_fn/src/client.rs +++ b/server_fn/src/client.rs @@ -259,13 +259,13 @@ pub mod reqwest { let mut websocket_server_url = get_server_url().to_string(); if let Some(postfix) = websocket_server_url.strip_prefix("http://") { - websocket_server_url = format!("ws://{}", postfix); + websocket_server_url = format!("ws://{postfix}"); } else if let Some(postfix) = websocket_server_url.strip_prefix("https://") { - websocket_server_url = format!("wss://{}", postfix); + websocket_server_url = format!("wss://{postfix}"); } - let url = format!("{}{}", websocket_server_url, path); + let url = format!("{websocket_server_url}{path}"); let (ws_stream, _) = tokio_tungstenite::connect_async(url).await.map_err(|e| { Error::from_server_fn_error(ServerFnErrorErr::Request( diff --git a/server_fn/src/error.rs b/server_fn/src/error.rs index 1b8491f5f2..c8944d7b8b 100644 --- a/server_fn/src/error.rs +++ b/server_fn/src/error.rs @@ -311,7 +311,7 @@ where fn decode(bytes: Bytes) -> Result, Self::Error> { let data = String::from_utf8(bytes.to_vec()) - .map_err(|err| format!("UTF-8 conversion error: {}", err))?; + .map_err(|err| format!("UTF-8 conversion error: {err}"))?; data.split_once('|') .ok_or_else(|| { diff --git a/tachys/src/ssr/mod.rs b/tachys/src/ssr/mod.rs index 8e0fbaf126..e0913869b9 100644 --- a/tachys/src/ssr/mod.rs +++ b/tachys/src/ssr/mod.rs @@ -153,7 +153,7 @@ impl StreamBuilder { self.sync_buf.reserve(11 + (id.len() * 2)); self.sync_buf.push_str(""); @@ -206,7 +206,7 @@ impl StreamBuilder { let mut id = String::new(); if let Some(ids) = &subbuilder.id { for piece in ids { - write!(&mut id, "{}-", piece).unwrap(); + write!(&mut id, "{piece}-").unwrap(); } } if let Some(id) = subbuilder.id.as_mut() {