#![cfg_attr(not(feature = "js"), forbid(unsafe_code))]
#![cfg_attr(feature = "js", deny(unsafe_code))]
#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/ENQT-GmbH/remoc/master/.misc/Remoc.png",
html_favicon_url = "https://raw.githubusercontent.com/ENQT-GmbH/remoc/master/.misc/Remoc.png"
)]
#![cfg_attr(
feature = "rch",
doc = r##"
```
use std::net::Ipv4Addr;
use tokio::net::{TcpStream, TcpListener};
use remoc::prelude::*;
#[tokio::main]
async fn main() {
// For demonstration we run both client and server in
// the same process. In real life connect_client() and
// connect_server() would run on different machines.
tokio::join!(connect_client(), connect_server());
}
// This would be run on the client.
// It establishes a Remoc connection over TCP to the server.
async fn connect_client() {
// Wait for server to be ready.
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
// Establish TCP connection.
let socket =
TcpStream::connect((Ipv4Addr::LOCALHOST, 9870)).await.unwrap();
let (socket_rx, socket_tx) = socket.into_split();
// Establish Remoc connection over TCP.
// The connection is always bidirectional, but we can just drop
// the unneeded receiver.
let (conn, tx, _rx): (_, _, rch::base::Receiver<()>) =
remoc::Connect::io(remoc::Cfg::default(), socket_rx, socket_tx)
.await.unwrap();
tokio::spawn(conn);
// Run client.
client(tx).await;
}
// This would be run on the server.
// It accepts a Remoc connection over TCP from the client.
async fn connect_server() {
// Listen for incoming TCP connection.
let listener =
TcpListener::bind((Ipv4Addr::LOCALHOST, 9870)).await.unwrap();
let (socket, _) = listener.accept().await.unwrap();
let (socket_rx, socket_tx) = socket.into_split();
// Establish Remoc connection over TCP.
// The connection is always bidirectional, but we can just drop
// the unneeded sender.
let (conn, _tx, rx): (_, rch::base::Sender<()>, _) =
remoc::Connect::io(remoc::Cfg::default(), socket_rx, socket_tx)
.await.unwrap();
tokio::spawn(conn);
// Run server.
server(rx).await;
}
// User-defined data structures needs to implement Serialize
// and Deserialize.
#[derive(Debug, serde::Serialize, serde::Deserialize)]
struct CountReq {
up_to: u32,
// Most Remoc types like channels can be included in serializable
// data structures for transmission to remote endpoints.
seq_tx: rch::mpsc::Sender<u32>,
}
// This would be run on the client.
// It sends a count request to the server and receives each number
// as it is counted over a newly established MPSC channel.
async fn client(mut tx: rch::base::Sender<CountReq>) {
// By sending seq_tx over an existing remote channel, a new remote
// channel is automatically created and connected to the server.
// This all happens inside the existing TCP connection.
let (seq_tx, mut seq_rx) = rch::mpsc::channel(1);
tx.send(CountReq { up_to: 4, seq_tx }).await.unwrap();
// Receive counted numbers over new channel.
assert_eq!(seq_rx.recv().await.unwrap(), Some(0));
assert_eq!(seq_rx.recv().await.unwrap(), Some(1));
assert_eq!(seq_rx.recv().await.unwrap(), Some(2));
assert_eq!(seq_rx.recv().await.unwrap(), Some(3));
assert_eq!(seq_rx.recv().await.unwrap(), None);
}
// This would be run on the server.
// It receives a count request from the client and sends each number
// as it is counted over the MPSC channel sender provided by the client.
async fn server(mut rx: rch::base::Receiver<CountReq>) {
// Receive count request and channel sender to use for counting.
while let Some(CountReq { up_to, seq_tx }) = rx.recv().await.unwrap() {
for i in 0..up_to {
// Send each counted number over provided channel.
seq_tx.send(i).await.unwrap();
}
}
}
```
"##
)]
pub mod prelude;
#[doc(hidden)]
pub mod exec;
pub mod chmux;
pub use chmux::Cfg;
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
pub mod codec;
#[cfg(feature = "rch")]
#[cfg_attr(docsrs, doc(cfg(feature = "rch")))]
pub mod rch;
#[cfg(feature = "rch")]
mod remote_send;
#[cfg(feature = "rch")]
#[cfg_attr(docsrs, doc(cfg(feature = "rch")))]
pub use remote_send::RemoteSend;
#[cfg(feature = "rch")]
mod connect;
#[cfg(feature = "rch")]
#[cfg_attr(docsrs, doc(cfg(feature = "rch")))]
pub use connect::{Connect, ConnectError};
#[cfg(feature = "rch")]
mod connect_ext;
#[cfg(feature = "rch")]
#[cfg_attr(docsrs, doc(cfg(feature = "rch")))]
pub use connect_ext::{ConnectExt, ConsumeError, ProvideError};
#[cfg(feature = "rfn")]
#[cfg_attr(docsrs, doc(cfg(feature = "rfn")))]
pub mod rfn;
#[cfg(feature = "robj")]
#[cfg_attr(docsrs, doc(cfg(feature = "robj")))]
pub mod robj;
#[cfg(feature = "robs")]
#[cfg_attr(docsrs, doc(cfg(feature = "robs")))]
pub mod robs;
#[cfg(feature = "rtc")]
#[cfg_attr(docsrs, doc(cfg(feature = "rtc")))]
pub mod rtc;
#[doc(hidden)]
#[cfg(feature = "rtc")]
pub use serde as _serde;
#[cfg(any(feature = "rfn", feature = "robj"))]
mod provider;
#[cfg(any(feature = "rfn", feature = "robj"))]
pub use provider::Provider;
#[doc(hidden)]
#[cfg(all(feature = "rch", feature = "default-codec-set"))]
pub mod doctest;