1use std::fmt;
13use std::task::{Context, Poll};
14use std::thread::Thread;
15
16use anyhow::anyhow;
17use itertools::Itertools;
18use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
19
20use crate::client::{GenericClient, Partitionable, Partitioned};
21
22#[derive(Debug)]
27pub struct LocalClient<C, R> {
28 rx: UnboundedReceiver<R>,
29 tx: UnboundedSender<C>,
30 thread: Thread,
31}
32
33impl<C, R> GenericClient<C, R> for LocalClient<C, R>
34where
35 C: fmt::Debug + Send,
36 R: fmt::Debug + Send,
37{
38 async fn send(&mut self, cmd: C) -> Result<(), anyhow::Error> {
39 self.tx.send(cmd).map_err(|_| anyhow!("receiver dropped"))?;
40 self.thread.unpark();
41
42 Ok(())
43 }
44
45 fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Result<Option<R>, anyhow::Error>> {
46 self.rx.poll_recv(cx).map(Ok)
47 }
48}
49
50impl<C, R> LocalClient<C, R> {
51 pub fn new(rx: UnboundedReceiver<R>, tx: UnboundedSender<C>, thread: Thread) -> Self {
53 Self { rx, tx, thread }
54 }
55
56 pub fn new_partitioned(
58 rxs: Vec<UnboundedReceiver<R>>,
59 txs: Vec<UnboundedSender<C>>,
60 threads: Vec<Thread>,
61 ) -> Partitioned<Self, C, R>
62 where
63 (C, R): Partitionable<C, R>,
64 {
65 let clients = rxs
66 .into_iter()
67 .zip_eq(txs)
68 .zip_eq(threads)
69 .map(|((rx, tx), thread)| LocalClient::new(rx, tx, thread))
70 .collect();
71 Partitioned::new(clients)
72 }
73}
74
75impl<C, R> Drop for LocalClient<C, R> {
76 fn drop(&mut self) {
77 self.thread.unpark();
78 }
79}