byteor_pipeline_spec/
describe.rs

1//! Stable human-readable formatting.
2
3#[cfg(feature = "alloc")]
4use alloc::string::{String, ToString};
5
6#[cfg(feature = "alloc")]
7use crate::{
8    EndpointKindV1, LaneKindV1, MergePolicyV1, OnFullV1, OrderingV1, PipelineSpecV1, RoleCfgV1,
9    ShardKeyV1, SingleRingProducerV1, SingleRingSchedulingV1, StageOpV1,
10};
11
12/// Render a stable human-readable description for a v1 spec.
13#[cfg(feature = "alloc")]
14pub fn describe_v1(spec: &PipelineSpecV1) -> String {
15    let mut out = String::new();
16    match spec {
17        PipelineSpecV1::LaneGraph(lg) => {
18            out.push_str("model: lane_graph\n");
19
20            out.push_str("on_full: ");
21            match lg.on_full {
22                OnFullV1::Block => out.push_str("block"),
23                OnFullV1::Drop => out.push_str("drop"),
24            }
25            out.push('\n');
26
27            out.push_str("endpoints: ");
28            out.push_str(&lg.endpoints.len().to_string());
29            out.push('\n');
30            for ep in &lg.endpoints {
31                out.push_str("- endpoint name=");
32                out.push_str(&ep.name);
33                out.push_str(" kind=");
34                match ep.kind {
35                    EndpointKindV1::Ingress => out.push_str("ingress"),
36                    EndpointKindV1::Egress => out.push_str("egress"),
37                }
38                out.push_str(" lane=");
39                out.push_str(&ep.lane);
40                out.push('\n');
41            }
42
43            out.push_str("lanes: ");
44            out.push_str(&lg.lanes.len().to_string());
45            out.push('\n');
46            for lane in &lg.lanes {
47                out.push_str("- lane name=");
48                out.push_str(&lane.name);
49                out.push_str(" kind=");
50                match lane.kind {
51                    LaneKindV1::Events => out.push_str("events"),
52                    LaneKindV1::Journal => out.push_str("journal"),
53                    LaneKindV1::SequencedSlots { capacity, gating } => {
54                        out.push_str("sequenced_slots capacity=");
55                        out.push_str(&capacity.to_string());
56                        out.push_str(" gating=");
57                        out.push_str(&gating.to_string());
58                    }
59                    LaneKindV1::FanoutBroadcast { consumers } => {
60                        out.push_str("fanout_broadcast consumers=");
61                        out.push_str(&consumers.to_string());
62                    }
63                }
64                out.push('\n');
65            }
66
67            out.push_str("roles: ");
68            out.push_str(&lg.roles.len().to_string());
69            out.push('\n');
70            for role in &lg.roles {
71                match role {
72                    RoleCfgV1::Stage(cfg) => {
73                        out.push_str("- role kind=stage name=");
74                        out.push_str(&cfg.name);
75                        out.push_str(" stage=");
76                        out.push_str(&cfg.stage);
77                        out.push_str(" rx=");
78                        out.push_str(&cfg.rx);
79                        out.push_str(" tx=");
80                        out.push_str(&cfg.tx);
81                    }
82                    RoleCfgV1::Bridge(cfg) => {
83                        out.push_str("- role kind=bridge name=");
84                        out.push_str(&cfg.name);
85                        out.push_str(" rx=");
86                        out.push_str(&cfg.rx);
87                        out.push_str(" tx=");
88                        out.push_str(&cfg.tx);
89                    }
90                    RoleCfgV1::Router(cfg) => {
91                        out.push_str("- role kind=router name=");
92                        out.push_str(&cfg.name);
93                        out.push_str(" rx=");
94                        out.push_str(&cfg.rx);
95                        out.push_str(" tx=");
96                        for (i, lane) in cfg.tx.iter().enumerate() {
97                            if i != 0 {
98                                out.push(',');
99                            }
100                            out.push_str(lane);
101                        }
102                    }
103                    RoleCfgV1::Merge(cfg) => {
104                        out.push_str("- role kind=merge name=");
105                        out.push_str(&cfg.name);
106                        out.push_str(" policy=");
107                        match cfg.policy {
108                            MergePolicyV1::RoundRobin => out.push_str("round_robin"),
109                        }
110                        out.push_str(" rx=");
111                        for (i, lane) in cfg.rx.iter().enumerate() {
112                            if i != 0 {
113                                out.push(',');
114                            }
115                            out.push_str(lane);
116                        }
117                        out.push_str(" tx=");
118                        out.push_str(&cfg.tx);
119                    }
120                }
121                out.push('\n');
122            }
123        }
124        PipelineSpecV1::SingleRing(ring) => {
125            out.push_str("model: single_ring\n");
126            out.push_str("shards: ");
127            out.push_str(&ring.shards.to_string());
128            if ring.shards > 1 {
129                out.push_str(" shard_key=");
130                match ring.shard_key {
131                    ShardKeyV1::FirstByte => out.push_str("first_byte"),
132                }
133            }
134            out.push('\n');
135
136            out.push_str("ordering: ");
137            match ring.ordering {
138                OrderingV1::Strict => out.push_str("strict"),
139                OrderingV1::PerKey => out.push_str("per_key"),
140                OrderingV1::Unordered => out.push_str("unordered"),
141            }
142            out.push('\n');
143
144            out.push_str("producer: ");
145            match ring.producer {
146                SingleRingProducerV1::Single => out.push_str("single"),
147                SingleRingProducerV1::Mpmc => out.push_str("mpmc"),
148            }
149            out.push('\n');
150
151            out.push_str("scheduling: ");
152            match ring.scheduling {
153                SingleRingSchedulingV1::Dedicated => out.push_str("dedicated"),
154                SingleRingSchedulingV1::WorkQueue => out.push_str("work_queue"),
155            }
156            out.push('\n');
157
158            out.push_str("stages: ");
159            out.push_str(&ring.stages.len().to_string());
160            out.push('\n');
161            for (i, st) in ring.stages.iter().enumerate() {
162                out.push_str("- stage ");
163                out.push_str(&i.to_string());
164                out.push_str(": ");
165                match &st.op {
166                    StageOpV1::Identity => out.push_str("identity"),
167                    StageOpV1::AddU8 { delta } => {
168                        out.push_str("add_u8 delta=");
169                        out.push_str(&delta.to_string());
170                    }
171                    #[cfg(feature = "alloc")]
172                    StageOpV1::ResolverKey { stage } => {
173                        out.push_str("resolver_key stage=");
174                        out.push_str(stage);
175                    }
176                }
177                if !st.depends_on.is_empty() {
178                    out.push_str(" depends_on=");
179                    for (j, d) in st.depends_on.iter().enumerate() {
180                        if j != 0 {
181                            out.push(',');
182                        }
183                        out.push_str(&d.to_string());
184                    }
185                }
186                out.push('\n');
187            }
188        }
189    }
190    out
191}