This crate provides the ability to generate static graphs by analysing the node dependencies in DSL. It allows only one input and one output in a graph, and independent nodes can run in maximum parallel.
For example, in the following graph(the number represents the execution time of the node), run it in serial will take 6 seconds, but run it in maximum parallel will just take 2 seconds.
mermaid
graph TD;
A/0-->B/1;
A/0-->C/2;
A/0-->D/1;
A/0-->E/1;
B/1-->F/0;
C/2-->F/0;
D/1-->G/1;
E/1-->G/1;
F/0-->H/0;
G/1-->H/0;
Add this to your Cargo.toml
:
toml
[build-dependencies]
static-graph = "0.2"
Write a graph description in example.graph
file:
```txt node E -> (X, Y) { #[default = "crate::Custom::new"] custom: crate::Custom, }
node X -> O {
x: list
node Y -> O {
y: map
node O { #[editable = "true"] o: string, }
graph G(E) ```
Then, in build.rs
:
rust
fn main() {
static_graph::configure()
.file_name("example.rs")
.compile("example.graph")
.unwrap();
}
Finally, in main.rs
write your own logic for your nodes in the graph. The generated code will be in the OUT_DIR
directory by default, the graph name is G
, and the nodes name are E
, X
, Y
, O
. You should implement the Runnable
trait for each node, and then you can automatically run the graph in maximum parallel by calling G::new().run()
.
```rust use std::{ sync::Arc, time::{Duration, Instant}, };
use gen_graph::{Runnable, E, G, O, X, Y};
pub mod gengraph { staticgraph::include_graph!("example.rs"); }
pub struct Custom;
impl Custom { pub fn new() -> Self { Self } }
async fn main() {
let start = Instant::now();
let resp = G::new()
.run::
println!("Time elapsed is {duration:?}, resp is {resp:?}");
}
pub struct Request { msg: String, user_age: u8, }
pub struct EResponse(Duration);
impl Runnable } pub struct XResponse(bool); impl Runnable } pub struct YResponse(bool); impl Runnable } pub struct OResponse(String); impl Runnable }
``` Volo is dual-licensed under the MIT license and the Apache License (Version 2.0). See LICENSE-MIT and LICENSE-APACHE for details. Feishu: Scan the QR code below with Feishu or click this link to join our CloudWeGo Volo user group.async fn run(&self, _req: Request, _prev_resp: ()) -> Result<Self::Resp, Self::Error> {
tokio::time::sleep(Duration::from_secs(1)).await;
Ok(EResponse(Duration::from_secs(1)))
}
[derive(Clone)]
[asynctrait::asynctrait]
async fn run(&self, req: Request, prev_resp: EResponse) -> Result<Self::Resp, Self::Error> {
tokio::time::sleep(prev_resp.0).await;
Ok(XResponse(!req.msg.contains('*')))
}
[derive(Clone)]
[asynctrait::asynctrait]
async fn run(&self, req: Request, prev_resp: EResponse) -> Result<Self::Resp, Self::Error> {
tokio::time::sleep(prev_resp.0).await;
Ok(YResponse(req.user_age >= 18))
}
[derive(Clone, Debug)]
[asynctrait::asynctrait]
async fn run(
&self,
req: Request,
prev_resp: (XResponse, YResponse),
) -> Result<Self::Resp, Self::Error> {
self.o.store(Arc::new(req.msg.clone()));
println!("O: {:#?}", self.o.load());
if prev_resp.0 .0 && prev_resp.1 .0 {
Ok(OResponse(req.msg))
} else {
Ok(OResponse("Ban".to_string()))
}
}
License
Community