Expand description
Viaduct is a library for establishing a duplex communication channel between a parent and child process, using unnamed pipes.
§Example
§Shared library
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
pub enum ExampleRpc {
Cow,
Pig,
Horse
}
#[derive(Serialize, Deserialize, PartialEq, Eq)]
pub struct FrontflipError;
#[derive(Serialize, Deserialize, PartialEq, Eq)]
pub struct BackflipError;
§Parent process
let child = std::process::Command::new("child.exe");
let ((tx, rx), mut child) = ViaductParent::new(child).unwrap().build().unwrap();
std::thread::spawn(move || {
rx.run(|event| match event {
ViaductEvent::Rpc(rpc) => match rpc {
ExampleRpc::Cow => println!("Moo"),
ExampleRpc::Pig => println!("Oink"),
ExampleRpc::Horse => println!("Neigh"),
},
ViaductEvent::Request { request, responder } => match request {
ExampleRequest::DoAFrontflip => {
println!("Doing a frontflip!");
responder.respond(Ok::<_, FrontflipError>(())).unwrap();
},
ExampleRequest::DoABackflip => {
println!("Doing a backflip!");
responder.respond(Ok::<_, BackflipError>(())).unwrap();
},
}
}).unwrap();
});
tx.rpc(ExampleRpc::Cow).unwrap();
tx.rpc(ExampleRpc::Pig).unwrap();
tx.rpc(ExampleRpc::Horse).unwrap();
let response: Result<(), FrontflipError> = tx.request(ExampleRequest::DoAFrontflip).unwrap().unwrap();
assert_eq!(response, Ok(()));
§Child process
let (tx, rx) = unsafe { ViaductChild::new().build() }.unwrap();
std::thread::spawn(move || {
rx.run(|event| match event {
ViaductEvent::Rpc(rpc) => match rpc {
ExampleRpc::Cow => println!("Moo"),
ExampleRpc::Pig => println!("Oink"),
ExampleRpc::Horse => println!("Neigh"),
},
ViaductEvent::Request { request, responder } => match request {
ExampleRequest::DoAFrontflip => {
println!("Doing a frontflip!");
responder.respond(Ok::<_, FrontflipError>(())).unwrap();
},
ExampleRequest::DoABackflip => {
println!("Doing a backflip!");
responder.respond(Ok::<_, BackflipError>(())).unwrap();
},
}
}).unwrap();
});
tx.rpc(ExampleRpc::Horse).unwrap();
tx.rpc(ExampleRpc::Pig).unwrap();
tx.rpc(ExampleRpc::Cow).unwrap();
let response: Result<(), BackflipError> = tx.request(ExampleRequest::DoABackflip).unwrap().unwrap();
assert_eq!(response, Ok(()));
§Use Cases
Viaduct was designed for separating user interface from application logic in a cross-platform manner.
For example, an application may want to run a GUI in a separate process from the application logic, for modularity or performance reasons.
Viaduct allows for applications like this to communicate between these processes in a natural way, without having to manually implement IPC machinery & synchronization.
§Usage
§Serialization
Viaduct currently supports serialization and deserialization of data using bytemuck
(default), bincode
or speedy
at your choice, using the respective Cargo feature flags.
You can also manually implement the ViaductSerialize
and ViaductDeserialize
traits.
§Initializing a viaduct
A viaduct is started by calling ViaductParent::new
as the parent process, which will spawn your child process.
Your child process should then call ViaductChild::new
, [ViaductChild::new_with_args_os
] or [ViaductChild::new_with_args
] (see CAVEAT below) to bridge the connection between the parent and child.
Then, you are ready to start…
§Passing data
Viaduct has two modes of operation: RPCs and Requests/Responses.
RPCs are one-way messages, and are useful for sending notifications to the other process.
Requests/Responses are two-way messages, and are useful for sending requests to the other process and receiving data as a response.
Requests will block any other thread trying to send requests and RPCs through the viaduct, until a response is received.
§CAVEAT: Don’t use std::env::args_os
or std::env::args
in your child process!
The child process should not use args_os
or args
to get its arguments, as these will contain data Viaduct needs to pass to the child process.
Instead, use the argument iterator provided by [ViaductChild::new_with_args_os
] or [ViaductChild::new_with_args
] for args_os
and args
respectively.
Structs§
- Viaduct
Child - Interface for creating a viaduct on the CHILD process.
- Viaduct
Parent - Interface for creating a viaduct on the PARENT process.
- Viaduct
Request Responder - Use
ViaductRequestResponder::respond
to send a response to the other side. - Viaduct
Rx - The receiving side of a viaduct.
- Viaduct
Tx - The sending side of a viaduct.
Enums§
- Never
- You can use this type (which implements
ViaductSerialize
andViaductDeserialize
) to specify that this type of packet (RCP/request) will never happen. - Viaduct
Event - An event that was received over the viaduct.
Traits§
- Viaduct
Deserialize - Types that can be serialized and deserialized for crossing the viaduct.
- Viaduct
Serialize - Types that can be serialized and deserialized for crossing the viaduct.
Type Aliases§
- Viaduct
- A channel pair for sending and receiving data across the viaduct.