1use crate::dynamic_value;
2use core::fmt::{self, Formatter};
3
4#[derive(Clone, Copy, Debug, Default)]
5pub(crate) struct Indent {
6 indent: Option<usize>,
8}
9
10impl Indent {
11 fn no_indent() -> Self {
12 Self { indent: None }
13 }
14
15 fn enabled() -> Self {
16 Self { indent: Some(0) }
17 }
18
19 fn next(self) -> Self {
20 match self.indent {
21 None => self,
22 Some(x) => Self {
23 indent: Some(x + 1),
24 },
25 }
26 }
27
28 fn maybe_newline(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
29 match self.indent {
30 None => Ok(()),
31 Some(indent) => {
32 formatter.write_str("\n")?;
33 for _ in 0..indent {
34 formatter.write_str(" ")?;
35 }
36 Ok(())
37 }
38 }
39 }
40
41 fn comma(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
42 match self.indent {
43 None => formatter.write_str(", "),
44 Some(_) => formatter.write_str(","),
45 }
46 }
47}
48
49fn cvt<T, E>(r: core::result::Result<T, E>) -> Result<T, fmt::Error> {
50 r.map_err(|_| fmt::Error)
51}
52
53pub(crate) fn print(
54 value: dynamic_value::Reader,
55 formatter: &mut Formatter,
56 indent: Indent,
57) -> Result<(), fmt::Error> {
58 match value {
59 dynamic_value::Reader::Void => formatter.write_str("()"),
60 dynamic_value::Reader::Bool(b) => write!(formatter, "{b}"),
61 dynamic_value::Reader::Int8(x) => write!(formatter, "{x}"),
62 dynamic_value::Reader::Int16(x) => write!(formatter, "{x}"),
63 dynamic_value::Reader::Int32(x) => write!(formatter, "{x}"),
64 dynamic_value::Reader::Int64(x) => write!(formatter, "{x}"),
65 dynamic_value::Reader::UInt8(x) => write!(formatter, "{x}"),
66 dynamic_value::Reader::UInt16(x) => write!(formatter, "{x}"),
67 dynamic_value::Reader::UInt32(x) => write!(formatter, "{x}"),
68 dynamic_value::Reader::UInt64(x) => write!(formatter, "{x}"),
69 dynamic_value::Reader::Float32(x) => write!(formatter, "{x}"),
70 dynamic_value::Reader::Float64(x) => write!(formatter, "{x}"),
71 dynamic_value::Reader::Enum(e) => match cvt(e.get_enumerant())? {
72 Some(enumerant) => {
73 formatter.write_str(cvt(cvt(enumerant.get_proto().get_name())?.to_str())?)
74 }
75 None => write!(formatter, "{}", e.get_value()),
76 },
77 dynamic_value::Reader::Text(t) => write!(formatter, "{t:?}"),
78 dynamic_value::Reader::Data(d) => {
79 formatter.write_str("0x\"")?;
80 for b in d {
81 write!(formatter, "{:02x}", *b)?;
82 }
83 formatter.write_str("\"")
84 }
85 dynamic_value::Reader::List(list) => {
86 if list.is_empty() {
87 formatter.write_str("[]")
88 } else {
89 formatter.write_str("[")?;
90 let indent2 = indent.next();
91 for (idx, value) in list.iter().enumerate() {
92 indent2.maybe_newline(formatter)?;
93 print(cvt(value)?, formatter, indent2)?;
94 if idx + 1 < list.len() as usize {
95 indent2.comma(formatter)?;
96 }
97 }
98 indent.maybe_newline(formatter)?;
99 formatter.write_str("]")
100 }
101 }
102 dynamic_value::Reader::Struct(st) => {
103 let schema = st.get_schema();
104 let union_fields = cvt(schema.get_union_fields())?;
105 let non_union_fields = cvt(schema.get_non_union_fields())?;
106 if union_fields.len() + non_union_fields.len() == 0 {
107 return formatter.write_str("()");
108 }
109 formatter.write_str("(")?;
110 let indent2 = indent.next();
111 let mut union_field = match cvt(st.which())? {
112 None => None,
113 Some(field) => {
114 if field.get_proto().get_discriminant_value() != 0 || cvt(st.has(field))? {
116 Some(field)
117 } else {
118 None
119 }
120 }
121 };
122 let mut first = true;
123 for field in non_union_fields {
124 if let Some(ff) = union_field {
125 if ff.get_index() < field.get_index() {
126 if first {
128 first = false
129 } else {
130 indent2.comma(formatter)?;
131 }
132 indent2.maybe_newline(formatter)?;
133 formatter.write_str(cvt(cvt(ff.get_proto().get_name())?.to_str())?)?;
134 formatter.write_str(" = ")?;
135 print(cvt(st.get(ff))?, formatter, indent2)?;
136 union_field = None;
137 }
138 }
139 if cvt(st.has(field))? {
140 if first {
141 first = false
142 } else {
143 indent2.comma(formatter)?;
144 }
145 indent2.maybe_newline(formatter)?;
146 formatter.write_str(cvt(cvt(field.get_proto().get_name())?.to_str())?)?;
147 formatter.write_str(" = ")?;
148 print(cvt(st.get(field))?, formatter, indent2)?;
149 }
150 }
151 if let Some(ff) = union_field {
152 if !first {
154 indent2.comma(formatter)?;
155 }
156 indent2.maybe_newline(formatter)?;
157 formatter.write_str(cvt(cvt(ff.get_proto().get_name())?.to_str())?)?;
158 formatter.write_str(" = ")?;
159 print(cvt(st.get(ff))?, formatter, indent2)?;
160 }
161 indent.maybe_newline(formatter)?;
162 formatter.write_str(")")
163 }
164 dynamic_value::Reader::AnyPointer(_) => formatter.write_str("<opaque pointer>"),
165 dynamic_value::Reader::Capability(_) => formatter.write_str("<external capability>"),
166 }
167}
168
169impl fmt::Debug for dynamic_value::Reader<'_> {
170 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
171 let indent = if f.alternate() {
172 Indent::enabled()
173 } else {
174 Indent::no_indent()
175 };
176 print(*self, f, indent)
177 }
178}