metrale_circuit/display/glyphs.rs
1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! 2026-09-28: The two glyph sets of `met circuit display`: Unicode box drawing, and a pure
4//! ASCII fallback for dumb terminals.
5//!
6//! Owner: metrale-circuit.
7//! Invariants:
8//! - Every Unicode glyph here is one terminal column wide, so a line's width is its char count
9//! (`display_tests.rs` checks this against `unicode-width`).
10//! - The ASCII set is 7-bit only. `+`, `#` and `=` are its structural characters; the Unicode
11//! set never emits them.
12
13/// 2026-09-28: Which glyph set to draw with.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum Glyphs {
16 /// 2026-09-28: Box drawing and symbols.
17 Unicode,
18 /// 2026-09-28: 7-bit ASCII only.
19 Ascii,
20}
21
22/// 2026-09-28: One box style: corners top-left, top-right, bottom-left, bottom-right, then the
23/// horizontal and vertical strokes.
24#[derive(Debug, Clone, Copy)]
25pub(crate) struct Frame {
26 pub tl: char,
27 pub tr: char,
28 pub bl: char,
29 pub br: char,
30 pub h: char,
31 pub v: char,
32}
33
34/// 2026-09-28: Every glyph the renderer draws.
35#[derive(Debug, Clone, Copy)]
36pub(crate) struct Set {
37 /// 2026-09-28: Light ops and the header card.
38 pub light: Frame,
39 /// 2026-09-28: Heavy (opaque) ops.
40 pub heavy: Frame,
41 /// 2026-09-28: A fused group's frame.
42 pub fused: Frame,
43 /// 2026-09-28: A materialised edge's stroke.
44 pub wire: char,
45 /// 2026-09-28: A fused (on-chip) edge's stroke.
46 pub dotted: char,
47 /// 2026-09-28: Arrow head.
48 pub arrow: char,
49 /// 2026-09-28: The branch off the main path, the corner turning down into the side path,
50 /// and the corner turning back in.
51 pub fan: [char; 3],
52 /// 2026-09-28: Layer strip: GatedDeltaNet, attention, dense FFN, MoE FFN.
53 pub layer: [char; 4],
54 /// 2026-09-28: Numerics badges: bit-identical, reference, differs.
55 pub badge: [&'static str; 3],
56 /// 2026-09-28: Separator between facts.
57 pub dot: &'static str,
58 /// 2026-09-28: Truncation marker.
59 pub ellipsis: &'static str,
60 /// 2026-09-28: Multiplication sign in shapes and counts.
61 pub times: &'static str,
62 /// 2026-09-28: Kernel sequence arrow.
63 pub then: &'static str,
64 /// 2026-09-28: The layer-boundary title glyph, and the dash of the cut line inside a frame
65 /// that spans two layers.
66 pub boundary: char,
67 pub cut: char,
68 /// 2026-09-28: Marks an input read from a node other than the one above.
69 pub reads: &'static str,
70}
71
72impl Glyphs {
73 pub(crate) fn set(self) -> Set {
74 match self {
75 Glyphs::Unicode => Set {
76 light: Frame {
77 tl: '╭',
78 tr: '╮',
79 bl: '╰',
80 br: '╯',
81 h: '─',
82 v: '│',
83 },
84 heavy: Frame {
85 tl: '╔',
86 tr: '╗',
87 bl: '╚',
88 br: '╝',
89 h: '═',
90 v: '║',
91 },
92 fused: Frame {
93 tl: '┏',
94 tr: '┓',
95 bl: '┗',
96 br: '┛',
97 h: '━',
98 v: '┃',
99 },
100 wire: '│',
101 dotted: '┊',
102 arrow: '▼',
103 fan: ['├', '┐', '┘'],
104 layer: ['▰', '◆', '▪', '✱'],
105 badge: ["✓ bit-identical", "≈ reference", "⚠ differs"],
106 dot: " · ",
107 ellipsis: "…",
108 times: "×",
109 then: " → ",
110 reads: "◂ ",
111 boundary: '╪',
112 cut: '╌',
113 },
114 Glyphs::Ascii => Set {
115 light: Frame {
116 tl: '+',
117 tr: '+',
118 bl: '+',
119 br: '+',
120 h: '-',
121 v: '|',
122 },
123 heavy: Frame {
124 tl: '#',
125 tr: '#',
126 bl: '#',
127 br: '#',
128 h: '=',
129 v: 'H',
130 },
131 fused: Frame {
132 tl: '#',
133 tr: '#',
134 bl: '#',
135 br: '#',
136 h: '#',
137 v: '#',
138 },
139 wire: '|',
140 dotted: ':',
141 arrow: 'v',
142 fan: ['+', '+', '+'],
143 layer: ['G', 'A', 'd', 'm'],
144 badge: ["[ok] bit-identical", "[~] reference", "[!] differs"],
145 dot: " . ",
146 ellipsis: "...",
147 times: "x",
148 then: " -> ",
149 reads: "< ",
150 boundary: '|',
151 cut: '~',
152 },
153 }
154 }
155}