ipc_channel_adapter 0.1.2

Provides a utility for fast cross process communication
Documentation
use std::collections::HashMap;
use std::fmt::Debug;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use std::sync::Arc;

use serde::de::DeserializeOwned;
use serde::Serialize;
use tokio::sync::mpsc::UnboundedSender;
use tokio::sync::oneshot::channel as oneshot_channel;
use tokio::sync::oneshot::Receiver as OneshotReceiver;
use tokio::sync::oneshot::Sender as OneshotSender;
use tokio::sync::Mutex;

use crate::context::IpcClientRequestContext;
use crate::context::IpcClientResponseContext;
use crate::ipc::asynch::create_ipc_child;

pub struct HostSender<Request, Response>
where
  Request: Clone + Send + Serialize + DeserializeOwned + Debug + 'static,
  Response: Clone + Send + Serialize + DeserializeOwned + Debug + 'static,
{
  counter: Arc<AtomicUsize>,
  messages: Arc<Mutex<HashMap<usize, OneshotSender<Response>>>>,
  tx_ipc: UnboundedSender<IpcClientRequestContext<Request>>,
}

impl<Request, Response> HostSender<Request, Response>
where
  Request: Clone + Send + Serialize + DeserializeOwned + Debug + 'static,
  Response: Clone + Send + Serialize + DeserializeOwned + Debug + 'static,
{
  pub fn new(channel_name: &str) -> Result<Self, ()> {
    let ipc_child_host = channel_name.to_string();

    let Ok((tx_ipc, mut rx_ipc)) = create_ipc_child::<
      IpcClientRequestContext<Request>,
      IpcClientResponseContext<Response>,
    >(&ipc_child_host) else {
      return Err(());
    };

    let messages = Arc::new(Mutex::new(HashMap::<usize, OneshotSender<Response>>::new()));

    tokio::spawn({
      let messages = messages.clone();

      async move {
        while let Some(data) = rx_ipc.recv().await {
          let Some(sender) = messages.lock().await.remove(&data.0) else {
            panic!();
          };
          sender.send(data.1).unwrap();
        }
      }
    });

    Ok(Self {
      messages,
      counter: Arc::new(AtomicUsize::new(0)),
      tx_ipc,
    })
  }

  pub async fn send_and_wait(&self, req: Request) -> Response {
    self.send(req).await.await.unwrap()
  }

  pub async fn send(&self, req: Request) -> OneshotReceiver<Response> {
    let count = self.counter.fetch_add(1, Ordering::Relaxed);
    let (tx, rx) = oneshot_channel::<Response>();
    self.messages.lock().await.insert(count.clone(), tx);
    self
      .tx_ipc
      .send(IpcClientRequestContext::<Request>(count.clone(), req))
      .unwrap();
    rx
  }
}