1use shapely::{Shape, ShapeDesc};
2use std::io::{self, Write};
3
4pub fn to_json<W: Write>(
6 data: *mut u8,
7 shape_desc: ShapeDesc,
8 writer: &mut W,
9 indent: bool,
10) -> io::Result<()> {
11 use shapely::{Innards, Scalar};
12
13 fn serialize_value<W: Write>(
14 data: *const u8,
15 shape: Shape,
16 writer: &mut W,
17 indent: bool,
18 level: usize,
19 ) -> io::Result<()> {
20 match &shape.innards {
21 Innards::Scalar(scalar) => match scalar {
22 Scalar::String => {
23 let s = unsafe { &*(data as *const String) };
24 write!(writer, "\"{}\"", s.replace('"', "\\\""))
25 }
26 Scalar::Bytes => Err(io::Error::new(
27 io::ErrorKind::InvalidData,
28 "cowardly refusing to inject binary data straight into your JSON",
29 )),
30 Scalar::I8 => {
31 let value = unsafe { *(data as *const i8) };
32 write!(writer, "{value}")
33 }
34 Scalar::I16 => {
35 let value = unsafe { *(data as *const i16) };
36 write!(writer, "{value}")
37 }
38 Scalar::I32 => {
39 let value = unsafe { *(data as *const i32) };
40 write!(writer, "{value}")
41 }
42 Scalar::I64 => {
43 let value = unsafe { *(data as *const i64) };
44 write!(writer, "{value}")
45 }
46 Scalar::I128 => {
47 let value = unsafe { *(data as *const i128) };
48 write!(writer, "{value}")
49 }
50 Scalar::U8 => {
51 let value = unsafe { *data };
52 write!(writer, "{value}")
53 }
54 Scalar::U16 => {
55 let value = unsafe { *(data as *const u16) };
56 write!(writer, "{value}")
57 }
58 Scalar::U32 => {
59 let value = unsafe { *(data as *const u32) };
60 write!(writer, "{value}")
61 }
62 Scalar::U64 => {
63 let value = unsafe { *(data as *const u64) };
64 write!(writer, "{value}")
65 }
66 Scalar::U128 => {
67 let value = unsafe { *(data as *const u128) };
68 write!(writer, "{value}")
69 }
70 Scalar::F32 => {
71 let value = unsafe { *(data as *const f32) };
72 write!(writer, "{value}")
73 }
74 Scalar::F64 => {
75 let value = unsafe { *(data as *const f64) };
76 write!(writer, "{value}")
77 }
78 Scalar::Boolean => {
79 let value = unsafe { *(data as *const bool) };
80 write!(writer, "{}", if value { "true" } else { "false" })
81 }
82 Scalar::Nothing => {
83 write!(writer, "null")
84 }
85 _ => Err(io::Error::new(
86 io::ErrorKind::InvalidData,
87 "unsupported scalar type encountered",
88 )),
89 },
90 Innards::Struct { fields } => {
91 write!(writer, "{{")?;
92 if indent {
93 writeln!(writer)?;
94 }
95 for (i, field) in fields.iter().enumerate() {
96 if indent {
97 write!(writer, "{:indent$}", "", indent = (level + 1) * 2)?;
98 }
99 write!(writer, "\"{}\":", field.name)?;
100 if indent {
101 write!(writer, " ")?;
102 }
103 let field_data = unsafe { data.add(field.offset) };
104 serialize_value(field_data, field.shape.get(), writer, indent, level + 1)?;
105 if i < fields.len() - 1 {
106 write!(writer, ",")?;
107 }
108 if indent {
109 writeln!(writer)?;
110 }
111 }
112 if indent {
113 write!(writer, "{:indent$}", "", indent = level * 2)?;
114 }
115 write!(writer, "}}")
116 }
117 Innards::List { vtable, item_shape } => {
118 write!(writer, "[")?;
119 if indent {
120 writeln!(writer)?;
121 }
122
123 unsafe {
124 let len = (vtable.len)(data);
125
126 for i in 0..len {
127 if indent {
128 write!(writer, "{:indent$}", "", indent = (level + 1) * 2)?;
129 }
130
131 let item_ptr = (vtable.get_item_ptr)(data, i);
132 serialize_value(item_ptr, item_shape.get(), writer, indent, level + 1)?;
133
134 if i < len - 1 {
135 write!(writer, ",")?;
136 }
137 if indent {
138 writeln!(writer)?;
139 }
140 }
141
142 if indent && len > 0 {
143 write!(writer, "{:indent$}", "", indent = level * 2)?;
144 }
145 }
146 write!(writer, "]")
147 }
148 Innards::Map {
149 vtable,
150 value_shape,
151 } => {
152 write!(writer, "{{")?;
153 if indent {
154 writeln!(writer)?;
155 }
156
157 unsafe {
158 let iter_ptr = (vtable.iter)(data);
160
161 let mut first = true;
163
164 while let Some((key_ptr, value_ptr)) = (vtable.iter_vtable.next)(iter_ptr) {
166 if !first {
167 write!(writer, ",")?;
168 if indent {
169 writeln!(writer)?;
170 }
171 }
172 first = false;
173
174 if indent {
175 write!(writer, "{:indent$}", "", indent = (level + 1) * 2)?;
176 }
177
178 let key = &(*key_ptr);
180 write!(writer, "\"{}\":", key.replace('"', "\\\""))?;
181
182 if indent {
183 write!(writer, " ")?;
184 }
185
186 serialize_value(value_ptr, value_shape.get(), writer, indent, level + 1)?;
188 }
189
190 (vtable.iter_vtable.dealloc)(iter_ptr);
192
193 if !first && indent {
194 writeln!(writer)?;
195 write!(writer, "{:indent$}", "", indent = level * 2)?;
196 }
197 }
198
199 write!(writer, "}}")
200 }
201 _ => write!(writer, "null"),
203 }
204 }
205
206 serialize_value(data, shape_desc.get(), writer, indent, 0)
207}
208
209pub fn to_json_string(data: *mut u8, shape_desc: ShapeDesc, indent: bool) -> String {
211 let mut buffer = Vec::new();
212 to_json(data, shape_desc, &mut buffer, indent).unwrap();
213 String::from_utf8(buffer).unwrap()
214}