1use super::{FieldFlags, Innards, NameOpts, Shape, VariantKind};
2use std::{collections::HashSet, fmt::Formatter};
3
4impl Shape {
5 pub fn pretty_print_recursive(&self, f: &mut Formatter) -> std::fmt::Result {
7 self.pretty_print_recursive_internal(f, &mut HashSet::new(), 0)
8 }
9
10 fn pretty_print_recursive_internal(
11 &self,
12 f: &mut Formatter,
13 printed_schemas: &mut HashSet<Shape>,
14 indent: usize,
15 ) -> std::fmt::Result {
16 if !printed_schemas.insert(*self) {
17 write!(f, "{:indent$}\x1b[1;33m", "", indent = indent)?;
18 (self.name)(f, NameOpts::one())?;
19 writeln!(f, "\x1b[0m (\x1b[1;31malready printed\x1b[0m)")?;
20 return Ok(());
21 }
22
23 write!(f, "{:indent$}\x1b[1;33m", "", indent = indent)?;
24 (self.name)(f, NameOpts::default())?;
25 writeln!(f, "\x1b[0m (\x1b[1;34m{}\x1b[0m bytes)", self.layout.size())?;
26
27 match &self.innards {
28 Innards::Struct { fields }
29 | Innards::TupleStruct { fields }
30 | Innards::Tuple { fields } => {
31 let max_name_length = fields.iter().map(|f| f.name.len()).max().unwrap_or(0);
32 for field in *fields {
33 write!(
34 f,
35 "{:indent$}\x1b[1;34m{:>4}\x1b[0m \x1b[1;32m{:<width$}\x1b[0m ",
36 "",
37 field.offset,
38 field.name,
39 indent = indent + Self::INDENT,
40 width = max_name_length
41 )?;
42 if field.flags.contains(FieldFlags::SENSITIVE) {
43 write!(f, "(sensitive) ")?;
44 }
45 if let Innards::Scalar(_) = field.shape.get().innards {
46 field.shape.get().pretty_print_recursive_internal(
47 f,
48 printed_schemas,
49 indent + Self::INDENT * 2,
50 )?;
51 } else {
52 writeln!(f)?;
53 field.shape.get().pretty_print_recursive_internal(
54 f,
55 printed_schemas,
56 indent + Self::INDENT * 2,
57 )?;
58 }
59 }
60 }
61 Innards::Map { value_shape, .. } => {
62 writeln!(
63 f,
64 "{:indent$}\x1b[1;36mHashMap with arbitrary keys and value shape:\x1b[0m",
65 "",
66 indent = indent + Self::INDENT
67 )?;
68 value_shape.get().pretty_print_recursive_internal(
69 f,
70 printed_schemas,
71 indent + Self::INDENT * 2,
72 )?;
73 }
74 Innards::List { item_shape, .. } => {
75 write!(
76 f,
77 "{:indent$}\x1b[1;36mArray of:\x1b[0m ",
78 "",
79 indent = indent + Self::INDENT
80 )?;
81 item_shape.get().pretty_print_recursive_internal(
82 f,
83 printed_schemas,
84 indent + Self::INDENT * 2,
85 )?;
86 }
87 Innards::Transparent(inner_schema) => {
88 write!(
89 f,
90 "{:indent$}\x1b[1;36mTransparent wrapper for:\x1b[0m ",
91 "",
92 indent = indent + Self::INDENT
93 )?;
94 inner_schema.get().pretty_print_recursive_internal(
95 f,
96 printed_schemas,
97 indent + Self::INDENT * 2,
98 )?;
99 }
100 Innards::Scalar(_scalar) => {
101 }
103 Innards::Enum { variants, repr: _ } => {
104 writeln!(
105 f,
106 "{:indent$}\x1b[1;36mEnum with {} variants:\x1b[0m",
107 "",
108 variants.len(),
109 indent = indent + Self::INDENT
110 )?;
111
112 for variant in *variants {
113 match &variant.kind {
114 VariantKind::Unit => {
115 let disc_str = if let Some(disc) = variant.discriminant {
116 format!(" = {}", disc)
117 } else {
118 String::new()
119 };
120 writeln!(
121 f,
122 "{:indent$}\x1b[1;32m{}{}\x1b[0m",
123 "",
124 variant.name,
125 disc_str,
126 indent = indent + Self::INDENT * 2
127 )?;
128 }
129 VariantKind::Tuple { fields } => {
130 writeln!(
131 f,
132 "{:indent$}\x1b[1;32m{}\x1b[0m({})",
133 "",
134 variant.name,
135 (0..fields.len())
136 .map(|_| "_")
137 .collect::<Vec<_>>()
138 .join(", "),
139 indent = indent + Self::INDENT * 2
140 )?;
141
142 for field in *fields {
144 write!(
145 f,
146 "{:indent$}\x1b[1;34m{:>4}\x1b[0m \x1b[1;32m{}\x1b[0m ",
147 "",
148 field.offset,
149 field.name,
150 indent = indent + Self::INDENT * 3
151 )?;
152 if field.flags.contains(FieldFlags::SENSITIVE) {
153 write!(f, "(sensitive) ")?;
154 }
155 if let Innards::Scalar(_) = field.shape.get().innards {
156 field.shape.get().pretty_print_recursive_internal(
157 f,
158 printed_schemas,
159 indent + Self::INDENT * 4,
160 )?;
161 } else {
162 writeln!(f)?;
163 field.shape.get().pretty_print_recursive_internal(
164 f,
165 printed_schemas,
166 indent + Self::INDENT * 4,
167 )?;
168 }
169 }
170 }
171 VariantKind::Struct { fields } => {
172 writeln!(
173 f,
174 "{:indent$}\x1b[1;32m{}\x1b[0m {{ {} }}",
175 "",
176 variant.name,
177 fields.iter().map(|f| f.name).collect::<Vec<_>>().join(", "),
178 indent = indent + Self::INDENT * 2
179 )?;
180
181 for field in *fields {
183 write!(
184 f,
185 "{:indent$}\x1b[1;34m{:>4}\x1b[0m \x1b[1;32m{}\x1b[0m ",
186 "",
187 field.offset,
188 field.name,
189 indent = indent + Self::INDENT * 3
190 )?;
191 if field.flags.contains(FieldFlags::SENSITIVE) {
192 write!(f, "(sensitive) ")?;
193 }
194 if let Innards::Scalar(_) = field.shape.get().innards {
195 field.shape.get().pretty_print_recursive_internal(
196 f,
197 printed_schemas,
198 indent + Self::INDENT * 4,
199 )?;
200 } else {
201 writeln!(f)?;
202 field.shape.get().pretty_print_recursive_internal(
203 f,
204 printed_schemas,
205 indent + Self::INDENT * 4,
206 )?;
207 }
208 }
209 }
210 }
211 }
212 }
213 }
214
215 Ok(())
216 }
217}