// SPDX-License-Identifier: LGPL-2.1-only // Copyright (C) 2026 Liberux Labs, S. L. //! [`ChannelSender`], which delivers an app's messages into the run loop. use std::fmt; use std::sync::mpsc::SendError; /// Delivers messages into the run loop from any thread and wakes it. Given to the app by [`crate::App::set_channel_sender`]. pub struct ChannelSender { #[ cfg( not( target_arch = "wasm32" ) ) ] inner: calloop::channel::Sender, #[ cfg( target_arch = "wasm32" ) ] inner: std::sync::mpsc::Sender, } impl ChannelSender { /// Fails once the run loop has ended. pub fn send( &self, msg: T ) -> Result<(), SendError> { self.inner.send( msg )?; #[ cfg( target_arch = "wasm32" ) ] wake(); Ok( () ) } #[ cfg( not( target_arch = "wasm32" ) ) ] pub( crate ) fn from_calloop( inner: calloop::channel::Sender ) -> Self { Self { inner } } } impl Clone for ChannelSender { fn clone( &self ) -> Self { Self { inner: self.inner.clone() } } } impl fmt::Debug for ChannelSender { fn fmt( &self, f: &mut fmt::Formatter<'_> ) -> fmt::Result { f.debug_struct( "ChannelSender" ).finish_non_exhaustive() } } #[ cfg( target_arch = "wasm32" ) ] static WAKE: std::sync::OnceLock = std::sync::OnceLock::new(); /// A sender and the receiver the run loop drains; `wake` is called after every message sent. #[ cfg( target_arch = "wasm32" ) ] pub( crate ) fn channel( wake: fn() ) -> ( ChannelSender, std::sync::mpsc::Receiver ) { let _ = WAKE.set( wake ); let ( inner, rx ) = std::sync::mpsc::channel(); ( ChannelSender { inner }, rx ) } #[ cfg( target_arch = "wasm32" ) ] fn wake() { if let Some( wake ) = WAKE.get() { wake(); } }