structio/json/raw.rs
1//! JSON that goes through untouched.
2//!
3//! [`Raw`] is a field holding the text of one JSON value exactly as the
4//! document spelled it, which it writes back out the same way. Nothing in it
5//! is decoded and nothing is re-encoded: a number keeps the spelling it
6//! arrived with, an integer literal wider than any type here keeps every
7//! digit, an object keeps the key order its producer chose, and a string keeps
8//! its escapes. A gateway that forwards a body it does not reshape forwards
9//! the body that arrived, and a JSON-RPC `params` reaches the handler that
10//! understands it as the caller wrote it.
11//!
12//! [`Value`](crate::Value) is the other destination for a value with no
13//! declared type, and is not a substitute for this one. It is a tree, so it
14//! respells its numbers through this crate's formatters, decodes an escape to
15//! the character it stood for, and has nowhere to put an integer literal past
16//! the width it stores. Those are the right properties for a value you are
17//! going to *look at*, and the wrong ones for a value you are going to hand on
18//! unchanged. Reach for `Value` to walk a document and for `Raw` to carry one.
19//!
20//! This is JSON only, which is why it lives here rather than at the crate root
21//! among the format-agnostic names. What a `Raw` holds is JSON text, and BEVE
22//! has no encoding for that: written as BEVE it would have to become either a
23//! string carrying a document or a re-encoding of the value it stands for, and
24//! neither is what a caller reaching for a passthrough asked for. A struct
25//! with a `Raw` field is therefore declared with
26//! [`json_object!`](crate::json_object), which exists for exactly the type
27//! that only one format can describe.
28//!
29//! ```
30//! use structio::json::Raw;
31//!
32//! #[derive(Default)]
33//! struct Envelope<'a> {
34//! id: u32,
35//! payload: Raw<'a>,
36//! }
37//! structio::json_object!(['a] Envelope<'a> { id, payload });
38//!
39//! // `1.50` keeps its trailing zero and `b` stays behind `a`, because
40//! // neither was ever read.
41//! let text = r#"{"id":7,"payload":{"b":1.50,"a":[1,2]}}"#;
42//! let envelope: Envelope = structio::from_str(text).unwrap();
43//!
44//! assert_eq!(envelope.payload.as_str(), r#"{"b":1.50,"a":[1,2]}"#);
45//! assert_eq!(structio::to_string(&envelope), text);
46//! ```
47
48use core::fmt;
49use std::borrow::Cow;
50
51use crate::error::{Error, PResult, Result};
52use crate::json::parser::Parser;
53use crate::json::traits::{Read, Write};
54use crate::json::writer::Writer;
55use crate::json::{minify_into_with, prettify_value_into};
56use crate::options::Options;
57use crate::swar::find_byte;
58
59/// JSON's way of spelling "no value here", and what a `Raw` holds until
60/// something puts a value in it. See [`Raw::default`].
61const NULL: &str = "null";
62
63/// One JSON value, kept as the text that spelled it.
64///
65/// The span is exactly one value with no whitespace on either side, which is
66/// what lets a `Raw` stand anywhere a value stands: a member of an object, an
67/// element of an array, or a whole document on its own.
68///
69/// Reading borrows out of the input under the default policy: the value is
70/// stepped over rather than decoded, nothing inside it is converted, and the
71/// field is a subslice of the document. Writing is then a copy of that run of
72/// bytes. The owning form exists for the value that has to outlive its
73/// document, through [`into_owned`](Self::into_owned), and for the span that
74/// had a comment taken out of it and so is no longer any run of the input; see
75/// the [`Read`] impl for both, and for exactly which spans those are.
76///
77/// The type deliberately has no `From<&str>`, no `From<String>` and no
78/// `FromStr`. Each would be a conversion that looks total and is not:
79/// [`new`](Self::new) and [`from_string`](Self::from_string) can fail, and the
80/// unchecked ways in are [`new_unchecked`](Self::new_unchecked) and
81/// [`from_string_unchecked`](Self::from_string_unchecked), spelled that way so
82/// that a span nobody validated is visible at the call site rather than hidden
83/// behind an `into()`.
84#[derive(Clone, Debug, PartialEq, Eq)]
85pub struct Raw<'de>(Cow<'de, str>);
86
87impl<'de> Raw<'de> {
88 /// Take the one JSON value `s` spells, checking that it really is one.
89 ///
90 /// The check is everything [`from_str`](crate::from_str) checks reading
91 /// `s` into a [`Value`](crate::Value) under [`Standard`](crate::Standard),
92 /// except the number grammar, and it refuses what that read refuses with
93 /// the same code at the same offset. The value has to be complete and well
94 /// formed, with no control character inside a string and no escape in one,
95 /// key or value, that the string reader would not decode: `\q`, a `\u`
96 /// that is not four hex digits, and a surrogate without its other half
97 /// all fail. And it has to be the only thing in `s`. Trailing content
98 /// fails rather than being stored with the value, because a `Raw` carrying
99 /// a tail would write that tail back out into the middle of whatever
100 /// document it lands in and break it.
101 ///
102 /// ```
103 /// use structio::{ErrorCode, json::Raw};
104 ///
105 /// assert!(Raw::new(r#"{"a":[1,2]}"#).is_ok());
106 /// assert_eq!(Raw::new(r#"{"a":}"#).unwrap_err().code, ErrorCode::UnexpectedCharacter);
107 /// assert_eq!(Raw::new("1 2").unwrap_err().code, ErrorCode::TrailingContent);
108 /// assert_eq!(Raw::new(r#""\q""#).unwrap_err().code, ErrorCode::InvalidEscape);
109 /// assert_eq!(Raw::new(r#""\ud800""#).unwrap_err().code, ErrorCode::InvalidSurrogate);
110 /// ```
111 ///
112 /// Whitespace on either side is dropped rather than refused, so `" 1 "`
113 /// and `"1"` are the same `Raw`. Keeping it would put the caller's
114 /// indentation inside a document laid out by someone else.
115 ///
116 /// Nothing is decoded to be checked: an escape is refused or let through
117 /// and the span keeps it as it was spelled. So this settles that `s` is
118 /// one value rather than that it is a value this crate would have
119 /// produced, and the number grammar is the one place the two differ. A
120 /// number is stepped over by its alphabet rather than held to the grammar,
121 /// exactly as [`prettify`](crate::prettify) steps over one, so `01` is
122 /// accepted and stored as it was written. Holding it to the grammar would
123 /// cost every well-formed number in every forwarded body to move a
124 /// rejection ahead of the reader that will make it anyway, and that reader
125 /// is the one that knows what the value was supposed to be.
126 pub fn new(s: &'de str) -> Result<Self> {
127 let (start, end) = span_of(s)?;
128 Ok(Raw(Cow::Borrowed(&s[start..end])))
129 }
130
131 /// Take `s` as one JSON value without looking at it.
132 ///
133 /// **The validity of the output document is yours**, in the same way it is
134 /// yours when you reach for [`Writer::raw`](crate::json::Writer::raw):
135 /// whatever `s` holds becomes part of whatever document this `Raw` is
136 /// written into, verbatim and unexamined. Hand it something that is not
137 /// one complete JSON value and you get output that is not JSON, at the
138 /// position where the value should have been.
139 ///
140 /// There is no `unsafe` here and nothing unsound to be caused: the type
141 /// holds a `&str` either way, and every path through it stays in safe
142 /// code. `unchecked` is about the document, not about memory. What the
143 /// call buys is the walk [`new`](Self::new) makes, which is worth
144 /// something for a span that some earlier step already proved out: a value
145 /// copied from another `Raw`, or a body a schema-aware layer has already
146 /// parsed.
147 ///
148 /// A span this accepted and [`new`](Self::new) would not still behaves the
149 /// same under every write policy. See the [`Write`] impl.
150 #[inline]
151 pub fn new_unchecked(s: &'de str) -> Self {
152 Raw(Cow::Borrowed(s))
153 }
154
155 /// The value's text, as it will be written.
156 ///
157 /// The span itself, not a decoded value: a `Raw` holding a JSON string has
158 /// the quotes and the escapes in here, because those are part of how the
159 /// value was spelled and this type is about the spelling. Reading the
160 /// value *as* a value means declaring a type for it and parsing this text
161 /// with [`from_str`](crate::from_str), which is a second pass and is meant
162 /// to look like one.
163 #[inline]
164 pub fn as_str(&self) -> &str {
165 &self.0
166 }
167
168 /// Cut the borrow, copying the span if it is still one.
169 ///
170 /// The way out of `'de` for a value that has to outlive the document it
171 /// came from: a request body parked on a queue, or a `params` held until
172 /// the worker that will forward it is free. A span that is already owned,
173 /// which is what reading a value carrying a comment under
174 /// [`ALLOW_COMMENTS`](crate::Options::ALLOW_COMMENTS) produces, moves
175 /// without copying.
176 ///
177 /// ```
178 /// use structio::json::Raw;
179 ///
180 /// let owned = {
181 /// let text = String::from(r#"[1,2,3]"#);
182 /// Raw::new(&text).unwrap().into_owned()
183 /// };
184 /// assert_eq!(owned.as_str(), "[1,2,3]");
185 /// ```
186 #[inline]
187 pub fn into_owned(self) -> Raw<'static> {
188 Raw(Cow::Owned(self.0.into_owned()))
189 }
190}
191
192impl Raw<'static> {
193 /// Take the one JSON value `s` spells, checking that it really is one,
194 /// without copying it.
195 ///
196 /// The owning counterpart to [`new`](Self::new), and the way in for text
197 /// this program produced rather than read: a body assembled from parts, or
198 /// a value some other layer already rendered. The `String` becomes the
199 /// span, so nothing is reallocated and the span is never copied out of the
200 /// buffer it arrived in. Reaching for `new(&s)` and then
201 /// [`into_owned`](Self::into_owned) instead copies a buffer the caller
202 /// already owns.
203 ///
204 /// The check and the trimming are exactly [`new`](Self::new)'s, being the
205 /// same walk: one complete value, nothing after it, and no whitespace on
206 /// either side of what is kept. Trimming shifts bytes down inside `s`.
207 ///
208 /// What the `Raw` then holds is the caller's whole allocation, not just
209 /// the span: a megabyte buffer that was built up and whittled down to one
210 /// short value keeps the megabyte for as long as the `Raw` lives. Where
211 /// that matters, `new(&s)?.into_owned()` is the call that pays a copy to
212 /// allocate the span exactly.
213 ///
214 /// ```
215 /// use structio::json::Raw;
216 ///
217 /// let text = format!(r#"{{"id":{}}}"#, 7);
218 /// let raw = Raw::from_string(text).unwrap();
219 /// assert_eq!(raw.as_str(), r#"{"id":7}"#);
220 /// ```
221 ///
222 /// `s` is consumed either way: a value that fails the check is dropped
223 /// rather than handed back, because [`Error`] carries a code and a
224 /// position and is not a place to park a buffer. Where the text has to
225 /// survive its own rejection, check it with [`new`](Self::new) first.
226 pub fn from_string(mut s: String) -> Result<Self> {
227 let (start, end) = span_of(&s)?;
228 // Both move bytes within the buffer and leave its allocation where it
229 // is, so the span is never copied out of the `String` it arrived in.
230 s.truncate(end);
231 s.drain(..start);
232 Ok(Raw(Cow::Owned(s)))
233 }
234
235 /// Take `s` as one JSON value without looking at it, and without copying
236 /// it.
237 ///
238 /// [`new_unchecked`](Self::new_unchecked) for text this program owns, on
239 /// the same terms: **the validity of the output document is yours**, and
240 /// whatever `s` holds goes verbatim into whatever document this `Raw`
241 /// lands in. Like that one and unlike [`from_string`](Self::from_string)
242 /// it does not trim, so whitespace around the value is part of the span
243 /// and is written with it.
244 ///
245 /// An empty `String` is the case to watch, being the one a builder that
246 /// never got filled hands over. It writes nothing at all, which truncates
247 /// the member it stands in to `{"params":}`; see [`default`](Self::default)
248 /// for why that is the hole the defaulted value exists to close.
249 #[inline]
250 pub fn from_string_unchecked(s: String) -> Self {
251 Raw(Cow::Owned(s))
252 }
253}
254
255impl Default for Raw<'_> {
256 /// The literal `null`, borrowed.
257 ///
258 /// Not the empty string, which is what a newtype over `Cow<str>` defaults
259 /// to on its own and what would make `Default` quietly able to break a
260 /// document. A `Raw` writes its span verbatim, so an empty span writes
261 /// nothing at all and a struct whose `payload` was merely never filled
262 /// comes out as `{"payload":}`: not a document any reader will accept, and
263 /// not one this crate can otherwise produce. Glaze's raw-JSON type has
264 /// exactly that hole, and reproducing it here would mean a field that is
265 /// safe to fill and dangerous to leave alone, which is the wrong way round
266 /// for the member a schema says is optional.
267 ///
268 /// `null` closes it and costs nothing to close: it is one complete value
269 /// like any other, it is the JSON for the member that has no value, and it
270 /// is what [`is_null`](Write::is_null) answers to, so a defaulted `Raw` is
271 /// also the member [`SKIP_NULL`](crate::Options::SKIP_NULL) leaves out
272 /// entirely.
273 ///
274 /// ```
275 /// # #[derive(Default)]
276 /// # struct Envelope<'a> { id: u32, payload: structio::json::Raw<'a> }
277 /// # structio::json_object!(['a] Envelope<'a> { id, payload });
278 /// let envelope = Envelope { id: 1, ..Default::default() };
279 /// assert_eq!(structio::to_string(&envelope), r#"{"id":1,"payload":null}"#);
280 /// ```
281 #[inline]
282 fn default() -> Self {
283 Raw(Cow::Borrowed(NULL))
284 }
285}
286
287impl fmt::Display for Raw<'_> {
288 /// The span, exactly as [`as_str`](Raw::as_str) gives it and exactly as a
289 /// compact write emits it. Under [`PRETTY`](crate::Options::PRETTY) a
290 /// write lays the span out at the depth it sits at, which `Display` has no
291 /// enclosing document to do.
292 ///
293 /// `{:#}` is the same text rather than the laid-out one.
294 /// [`Value`](crate::Value) prettifies under the alternate flag, but it is
295 /// a tree and cannot be holding anything it could not lay out. A `Raw` can:
296 /// [`new_unchecked`](Self::new_unchecked) takes a span nobody walked, and
297 /// laying that one out fails. `Display` has nowhere to report a failure
298 /// and would have to swallow it, so laying a span out stays
299 /// [`prettify`](crate::prettify), which is asked for by name and returns
300 /// a [`Result`].
301 ///
302 /// ```
303 /// use structio::json::Raw;
304 ///
305 /// let raw = Raw::new(r#""a\nb""#).unwrap();
306 /// assert_eq!(raw.to_string(), r#""a\nb""#);
307 /// ```
308 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
309 f.write_str(&self.0)
310 }
311}
312
313/// Borrow the value's bytes straight out of the document.
314///
315/// The span is found by stepping over the value rather than by reading it, so
316/// a `Raw` member costs a parse roughly what an unknown key costs: one walk to
317/// find where the value ends, and then a slice of the input between the two
318/// offsets that walk left. Nothing inside the value is converted, nothing is
319/// copied, and under the default policy nothing is allocated, the field being
320/// a subslice of the input.
321///
322/// The walk checks what [`Raw::new`] checks, so a document is refused or not
323/// whatever type its value lands in, the number grammar aside. The one thing
324/// it does that skipping an unknown key does not is decode each escape it
325/// meets and throw the character away, because a skipped value is discarded
326/// and this one is kept and written out again. Only a string holding a
327/// backslash pays for that.
328///
329/// Under [`ALLOW_COMMENTS`](crate::Options::ALLOW_COMMENTS) the span may hold
330/// `//` and `/* */`. The document was allowed to carry those; the output is
331/// not, a comment being no part of what any writer here can emit, and a
332/// forwarded body carrying one would be refused by the next plain JSON reader
333/// that saw it. So that policy, and only that policy, searches the span for a
334/// `/`, and runs it through the [minifier](crate::json::minify_with), which
335/// already strips comments under it, only when it finds one.
336///
337/// **What that means for the bytes, exactly.** A span with no `/` in it holds
338/// no comment, so it is borrowed just as the default policy borrows it: the
339/// same bytes, interior whitespace and all. A span with a `/` in it is
340/// minified into an owned string, which moves the whitespace between its
341/// tokens but never the tokens themselves, so key order, number spellings and
342/// escapes still come through as the document spelled them. The search is
343/// conservative in the direction that costs nothing: a `/` inside a string,
344/// as in `"http://x"`, buys a minify the span did not need, while a `/` that
345/// is absent is proof there was nothing to strip.
346///
347/// The test is `O::ALLOW_COMMENTS`, a compile-time constant, so the default
348/// policy compiles to the borrow with neither the search nor the stripping
349/// present.
350impl<'de> Read<'de> for Raw<'de> {
351 fn read<O: Options>(&mut self, p: &mut Parser<'de, O>) -> PResult<()> {
352 // Skipped here rather than left to the walk, which would skip it
353 // after `rest_str` had already taken it in: the span has to begin at
354 // the value, not at the whitespace in front of it.
355 p.skip_ws();
356 let rest = p.rest_str();
357 let start = p.position();
358 p.skip_value_checked()?;
359 // The walk stops where the value stopped, which is a token
360 // boundary and so a character boundary, as is the cursor `rest` was
361 // taken at. See `Parser::rest_str`.
362 let text = &rest[..p.position() - start];
363
364 // A comment begins with a slash, so a span holding no slash holds no
365 // comment and is the input's own bytes, exactly as it is under the
366 // default policy. The minifier is the fallback for the span that
367 // might hold one, not the path every span takes.
368 if O::ALLOW_COMMENTS && find_byte(text.as_bytes(), 0, b'/').is_some() {
369 // Refill whatever this field already owns, the way every other
370 // reader here reuses its destination's allocation.
371 let mut buf = match core::mem::replace(&mut self.0, Cow::Borrowed(NULL)) {
372 Cow::Owned(s) => s,
373 Cow::Borrowed(_) => String::new(),
374 };
375 let stripped = minify_into_with::<O>(text, &mut buf);
376 // The buffer goes back whether or not the strip ran to the end, so
377 // a failure costs the allocation nothing; the same bargain
378 // `read_into` makes about a value it left partly written.
379 self.0 = Cow::Owned(buf);
380 if let Err(e) = stripped {
381 // Unreachable in practice: a span the walk accepted holds
382 // no unterminated string, no slash that begins no comment, and
383 // no whitespace holding two bare tokens apart, which are the
384 // three things the minifier refuses. If it ever does happen,
385 // the offset it reports is into the span while the cursor is
386 // past the end of it, so wind back and name the value.
387 p.rewind(start);
388 return Err(e.code);
389 }
390 } else {
391 // Borrowing gives up whatever buffer this field was holding, and
392 // that is the right way round: the borrow costs nothing to make,
393 // and the buffer was only ever saving a copy this read does not
394 // have to do.
395 self.0 = Cow::Borrowed(text);
396 }
397 Ok(())
398 }
399}
400
401/// Write the span back out.
402///
403/// Compact, which is the default, that is one copy of the bytes that arrived
404/// and nothing else. Byte-for-byte preservation is the whole point of the
405/// type, so the bytes are not looked at, let alone reformatted.
406///
407/// Under [`PRETTY`](crate::Options::PRETTY) they are laid out again at the
408/// writer's current depth, through the same walk
409/// [`prettify`](crate::prettify) uses. A forwarded value is usually the one
410/// part of a document that did not come from a writer here, and emitting it
411/// verbatim would wedge an unindented blob between indented neighbours, which
412/// is what Glaze does and is jarring exactly where a human is reading. Reusing
413/// that walk rather than writing a second one is also what keeps the promise
414/// its module docs make: the output is byte-identical to what writing the same
415/// data under the same policy produces, because there is one set of layout
416/// rules rather than two. Tokens are still copied through as the input spelled
417/// them, so only the whitespace between them is this crate's and the
418/// passthrough guarantee survives the layout.
419///
420/// A span that is not one complete JSON value can only come from
421/// [`new_unchecked`](Raw::new_unchecked), and is written verbatim under either
422/// policy. `write` returns `()` and has no way to report the problem, so the
423/// choice is between laying out as much as parses and emitting what the caller
424/// supplied; emitting it is what the compact path would have done, which makes
425/// an invalid span behave the same way whichever policy is in force. The
426/// layout walk therefore settles the span's structure before it emits a byte,
427/// rather than starting and discovering the problem halfway: a writer has no
428/// way to take output back, so a fallback after a partial layout would write
429/// the value twice.
430impl Write for Raw<'_> {
431 #[inline]
432 fn write<O: Options>(&self, w: &mut Writer<'_, O>) {
433 if O::PRETTY && lay_out(self.as_str(), w) {
434 return;
435 }
436 w.raw(self.as_str());
437 }
438
439 /// Whether the span is the literal `null`.
440 ///
441 /// [`Write::is_null`] is about absence rather than about bytes, and a
442 /// `Raw` is the one type here where the two questions have the same
443 /// answer: it holds no value of its own, only the text of one, so what it
444 /// means under [`SKIP_NULL`](crate::Options::SKIP_NULL) is whatever the
445 /// value it stands for would have meant. A forwarded `null` is a forwarded
446 /// absence.
447 ///
448 /// The comparison is against the span exactly, which
449 /// [`new`](Raw::new) guarantees carries no surrounding whitespace. A `Raw`
450 /// built by [`new_unchecked`](Raw::new_unchecked) out of `" null "` is not
451 /// absent, for the same reason it is not the value `new` would have
452 /// stored.
453 #[inline]
454 fn is_null(&self) -> bool {
455 self.as_str() == NULL
456 }
457}
458
459/// The half-open span of `s` that is the value: one whole JSON value, with the
460/// whitespace on either side of it walked past.
461///
462/// The one walk behind both checked ways in, so what
463/// [`Raw::from_string`] accepts is what [`Raw::new`] accepts by construction
464/// rather than by two copies of a check staying in step.
465///
466/// `start` follows a run of whitespace and `end` is where stepping over the
467/// value stopped, so both are token boundaries and neither can be inside a
468/// character. That is what lets a caller slice on them, or move bytes between
469/// them, without checking again.
470fn span_of(s: &str) -> Result<(usize, usize)> {
471 let mut p = Parser::new(s);
472 p.skip_ws();
473 let start = p.position();
474 if let Err(code) = p.skip_value_checked() {
475 return Err(Error::new(code, p.position()));
476 }
477 let end = p.position();
478 if let Err(code) = p.finish() {
479 return Err(Error::new(code, p.position()));
480 }
481 Ok((start, end))
482}
483
484/// Lay `span` out into `w` at the writer's current depth, or answer `false`
485/// without having written anything.
486///
487/// Two passes, because the second one cannot be taken back. The probe walks
488/// the span without emitting, and decides the question the layout walk would
489/// otherwise decide halfway through it. Everything the probe checks,
490/// [`prettify_value_into`] checks the same way and with the same limits, being
491/// the same parser under the same policy, so a span the probe accepts is one
492/// the layout lays out to the end.
493///
494/// The cost is a second structural walk, and it is paid only under
495/// [`Options::PRETTY`], by a caller who has already asked for the expensive
496/// layout of the whole document. The compact path never reaches here.
497///
498/// The layout itself is the public call rather than anything private to the
499/// crate, so the entry point an outside implementer of a passthrough type has
500/// is the one this type exercises on every pretty write.
501fn lay_out<O: Options>(span: &str, w: &mut Writer<'_, O>) -> bool {
502 let mut probe = Parser::<O>::with_options(span);
503 if probe.skip_value().is_err() || probe.finish().is_err() {
504 return false;
505 }
506
507 let laid_out = prettify_value_into::<O>(span, w);
508 debug_assert!(
509 laid_out.is_ok(),
510 "the probe accepted a span the layout walk refused"
511 );
512 // True even in the impossible case: the value has been emitted, in part at
513 // worst, and falling back now would emit it a second time.
514 true
515}