1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
//! Laying out JSON text that is already JSON.
//!
//! What a caller can rely on is documented on [`prettify`], which the other
//! entry points here refer back to. Why the walk goes through the value path's
//! writer rather than carrying layout rules of its own, and why a number is
//! stepped over by its alphabet rather than held to the grammar, is in
//! [docs/design.md](https://github.com/matrix-research-inc/structio/blob/main/docs/design.md#prettifying-is-the-writer-not-a-second-layout).
//!
//! Every entry point is [`prettify_value_into`] underneath. It is the one that
//! lays out into a writer already part-way through a document; the others hand
//! it a fresh writer, at depth zero, and return what it wrote.
use crate;
use crateParser;
use crateWriter;
use crate;
/// Lay out a JSON document across indented lines.
///
/// Two spaces per level, one member or element per line: [`Pretty`], the same
/// policy [`to_string_with`](crate::to_string_with) takes.
///
/// ```
/// let out = structio::prettify(r#"{"a":[1,2],"b":{}}"#).unwrap();
/// assert_eq!(out, "{\n \"a\": [\n 1,\n 2\n ],\n \"b\": {}\n}");
/// ```
///
/// This is for a document that arrived as text, such as a log line, a response
/// body or a file on disk, rather than out of a [`Write`](crate::json::Write)
/// impl. Its whitespace goes through the same writer such an impl writes
/// through, so the output is byte-identical to what writing the same data under
/// the same policy would have produced.
///
/// Values are copied, not re-encoded. A number keeps the spelling the input
/// gave it and a string keeps its escapes, so `1.50` stays `1.50` and
/// `"\u0041"` stays `"\u0041"`. The output is the input's data laid out again,
/// not a round trip through this crate's number and string formatters.
///
/// ```
/// let out = structio::prettify(r#"[1.50,"\u0041"]"#).unwrap();
/// assert_eq!(out, "[\n 1.50,\n \"\\u0041\"\n]");
/// ```
///
/// Structure is checked as the walk goes, because it has to be known to be laid
/// out at all: which container a value is in decides whether it gets a line or
/// a space, and how deep it is decides the indent. The input must be one
/// complete JSON document whose structure holds up. Anything else is an
/// [`Error`] naming the byte that stopped the walk, rather than output that is
/// quietly wrong:
///
/// ```
/// use structio::ErrorCode;
///
/// let e = structio::prettify(r#"{"a":}"#).unwrap_err();
/// assert_eq!(e.code, ErrorCode::UnexpectedCharacter);
/// assert_eq!(e.index, 5);
/// ```
///
/// Tokens are not checked past what stepping over them requires. A number is
/// taken by its alphabet, so `01` and `1.2.3` lay out unchanged rather than
/// being refused:
///
/// ```
/// assert_eq!(structio::prettify("[01,1.2.3]").unwrap(), "[\n 01,\n 1.2.3\n]");
/// ```
///
/// This is not a validator, and [`from_str`](crate::from_str) is the thing to
/// reach for when the question is whether a document is good.
/// [`prettify`] under an explicit [write policy](crate::Options).
///
/// The policy decides the layout exactly as it does when a value is written:
/// [`INDENT`](Options::INDENT) sets the width and
/// [`NEW_LINES_IN_ARRAYS`](Options::NEW_LINES_IN_ARRAYS) decides whether an
/// array gets a line per element.
///
/// ```
/// use structio::{PrettyInlineArrays, json::prettify_with};
///
/// let out = prettify_with::<PrettyInlineArrays>(r#"{"v":[1,2,3]}"#).unwrap();
/// assert_eq!(out, "{\n \"v\": [1, 2, 3]\n}");
/// ```
///
/// [`PRETTY`](Options::PRETTY) is honoured too, rather than assumed, so a
/// compact policy compacts. That makes [`Standard`](crate::Standard) a
/// minifier, which is the same walk with nothing to emit between tokens:
///
/// ```
/// use structio::{Standard, json::prettify_with};
///
/// let out = prettify_with::<Standard>("{\n \"a\": [1, 2]\n}").unwrap();
/// assert_eq!(out, r#"{"a":[1,2]}"#);
/// ```
///
/// [`minify`](crate::minify) reaches the same bytes on any document that is
/// really JSON, and much faster, because compacting needs none of the structure
/// this walks. Reach for that unless you want the walk's checking too.
///
/// The reading settings do not apply, there being no schema here to have an
/// opinion about: an unknown key is every key. The exception is
/// [`ALLOW_COMMENTS`](Options::ALLOW_COMMENTS), which decides whether a
/// document may carry comments at all. It drops them, as everything in this
/// crate does, a comment being no part of what a writer can emit.
/// [`prettify`] into an existing `String`, replacing its contents and keeping
/// its allocation.
///
/// Prefer this in a loop, the way [`write_into`](crate::write_into) is
/// preferred over [`to_string`](crate::to_string).
///
/// On failure `out` holds however much was laid out before the error, which is
/// the same bargain [`read_into`](crate::read_into) makes: recovering the
/// original would mean copying it first, on every call, to serve the failing
/// case.
/// [`prettify_into`] under an explicit [write policy](crate::Options).
/// Lay one JSON value out into a writer that is already part-way through a
/// document.
///
/// Every other entry point here begins a fresh document at depth zero and
/// hands back the text of it, which is everything a caller holding a document
/// wants and nothing a [`Write`](crate::json::Write) impl can use. This one
/// takes the writer instead, and lays `input` out at that writer's current
/// nesting depth under the policy it carries, so the value arrives indented
/// against its neighbours rather than as a blob starting again at column zero.
/// It is what a type holding JSON *text* where the document expects a *value*
/// needs; [`Raw`](crate::json::Raw) is that type here, and this is the call its
/// [`Write`](crate::json::Write) impl makes.
///
/// ```
/// use structio::{Options, Pretty, json};
///
/// /// A value this program forwards rather than reads, kept as its text.
/// struct Body(&'static str);
///
/// impl json::Write for Body {
/// fn write<O: Options>(&self, w: &mut json::Writer<'_, O>) {
/// // The span was settled when the `Body` was built, so it lays out.
/// json::prettify_value_into(self.0, w).unwrap();
/// }
/// }
///
/// // Laid out where the element actually sits, not at column zero.
/// assert_eq!(
/// structio::to_string_with::<Pretty, _>(&vec![Body(r#"{"a":[1]}"#)]),
/// "[\n {\n \"a\": [\n 1\n ]\n }\n]"
/// );
/// ```
///
/// `input` has to be exactly one JSON value, whitespace on either side and
/// nothing else, which is [`prettify`]'s rule too, a document being one value.
/// Anything after it is [`TrailingContent`](crate::ErrorCode::TrailingContent)
/// rather than something copied through, a tail landing in the middle of the
/// surrounding document being the one place it could land.
///
/// The tokens are what survive. A number keeps the spelling `input` gave it and
/// a string keeps its escapes, exactly as under [`prettify`], because the walk
/// copies tokens rather than decoding and re-encoding them. The whitespace
/// between them does not: the input's own layout is dropped and the policy's is
/// written in its place, which is the whole of what the call is for. Under
/// [`ALLOW_COMMENTS`](Options::ALLOW_COMMENTS) a comment is whitespace and goes
/// the same way, there being no writer here that can emit one.
///
/// A compact policy is honoured rather than overridden, as it is by
/// [`prettify_with`], so this minifies `input` into the writer under
/// [`Standard`](crate::Standard). That is why `Raw` reaches here only under
/// [`PRETTY`](Options::PRETTY): compacted output and the span it arrived as
/// differ only in whitespace, and rewriting that whitespace would give up the
/// bytes it exists to preserve for nothing.
///
/// **A call that fails leaves behind what it had already written.** A writer
/// cannot be rewound, for the reason [`Writer`] gives, so a span that turns out
/// to be malformed halfway through has its first half in the document and no
/// way to take it back. An impl that must not do that has to settle the
/// question before it emits a byte, by walking `input` first with
/// [`Parser::skip_value`](crate::json::Parser::skip_value) and
/// [`Parser::finish`](crate::json::Parser::finish), or by having accepted it
/// earlier through [`Raw::new`](crate::json::Raw::new). `Raw`'s own
/// [`Write`](crate::json::Write) impl takes the first of those routes, and the
/// probe pass it pays for is what a second layout walk would cost anyway.
///
/// The error's offset is a position in `input`. An impl composing this into one
/// of its own has nowhere to put that: an offset into a span of a larger
/// document names the wrong byte of that document, so the code travels and the
/// offset is dropped. See
/// [docs/errors.md](https://github.com/matrix-research-inc/structio/blob/main/docs/errors.md#two-error-currencies-and-why)
/// for why the seam is there.
///
/// This is the one member of the `prettify` family not also re-exported at the
/// crate root. The root carries the entry points you reach for with a document
/// in hand; reaching for this one means having a [`Writer`], which happens
/// inside a `Write` impl and nowhere else, and `Writer` is not at the root
/// either.
/// One whole document: the value, then nothing but whitespace.
/// Lay out one value, whatever it is.
///
/// The cursor must be on the value's first byte, whitespace already behind it.
/// That is the parser's own convention and every route here keeps it: the walk
/// above skips the leading run once, an opening bracket skips what follows it,
/// and `colon` and `comma_or_close` skip what follows them. Skipping again per
/// value would be a third of the whitespace work in a document that has none.
///
/// Private, and [`prettify_value_into`] is what a caller outside this module
/// reaches for: the same walk with the leading whitespace skipped for it, the
/// tail checked, and the error given a position, rather than a cursor contract
/// stated in prose and enforced by a debug assertion.
/// `{ "key": value, ... }`, one member per line.
/// `[value, ...]`, one element per line or all on one, as the policy says.
/// Copy one scalar token through, exactly as the input spelled it.
///
/// A string or a number is the input's own bytes, and its length is not known
/// until the parser has walked it, so it is copied. The three literals are
/// known text and go through the writer's fixed-size appenders instead, which
/// store a compile-time-constant run rather than calling out to a copy of four
/// bytes whose length the compiler cannot see.
///
/// Either way the parser is what finds the token's end, and it checks only what
/// finding the end requires: a string's escapes and its closing quote, a
/// literal's spelling, and a number's alphabet. Object keys come through here
/// too, a key being a string like any other.
///
/// The cursor must already be on the token, as it must be for [`value`].