bevy-remote-devtools-plugin 0.2.0

A toolset that allows you to debug / view any bevy application with a tauri based UI. This crate is only the plugin part.
Documentation
use std::sync::{Arc, Mutex};

use bevy::prelude::World;
use tokio::sync::Notify;

pub(crate) fn execute_world_tasks_begin(world: &mut World) {
    let receiver = CHANNEL_FRAME_START.1.lock().unwrap();
    while let Ok(task) = receiver.try_recv() {
        (task.task)(world);
    }
}

pub(crate) fn execute_world_tasks_end(world: &mut World) {
    let receiver = CHANNEL_FRAME_END.1.lock().unwrap();
    while let Ok(task) = receiver.try_recv() {
        (task.task)(world);
    }
}

pub(crate) fn execute_world_tasks_render_app(world: &mut World) {
    let receiver = CHANNEL_RENDER_APP.1.lock().unwrap();
    while let Ok(task) = receiver.try_recv() {
        (task.task)(world);
    }
}

struct WorldTask {
    task: Box<dyn FnOnce(&mut World) + Send + Sync + 'static>,
}

pub(crate) async fn execute_in_world<
    T: Send + Sync + 'static,
    F: FnOnce(&mut World) -> T + Send + Sync + 'static,
>(
    channel: ExecutionChannel,
    task: F,
) -> T {
    let notify = Arc::new(Notify::new());
    let output = Arc::new(Mutex::new(None));

    let notify_cloned = notify.clone();
    let output_cloned = output.clone();
    let boxed_task = Box::new(move |world: &mut World| {
        let mut output = output_cloned.lock().unwrap();
        *output = Some(task(world));
        notify_cloned.notify_one();
    });

    let world_task = WorldTask { task: boxed_task };
    {
        let channel = match channel {
            ExecutionChannel::FrameStart => &CHANNEL_FRAME_START.0,
            ExecutionChannel::FrameEnd => &CHANNEL_FRAME_END.0,
            ExecutionChannel::RenderApp => &CHANNEL_RENDER_APP.0,
        };

        let sender = channel.lock().unwrap();
        sender.send(world_task).unwrap();
    }

    notify.notified().await;

    let mut output = output.lock().unwrap();
    output.take().unwrap()
}

lazy_static::lazy_static! {
  static ref CHANNEL_FRAME_START: (Mutex<std::sync::mpsc::Sender<WorldTask>>, Mutex<std::sync::mpsc::Receiver<WorldTask>>) = {
    let (rx, tx) = std::sync::mpsc::channel();
    (Mutex::new(rx), Mutex::new(tx))
  };
  static ref CHANNEL_FRAME_END: (Mutex<std::sync::mpsc::Sender<WorldTask>>, Mutex<std::sync::mpsc::Receiver<WorldTask>>) = {
    let (rx, tx) = std::sync::mpsc::channel();
    (Mutex::new(rx), Mutex::new(tx))
  };
  static ref CHANNEL_RENDER_APP: (Mutex<std::sync::mpsc::Sender<WorldTask>>, Mutex<std::sync::mpsc::Receiver<WorldTask>>) = {
    let (rx, tx) = std::sync::mpsc::channel();
    (Mutex::new(rx), Mutex::new(tx))
  };
}

pub(crate) enum ExecutionChannel {
    FrameStart,
    FrameEnd,
    RenderApp,
}