// Type-safe builder DSL for authoring diagrams in MoonBit code.
//
// let dg = Diagram::new()
// let src = dg.source("mine", flow=Push, rate_out=...) // see connect()
// let gold = dg.pool("gold", initial=0, x=120.0, y=40.0)
// let sink = dg.drain("upkeep")
// dg.connect(src, gold, rate=Fixed(2))
// dg.connect(gold, sink, rate=Fixed(1))
///|
/// An empty diagram.
pub fn Diagram::new() -> Diagram {
{ nodes: [], resources: [], states: [], }
}
///|
fn Diagram::add(self : Diagram, node : Node) -> Int {
self.nodes.push(node)
self.nodes.length() - 1
}
///|
/// Add a node of any kind. Returns the node id (index into `nodes`).
pub fn Diagram::node(
self : Diagram,
kind : NodeKind,
label : String,
initial? : Int = 0,
capacity? : Int? = None,
flow? : Flow = Pull,
activation? : Activation = Passive,
gate_mode? : GateMode = Deterministic,
param? : Int = 0,
x? : Double = 0.0,
y? : Double = 0.0,
) -> Int {
self.add({
kind,
label,
activation,
flow,
capacity,
initial,
gate_mode,
param,
x,
y,
})
}
///|
/// A storage pool. Default: passive, pull.
pub fn Diagram::pool(
self : Diagram,
label : String,
initial? : Int = 0,
capacity? : Int? = None,
flow? : Flow = Pull,
activation? : Activation = Passive,
x? : Double = 0.0,
y? : Double = 0.0,
) -> Int {
self.node(Pool, label, initial~, capacity~, flow~, activation~, x~, y~)
}
///|
/// An infinite source. Default: automatic, push.
pub fn Diagram::source(
self : Diagram,
label : String,
flow? : Flow = Push,
activation? : Activation = Automatic,
x? : Double = 0.0,
y? : Double = 0.0,
) -> Int {
self.node(Source, label, flow~, activation~, x~, y~)
}
///|
/// A drain. Default: automatic, pull.
pub fn Diagram::drain(
self : Diagram,
label : String,
flow? : Flow = Pull,
activation? : Activation = Automatic,
x? : Double = 0.0,
y? : Double = 0.0,
) -> Int {
self.node(Drain, label, flow~, activation~, x~, y~)
}
///|
/// A gate (non-storing router). Default: automatic, pull, deterministic split.
pub fn Diagram::gate(
self : Diagram,
label : String,
flow? : Flow = Pull,
activation? : Activation = Automatic,
gate_mode? : GateMode = Deterministic,
x? : Double = 0.0,
y? : Double = 0.0,
) -> Int {
self.node(Gate, label, flow~, activation~, gate_mode~, x~, y~)
}
///|
/// A converter (atomically turns inputs into outputs). Default: automatic.
pub fn Diagram::converter(
self : Diagram,
label : String,
activation? : Activation = Automatic,
x? : Double = 0.0,
y? : Double = 0.0,
) -> Int {
self.node(Converter, label, activation~, x~, y~)
}
///|
/// A trader (atomic resource exchange). Same resolution as a converter.
pub fn Diagram::trader(
self : Diagram,
label : String,
activation? : Activation = Automatic,
x? : Double = 0.0,
y? : Double = 0.0,
) -> Int {
self.node(Trader, label, activation~, x~, y~)
}
///|
/// A register: holds a numeric value that feeds state connections.
pub fn Diagram::register(
self : Diagram,
label : String,
value? : Int = 0,
x? : Double = 0.0,
y? : Double = 0.0,
) -> Int {
self.node(Register, label, initial=value, x~, y~)
}
///|
/// A delay: holds incoming resources for `steps` steps, then releases them.
pub fn Diagram::delay(
self : Diagram,
label : String,
steps? : Int = 1,
activation? : Activation = Automatic,
x? : Double = 0.0,
y? : Double = 0.0,
) -> Int {
self.node(Delay, label, activation~, param=steps, x~, y~)
}
///|
/// A queue: stores incoming and releases up to `rate` per step (FIFO).
pub fn Diagram::queue(
self : Diagram,
label : String,
rate? : Int = 1,
activation? : Activation = Automatic,
x? : Double = 0.0,
y? : Double = 0.0,
) -> Int {
self.node(Queue, label, activation~, param=rate, x~, y~)
}
///|
/// Connect two nodes with a resource flow. Returns the resource-edge id.
pub fn Diagram::connect(
self : Diagram,
from : Int,
to : Int,
rate? : Rate = Fixed(1),
weight? : Double = 1.0,
) -> Int {
self.resources.push({ from, to, rate, weight, })
self.resources.length() - 1
}
///|
/// Add a state connection targeting a node (Trigger / Activator).
pub fn Diagram::state_to_node(
self : Diagram,
from : Int,
to : Int,
kind : StateKind,
factor? : Double = 1.0,
) -> Int {
self.states.push({ from, to_node: Some(to), to_edge: None, kind, factor, })
self.states.length() - 1
}
///|
/// Add a state connection targeting a resource edge (Modifier / RateLabel).
pub fn Diagram::state_to_edge(
self : Diagram,
from : Int,
edge : Int,
kind : StateKind,
factor? : Double = 1.0,
) -> Int {
self.states.push({ from, to_node: None, to_edge: Some(edge), kind, factor, })
self.states.length() - 1
}