Skip to main content

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}