1
0
Fork
You've already forked rhenus
0
Rust library for graph processing pipelines
  • Rust 100%
2026年04月09日 00:40:38 +02:00
crates Make the graph own the nodes so that Node::tick can take &mut self 2026年04月09日 00:40:38 +02:00
examples/audio-loopback Make the graph own the nodes so that Node::tick can take &mut self 2026年04月09日 00:40:38 +02:00
.gitignore Initial commit 2026年04月08日 15:42:42 +02:00
AGENTS.md Initial commit 2026年04月08日 15:42:42 +02:00
Cargo.lock Initial commit 2026年04月08日 15:42:42 +02:00
Cargo.toml Initial commit 2026年04月08日 15:42:42 +02:00
mise.toml Initial commit 2026年04月08日 15:42:42 +02:00
README.md Make the graph own the nodes so that Node::tick can take &mut self 2026年04月09日 00:40:38 +02:00
rustfmt.toml Initial commit 2026年04月08日 15:42:42 +02:00
tombi.toml Initial commit 2026年04月08日 15:42:42 +02:00

Rhenus

Rust library for graph processing pipelines.

Usage

Define a node by implementing the Node trait and registering its ports:

userhenus_core::graph::node::Node;userhenus_core::graph::node::NodeRegistrationContext;userhenus_core::graph::ports::{AllocatingProducerPort,BorrowingConsumerPort,NodeIO};#[derive(Clone)]struct MyNodePorts{input: BorrowingConsumerPort<f32>,output: AllocatingProducerPort<f32>,}struct MyNode{ports: MyNodePorts,}implMyNode{pubfn register(ctx: &mutNodeRegistrationContext)-> (MyNode,MyNodePorts){letports=MyNodePorts{input: ctx.register_borrowing_consumer_port("input"),output: ctx.register_allocating_producer_port("output"),};(MyNode{ports: ports.clone()},ports)}}implNodeforMyNode{fn tick(&self,io: &mutNodeIO){letvalue=io.consume_borrowing(&self.ports.input);io.produce_allocating(&self.ports.output,value*2.0);}}

Build a graph and run it:

letmutbuilder=GraphBuilder::new();letmy_ports=builder.register_node_with("my_node",MyNode::register)?;letinput_port=builder.register_external_producer_port::<f32>("input");letoutput_port=builder.register_external_consumer_port::<f32>("output");builder.connect(&input_port,&my_ports.input)?;builder.connect(&my_ports.output,&output_port)?;letgraph=builder.build()?;foriin0..10{letmutresult=0.0_f32;graph.run(|io|{io.produce_unmanaged(&input_port,iasf32);io.consume_unmanaged(&output_port,&mutresult);});println!("Input: {i}, Output: {result}");}

See examples/audio-loopback for a complete example.

There are multiple port types:

  • allocating producer: receives nothing, returns owned data

  • borrowing producer: receives mutable reference to data, returns nothing

  • unmanaged producer: receives nothing, returns immutable reference to data

  • borrowing consumer: provides nothing, receives immutable reference to data

  • owning consumer: provides nothing, receives data (taking ownership)

  • unmanaged consumer: provides mutable reference to data, receives nothing (because it has a mutable reference already)

  • processor: receives mutable reference to data, returns nothing, counts as both producer and consumer at the same time

The constructed graph must not contain cycles. Each port must be connected to exactly one other port.

Code Style

Many issues are automatically fixed by rustfmt. These following rules need to be upheld manually, though:

  • Put mod statements at the start of the file, before any use statements. Separate those two groups by an empty line.
  • When importing items from child modules or re-exporting module items using pub use, make sure to prefix the import path with self::. Otherwise, rustfmt will put the statement into the wrong group.