Skip to main content

typesafe_sdk/
codec.rs

1//! JSON encoding and decoding for the whole crate.
2//!
3//! This is the only module that names `sonic_rs`. No type of that crate
4//! appears in any signature outside it, so replacing the codec is a change to
5//! this file alone.
6//!
7//! Four things here are not what a plain `serde_json` wrapper would do:
8//!
9//! * **The encode buffer is retained per thread.** Before every string write
10//!   the codec reserves `len * 6 + 35` bytes, so a buffer sized to the final
11//!   body re-allocates on every call. [`encode_body`] writes into a scratch
12//!   buffer this thread keeps between calls and copies the finished bytes into
13//!   an exactly sized one.
14//! * **Decoding runs a depth pre-scan first.** The codec has no recursion
15//!   limit on the paths this crate uses, and it aborts the process rather than
16//!   returning an error when the parser runs out of stack. A counter inside a
17//!   `serde` `Visitor` cannot help, because the overflow happens inside the
18//!   parser before the visitor is entered again; the guard has to be a pass
19//!   over the raw bytes. See [`check_depth`].
20//! * **Decode errors are rebuilt rather than forwarded.** The codec's own
21//!   `Display` embeds a multi-line excerpt of the input, and `serde`'s
22//!   type-mismatch messages quote the offending value; a `state` may carry
23//!   personal data, so [`DecodeError`] keeps only a kind, a position and a
24//!   field path.
25//! * **Raw JSON has a path for this codec and a path for every other one.**
26//!   Splicing text in unchanged, and capturing it on the way back, are both
27//!   protocols private to this codec. [`RawJson`] is public and users will
28//!   hand it to a codec of their own, so it also knows how to write itself out
29//!   as ordinary data and to read ordinary data back. See [`serialize_raw`]
30//!   and [`deserialize_raw`].
31
32use std::{
33    borrow::Cow,
34    cell::{Cell, RefCell},
35    fmt,
36    marker::PhantomData,
37};
38
39use bytes::Bytes;
40use serde::{
41    Deserialize, Deserializer, Serialize, Serializer, de,
42    de::{DeserializeSeed, IgnoredAny},
43    ser,
44    ser::{SerializeMap, SerializeSeq, SerializeStruct},
45};
46use thiserror::Error;
47
48use crate::text::{Backslash, SafeText};
49
50/// The deepest JSON nesting this crate will parse.
51///
52/// Anything deeper is rejected before a byte reaches the parser. The limit is
53/// far below what any documented API response needs; it exists because the
54/// parser's failure mode on deep input is a process abort.
55pub(crate) const MAX_JSON_DEPTH: usize = 16;
56
57// ------------------------------------------------------------------ errors
58
59/// The reason a JSON document could not be decoded.
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
61#[non_exhaustive]
62pub enum DecodeErrorKind {
63    /// The document is nested deeper than the 16 levels this crate parses, and
64    /// was rejected without being parsed.
65    TooDeep,
66    /// The bytes are not syntactically valid JSON, or they end early.
67    Syntax,
68    /// The document parses, but its shape does not match the expected type: a
69    /// field is missing, or a value has the wrong type.
70    Data,
71}
72
73/// A JSON document could not be decoded into the expected type.
74///
75/// The error deliberately carries no part of the input. A decoded document may
76/// contain application state and therefore personal data, and both the codec's
77/// own error text and `serde`'s type-mismatch messages quote the input. What
78/// is kept is the kind, the position and the field path, which are derived
79/// from the expected type rather than from the values.
80#[derive(Debug, Clone, PartialEq, Eq, Error)]
81#[error("{detail}")]
82#[non_exhaustive]
83pub struct DecodeError {
84    detail: Detail,
85}
86
87/// The rendered forms of [`DecodeError`], kept private so that the public type
88/// can gain fields without breaking callers.
89#[derive(Debug, Clone, PartialEq, Eq, Error)]
90enum Detail {
91    #[error("JSON input is nested deeper than the maximum of {}", MAX_JSON_DEPTH)]
92    TooDeep,
93    #[error("invalid JSON syntax at line {line} column {column}")]
94    Syntax { line: usize, column: usize },
95    #[error("unexpected JSON value at `{path}`, line {line} column {column}")]
96    Data { path: Box<str>, line: usize, column: usize },
97    /// The document does not have the shape the type expects, and the codec
98    /// could say neither where nor why. Rendering an empty path as ``at ` ` ``
99    /// would say less than saying nothing.
100    #[error("the JSON document does not have the expected shape")]
101    Opaque,
102}
103
104impl DecodeError {
105    /// Which of the three failure classes this is.
106    #[must_use]
107    pub fn kind(&self) -> DecodeErrorKind {
108        match self.detail {
109            Detail::TooDeep => DecodeErrorKind::TooDeep,
110            Detail::Syntax { .. } => DecodeErrorKind::Syntax,
111            Detail::Data { .. } | Detail::Opaque => DecodeErrorKind::Data,
112        }
113    }
114
115    /// The one-based line the parser stopped at, or 0 when the document was
116    /// rejected before it was parsed.
117    #[must_use]
118    pub fn line(&self) -> usize {
119        match self.detail {
120            Detail::TooDeep | Detail::Opaque => 0,
121            Detail::Syntax { line, .. } | Detail::Data { line, .. } => line,
122        }
123    }
124
125    /// The one-based column the parser stopped at, or 0 when the document was
126    /// rejected before it was parsed.
127    #[must_use]
128    pub fn column(&self) -> usize {
129        match self.detail {
130            Detail::TooDeep | Detail::Opaque => 0,
131            Detail::Syntax { column, .. } | Detail::Data { column, .. } => column,
132        }
133    }
134
135    /// The path of the offending field, with dotted names and bracketed
136    /// indices, for example `answers.tone.confidence` or `models[1].name`.
137    ///
138    /// The path of the document root is `.`, and it is empty when the failure
139    /// carries no path at all.
140    ///
141    /// A name in the path may be an object key the input chose, so it is
142    /// rendered safe to print: a control character or a format character that
143    /// reorders or hides text is written as a Rust escape (`\n`, `\u{1b}`,
144    /// `\u{202e}`), a backslash is written `\\` so that an escape cannot be
145    /// mistaken for text, and other printable text, non-ASCII included, is kept
146    /// as it is.
147    /// Each name is cut at 128 characters and the whole path at 320, counted
148    /// after escaping, and a cut is marked with U+2026.
149    #[must_use]
150    pub fn path(&self) -> &str {
151        match &self.detail {
152            Detail::TooDeep | Detail::Syntax { .. } | Detail::Opaque => "",
153            Detail::Data { path, .. } => path,
154        }
155    }
156
157    fn too_deep() -> Self {
158        Self { detail: Detail::TooDeep }
159    }
160}
161
162/// A value could not be encoded as JSON.
163///
164/// The message comes from the codec's serializer, which reports the failing
165/// step - a map key that is not a string, a boolean or a number, or an error
166/// returned by the value's own [`Serialize`] implementation - and never quotes
167/// the value.
168#[derive(Debug, Clone, PartialEq, Eq, Error)]
169#[error("the value could not be encoded as JSON: {message}")]
170#[non_exhaustive]
171pub struct EncodeError {
172    message: Box<str>,
173}
174
175impl EncodeError {
176    /// The serializer's description of what went wrong.
177    #[must_use]
178    pub fn message(&self) -> &str {
179        &self.message
180    }
181
182    /// Serialization errors carry no position and no input excerpt, so the
183    /// codec's `Display` is safe to keep here. Decode errors are not, which is
184    /// why [`DecodeError`] is rebuilt from parts instead.
185    fn from_codec(error: sonic_rs::Error) -> Self {
186        Self { message: error.to_string().into_boxed_str() }
187    }
188}
189
190// ---------------------------------------------------------------- encoding
191
192thread_local! {
193    /// The buffer [`encode_body`] writes into, kept between calls.
194    ///
195    /// It is an `Option` because the buffer is taken out for the duration of a
196    /// call rather than borrowed: the closure runs arbitrary `Serialize`
197    /// implementations, and one of them encoding a body of its own would panic
198    /// on a `RefCell` borrow held across it.
199    static SCRATCH: RefCell<Option<Vec<u8>>> = const { RefCell::new(None) };
200    /// The recent body size this thread encodes, decayed by a sixteenth per
201    /// call so that a single large outlier stops pinning the buffer.
202    static SCRATCH_HINT: Cell<usize> = const { Cell::new(0) };
203}
204
205/// The most encode scratch a thread keeps between calls: 8 MiB.
206///
207/// The codec reserves six times a string's length before writing it, so the
208/// scratch a large string state leaves behind is six times the state, and a
209/// thread would keep it until later calls on that same thread decayed it
210/// away - never, on a thread that goes idle. A scratch over this size is
211/// dropped after its call instead, and a state that large grows it afresh on
212/// every call, as a first call does. The scratch of a 1 MB state, the largest
213/// one a call is budgeted for, stays under the ceiling, so its calls keep
214/// reusing it.
215const MAX_RETAINED_SCRATCH: usize = 8 * 1024 * 1024;
216
217/// Appends the JSON form of `value` to `buf`.
218///
219/// The buffer is not cleared, which is what lets a request body be spliced out
220/// of literal fragments and encoded values in one pass.
221///
222/// # Errors
223///
224/// Returns [`EncodeError`] when the value cannot be represented as JSON: a
225/// map whose keys are neither strings, booleans nor numbers, or a
226/// [`Serialize`] implementation that returns an error of its own. A non-finite
227/// float is not one of these - it is written as `null`, which is what
228/// `serde_json` does as well. The buffer may then hold a partial encoding of
229/// that value, so a caller that reuses it has to truncate it.
230pub(crate) fn encode_into<T>(buf: &mut Vec<u8>, value: &T) -> Result<(), EncodeError>
231where
232    T: Serialize + ?Sized,
233{
234    // The mark is what tells `RawJson` that the serializer about to run is
235    // this crate's own, and so that raw text may be spliced in verbatim.
236    let _inside = EncoderMark::enter();
237    sonic_rs::to_writer(&mut *buf, value).map_err(EncodeError::from_codec)
238}
239
240/// Appends `text` to `buf` as a JSON string literal, quoted and escaped.
241pub(crate) fn write_json_string(buf: &mut Vec<u8>, text: &str) {
242    encode_into(buf, text).expect("invariant: encoding a string into a Vec cannot fail");
243}
244
245/// Builds one request body and hands it over as exactly sized [`Bytes`].
246///
247/// `fill` writes the whole body into a buffer this thread keeps between calls,
248/// so a repeated call of the same shape allocates once: the copy into the
249/// returned buffer. A buffer that grew past [`MAX_RETAINED_SCRATCH`] is not
250/// kept. That buffer has `len == capacity`, which makes
251/// `Bytes::from` a move rather than a copy and defers the shared-header
252/// allocation to the first `clone`.
253///
254/// The scratch buffer is taken out of the thread-local for the duration of the
255/// call. A `Serialize` implementation that calls this function again therefore
256/// gets a buffer of its own instead of corrupting the outer one, and a panic
257/// inside `fill` drops the buffer rather than leaving a damaged one behind.
258///
259/// # Errors
260///
261/// Returns whatever `fill` returns.
262pub(crate) fn encode_body<F>(fill: F) -> Result<Bytes, EncodeError>
263where
264    F: FnOnce(&mut Vec<u8>) -> Result<(), EncodeError>,
265{
266    let mut scratch = SCRATCH.with(|cell| cell.borrow_mut().take()).unwrap_or_default();
267    scratch.clear();
268
269    // `to_vec` allocates exactly `len` bytes, so the body buffer is full and
270    // `Bytes::from` takes it over without copying again.
271    let body = fill(&mut scratch).map(|()| Bytes::from(scratch.as_slice().to_vec()));
272
273    let hint = SCRATCH_HINT.get();
274    let decayed = scratch.len().max(hint - hint / 16);
275    SCRATCH_HINT.set(decayed);
276    if scratch.capacity() > MAX_RETAINED_SCRATCH {
277        // Not shrunk to the hint either: a hint this large is the body that
278        // just passed the ceiling, and keeping it would hold the memory the
279        // ceiling exists to release.
280        scratch = Vec::new();
281    } else if scratch.capacity() > decayed.saturating_mul(8) {
282        // The shrink goes all the way down to the hint rather than to the
283        // bound: stopping at the bound leaves the capacity exactly where the
284        // still-decaying hint lowers it again, so every following call
285        // re-allocates the whole buffer.
286        scratch.shrink_to(decayed);
287    }
288    SCRATCH.with(|cell| cell.replace(Some(scratch)));
289
290    body
291}
292
293/// Bytes the encode scratch of this thread is holding on to.
294#[cfg(any(test, feature = "internals"))]
295pub(crate) fn scratch_capacity() -> usize {
296    SCRATCH.with(|cell| cell.borrow().as_ref().map_or(0, Vec::capacity))
297}
298
299/// The decayed size hint this thread carries.
300#[cfg(any(test, feature = "internals"))]
301pub(crate) fn scratch_hint() -> usize {
302    SCRATCH_HINT.get()
303}
304
305/// Drops this thread's encode scratch and its size hint, so that the next call
306/// starts from the state of a fresh thread.
307#[cfg(any(test, feature = "internals"))]
308pub(crate) fn reset_scratch() {
309    SCRATCH.with(|cell| cell.replace(None));
310    SCRATCH_HINT.set(0);
311}
312
313// ---------------------------------------------------------------- decoding
314
315/// Rejects JSON nested deeper than [`MAX_JSON_DEPTH`].
316///
317/// This runs over the raw bytes, before any of them reach the parser, and it
318/// only counts brackets outside string literals. It does not validate the
319/// document: unbalanced or misplaced brackets are the parser's business.
320///
321/// # Errors
322///
323/// Returns a [`DecodeErrorKind::TooDeep`] error at the first bracket that
324/// crosses the limit.
325pub(crate) fn check_depth(json: &[u8]) -> Result<(), DecodeError> {
326    let mut depth = 0usize;
327    let mut in_string = false;
328    let mut escaped = false;
329
330    for &byte in json {
331        if in_string {
332            if escaped {
333                // Every escape sequence this matters for is one byte long
334                // (`\"` and `\\`); the four hex digits of `\uXXXX` contain no
335                // quote or backslash, so skipping one byte is enough.
336                escaped = false;
337            } else if byte == b'\\' {
338                escaped = true;
339            } else if byte == b'"' {
340                in_string = false;
341            }
342            continue;
343        }
344
345        match byte {
346            b'"' => in_string = true,
347            b'[' | b'{' => {
348                depth += 1;
349                if depth > MAX_JSON_DEPTH {
350                    return Err(DecodeError::too_deep());
351                }
352            }
353            b']' | b'}' => depth = depth.saturating_sub(1),
354            _ => {}
355        }
356    }
357
358    Ok(())
359}
360
361/// Checks that `bytes` are UTF-8, and hands them back as text.
362///
363/// Every decode starts here, before the depth pre-scan and before any byte
364/// reaches the codec, because the codec cannot be trusted with anything
365/// else: when it reads a string it takes the bytes as text without checking
366/// them (a `debug_assert!` in its debug builds, nothing in its release
367/// builds), and it reports a byte that is not UTF-8 only once the whole
368/// document has been read - after a string holding one has already been
369/// handed on as text. The codec is then given the checked text, which it does
370/// not check a second time.
371///
372/// # Errors
373///
374/// Returns a [`DecodeErrorKind::Syntax`] error at the first byte that is not
375/// part of a UTF-8 character: JSON text is UTF-8 (RFC 8259, section 8.1), so a
376/// document holding such a byte is not JSON. The position counts bytes, as the
377/// codec's own positions do.
378fn as_text(bytes: &[u8]) -> Result<&str, DecodeError> {
379    std::str::from_utf8(bytes).map_err(|failure| {
380        let before = &bytes[..failure.valid_up_to()];
381        let line = 1 + before.iter().filter(|&&byte| byte == b'\n').count();
382        let line_start = before.iter().rposition(|&byte| byte == b'\n').map_or(0, |at| at + 1);
383        let column = 1 + before.len() - line_start;
384        DecodeError { detail: Detail::Syntax { line, column } }
385    })
386}
387
388/// Decodes `bytes` into `T`.
389///
390/// The successful path is a single pass and pays nothing for error reporting.
391/// A failure is decoded a second time through a path-tracking wrapper, which
392/// is what turns a bare position into `answers.tone.confidence`.
393///
394/// # Errors
395///
396/// Returns [`DecodeError`] when the input is not UTF-8, is nested too deeply,
397/// is not valid JSON, or does not have the shape `T` expects.
398pub(crate) fn decode<'de, T>(bytes: &'de [u8]) -> Result<T, DecodeError>
399where
400    T: Deserialize<'de>,
401{
402    let text = as_text(bytes)?;
403    check_depth(bytes)?;
404    // `PhantomData<T>` is serde's own seed for "decode a `T`", which is what
405    // lets the failure pass below serve this function and `decode_seed` alike.
406    sonic_rs::from_str::<T>(text).map_err(|_| describe_failure(text, PhantomData::<T>))
407}
408
409/// Decodes `bytes` through `seed`, a decoder that carries state of its own -
410/// how many answers to make room for, for instance - which a type's
411/// `Deserialize` cannot receive.
412///
413/// Everything else is [`decode`]: the same UTF-8 check and depth pre-scan,
414/// one pass on success that accepts exactly what `decode` accepts, and on
415/// failure the same second, path-tracking pass. That second pass needs the
416/// seed again, which is why it is `Clone`: a seed is consumed by the pass it
417/// drives.
418///
419/// # Errors
420///
421/// Returns [`DecodeError`] when the input is not UTF-8, is nested too deeply,
422/// is not valid JSON, or does not have the shape the seed expects.
423pub(crate) fn decode_seed<'de, S>(bytes: &'de [u8], seed: S) -> Result<S::Value, DecodeError>
424where
425    S: DeserializeSeed<'de> + Clone,
426{
427    let text = as_text(bytes)?;
428    check_depth(bytes)?;
429    // The codec's entry point for a type checks that the value is followed by
430    // nothing but whitespace; its deserializer does that only when asked, with
431    // `end`.
432    let decoded = {
433        let mut deserializer = sonic_rs::Deserializer::from_str(text);
434        seed.clone()
435            .deserialize(&mut deserializer)
436            .ok()
437            .and_then(|value| deserializer.end().ok().map(|()| value))
438    };
439    decoded.ok_or_else(|| describe_failure(text, seed))
440}
441
442/// Re-runs a failed decode with path tracking and turns the result into a
443/// [`DecodeError`] that carries no part of the input.
444///
445/// `text` is what [`as_text`] returned, so it is read without a second check.
446fn describe_failure<'de, S>(text: &'de str, seed: S) -> DecodeError
447where
448    S: DeserializeSeed<'de>,
449{
450    let mut deserializer = sonic_rs::Deserializer::from_str(text);
451    let mut track = serde_path_to_error::Track::new();
452    let failure = seed
453        .deserialize(serde_path_to_error::Deserializer::new(&mut deserializer, &mut track))
454        .err();
455    let Some(inner) = failure else {
456        // The tracked pass reads one value and stops there; unlike the first
457        // pass it never looks at what follows it. So a document with anything
458        // but whitespace after its value parses here and failed there, and
459        // asking the deserializer to finish is the only way to get the
460        // position of the byte the first pass tripped on.
461        return match deserializer.end() {
462            Err(trailing) => DecodeError {
463                detail: Detail::Syntax { line: trailing.line(), column: trailing.column() },
464            },
465            // Both passes read the same bytes with the same type and
466            // disagreed on whether they parse at all. Nothing about the
467            // input can be reported beyond that disagreement.
468            Ok(()) => DecodeError { detail: Detail::Opaque },
469        };
470    };
471    let path = track.path();
472
473    let line = inner.line();
474    let column = inner.column();
475    let category = inner.classify();
476
477    if matches!(category, sonic_rs::error::Category::Syntax | sonic_rs::error::Category::Eof) {
478        return DecodeError { detail: Detail::Syntax { line, column } };
479    }
480
481    // `serde` reports a missing field at the struct that misses it, and names
482    // the field only in the message. The message itself is not kept - a
483    // type-mismatch message quotes the offending value - but the field name in
484    // it comes from the target type, so appending it is safe and gives a
485    // missing and a wrongly typed field the same shape of path.
486    let message = inner.to_string();
487    let path = render_path(&path, missing_field_name(&message));
488
489    DecodeError { detail: Detail::Data { path: path.into_boxed_str(), line, column } }
490}
491
492/// The most characters one name in a field path is rendered with before it is
493/// cut and marked with an ellipsis.
494///
495/// A name in a path can be a key the server chose - a question name, a legend
496/// level, a choice option - so it is bounded like any other server text in an
497/// error. The bound is well above any name a caller would give a question.
498const MAX_PATH_SEGMENT_CHARS: usize = 128;
499
500/// The most characters a whole field path is rendered with before it is cut
501/// and marked with an ellipsis.
502///
503/// It holds the deepest path the response schema has,
504/// `answers.<name>.probabilities.<option>`, with both names at their own cap.
505const MAX_PATH_CHARS: usize = 320;
506
507/// Renders a field path the way `serde_path_to_error` does - dotted names,
508/// bracketed indices, `.` for the root - with every name escaped and cut as
509/// `crate::text` describes, and a backslash written `\\` so that no escape
510/// can be mistaken for text. Each name is capped at [`MAX_PATH_SEGMENT_CHARS`]
511/// characters and the whole path at [`MAX_PATH_CHARS`].
512fn render_path(path: &serde_path_to_error::Path, missing: Option<&str>) -> String {
513    use serde_path_to_error::Segment;
514
515    let mut out = SafeText::new(MAX_PATH_CHARS, Backslash::Double);
516    // A name is preceded by a dot unless it starts the path; an index never
517    // is. Whether it starts the path cannot be read off the text, because a
518    // key may be the empty string.
519    let mut first = true;
520    for segment in path {
521        match segment {
522            Segment::Seq { index } => out.fixed(&format!("[{index}]")),
523            Segment::Map { key } | Segment::Enum { variant: key } => {
524                if !first {
525                    out.fixed(".");
526                }
527                out.untrusted(key, MAX_PATH_SEGMENT_CHARS);
528            }
529            Segment::Unknown => out.fixed(if first { "?" } else { ".?" }),
530        }
531        first = false;
532    }
533    match missing {
534        Some(field) => {
535            if !first {
536                out.fixed(".");
537            }
538            out.untrusted(field, MAX_PATH_SEGMENT_CHARS);
539        }
540        None if first => out.fixed("."),
541        None => {}
542    }
543    out.into_string()
544}
545
546/// Extracts `noul` from ``missing field `noul` at line 1 column 101``.
547fn missing_field_name(message: &str) -> Option<&str> {
548    let rest = message.strip_prefix("missing field `")?;
549    let end = rest.find('`')?;
550    Some(&rest[..end])
551}
552
553// ------------------------------------------------------------- raw JSON
554
555/// The struct name sonic-rs reads as "the one field below is JSON text
556/// already, write it out unchanged".
557///
558/// The constant is private to that crate, so the name is spelled out here
559/// rather than reached by serializing a `sonic_rs::LazyValue`: building one of
560/// those needs a parse of the text, and the parser has no recursion limit, so
561/// that would put a process abort on the outbound path for a deeply nested
562/// value. Should a later sonic-rs rename the token, the splice degrades into
563/// an ordinary one-field object and the round-trip tests fail on it.
564const SPLICE_TOKEN: &str = "$sonic_rs::LazyValue";
565
566thread_local! {
567    /// How many [`encode_into`] calls this thread is inside.
568    ///
569    /// A counter rather than a flag, because a `Serialize` implementation the
570    /// encoder reaches may encode a value of its own.
571    static INSIDE_SDK_ENCODER: Cell<u32> = const { Cell::new(0) };
572}
573
574/// Marks this thread as being inside the SDK's serializer while it lives.
575///
576/// serde offers no way to ask a `Serializer` which implementation it is, and
577/// the verbatim splice below is a protocol only this crate's codec
578/// understands. The mark is therefore set where the codec's serializer is
579/// built - [`encode_into`], the single place in the crate that builds one -
580/// and read by [`serialize_raw`].
581struct EncoderMark;
582
583impl EncoderMark {
584    fn enter() -> Self {
585        INSIDE_SDK_ENCODER.with(|depth| depth.set(depth.get().saturating_add(1)));
586        Self
587    }
588
589    /// Whether the value being serialized on this thread is on its way into
590    /// the SDK's own encoder.
591    fn is_set() -> bool {
592        INSIDE_SDK_ENCODER.with(|depth| depth.get() > 0)
593    }
594}
595
596impl Drop for EncoderMark {
597    fn drop(&mut self) {
598        INSIDE_SDK_ENCODER.with(|depth| depth.set(depth.get().saturating_sub(1)));
599    }
600}
601
602/// Writes raw JSON text through `serializer`.
603///
604/// Inside this crate's encoder the text is spliced in byte for byte. Through
605/// any other serializer it is streamed out as ordinary JSON data instead, so
606/// that a value which travels through, say, `serde_json` carries the data it
607/// holds rather than a protocol this crate's codec invented.
608///
609/// # Errors
610///
611/// Returns the serializer's own error, and a too-deep error when a value on
612/// the transcoding path is nested deeper than [`MAX_JSON_DEPTH`].
613fn serialize_raw<S>(text: &str, serializer: S) -> Result<S::Ok, S::Error>
614where
615    S: Serializer,
616{
617    if EncoderMark::is_set() { splice(text, serializer) } else { transcode(text, serializer) }
618}
619
620/// Hands `text` to this crate's codec for a verbatim splice.
621///
622/// Nothing parses the text here: a `RawJson` only ever holds text the codec
623/// produced or captured, so the splice writes bytes the codec has already
624/// accepted once.
625fn splice<S>(text: &str, serializer: S) -> Result<S::Ok, S::Error>
626where
627    S: Serializer,
628{
629    let mut raw = serializer.serialize_struct(SPLICE_TOKEN, 1)?;
630    raw.serialize_field(SPLICE_TOKEN, text)?;
631    raw.end()
632}
633
634/// Streams the JSON value in `text` into a serializer that is not this crate's
635/// codec.
636///
637/// Nothing is buffered and no value tree is built: every value read out of
638/// `text` is handed straight to `serializer`. The data is preserved; its
639/// spelling is not, because the target serializer chooses its own number
640/// format and drops the insignificant whitespace the text may carry.
641///
642/// # Errors
643///
644/// Returns a too-deep error when `text` is nested deeper than
645/// [`MAX_JSON_DEPTH`], and otherwise whatever `serializer` returns.
646fn transcode<S>(text: &str, serializer: S) -> Result<S::Ok, S::Error>
647where
648    S: Serializer,
649{
650    // Both the transcode and the parser driving it descend one stack frame per
651    // nesting level. The cap the decode path uses bounds that recursion, which
652    // is what stops a `RawJson` built by `RawJson::from_value` from an
653    // arbitrarily deep value from overflowing the stack here; the splice path
654    // above does not read the text at all and so needs no cap.
655    check_depth(text.as_bytes()).map_err(ser::Error::custom)?;
656
657    let mut source = sonic_rs::Deserializer::from_str(text);
658    Transcoder::new(&mut source).serialize(serializer)
659}
660
661/// The prefix that marks a serializer error on its way out through the
662/// deserializer driving a transcode.
663const REFUSED: &str = "the JSON writer refused a value: ";
664
665/// Wraps a serializer error so that it survives the trip out through the
666/// deserializer. The two halves of a transcode share no error type, so the
667/// message is all that can cross.
668fn writer_refused<E, D>(error: E) -> D
669where
670    E: fmt::Display,
671    D: de::Error,
672{
673    de::Error::custom(format_args!("{REFUSED}{error}"))
674}
675
676/// Turns the error a transcode comes back with into a serializer error.
677///
678/// Only a message [`writer_refused`] marked is passed on. Anything else was
679/// raised by the parser, whose `Display` embeds an excerpt of what it was
680/// reading, and the text of a `RawJson` may be application data.
681fn transcode_failed<E, S>(error: E) -> S
682where
683    E: fmt::Display,
684    S: ser::Error,
685{
686    let rendered = error.to_string();
687    match rendered.split_once(REFUSED) {
688        Some((_, message)) => ser::Error::custom(message),
689        None => ser::Error::custom("the stored JSON text could not be read back"),
690    }
691}
692
693/// A `Serialize` that writes whatever one deserializer yields.
694///
695/// serde drives serializing from the value side and deserializing from the
696/// visitor side, so a transcode has to hand the serializer something that
697/// implements `Serialize` and pulls from a deserializer when it is asked to
698/// write. That single call consumes the deserializer, which is why it sits in
699/// a `RefCell<Option<_>>` rather than being held by value.
700struct Transcoder<D> {
701    source: RefCell<Option<D>>,
702}
703
704impl<D> Transcoder<D> {
705    fn new(source: D) -> Self {
706        Self { source: RefCell::new(Some(source)) }
707    }
708}
709
710impl<'de, D> Serialize for Transcoder<D>
711where
712    D: Deserializer<'de>,
713{
714    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
715    where
716        S: Serializer,
717    {
718        let Some(source) = self.source.borrow_mut().take() else {
719            return Err(ser::Error::custom("a raw JSON value can be written only once"));
720        };
721        source.deserialize_any(TranscodeVisitor { serializer }).map_err(transcode_failed)
722    }
723}
724
725/// Hands every value it is shown straight to `serializer`.
726struct TranscodeVisitor<S> {
727    serializer: S,
728}
729
730impl<'de, S> de::Visitor<'de> for TranscodeVisitor<S>
731where
732    S: Serializer,
733{
734    type Value = S::Ok;
735
736    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
737        formatter.write_str("any JSON value")
738    }
739
740    fn visit_bool<E: de::Error>(self, value: bool) -> Result<Self::Value, E> {
741        self.serializer.serialize_bool(value).map_err(writer_refused)
742    }
743
744    fn visit_i64<E: de::Error>(self, value: i64) -> Result<Self::Value, E> {
745        self.serializer.serialize_i64(value).map_err(writer_refused)
746    }
747
748    fn visit_i128<E: de::Error>(self, value: i128) -> Result<Self::Value, E> {
749        self.serializer.serialize_i128(value).map_err(writer_refused)
750    }
751
752    fn visit_u64<E: de::Error>(self, value: u64) -> Result<Self::Value, E> {
753        self.serializer.serialize_u64(value).map_err(writer_refused)
754    }
755
756    fn visit_u128<E: de::Error>(self, value: u128) -> Result<Self::Value, E> {
757        self.serializer.serialize_u128(value).map_err(writer_refused)
758    }
759
760    fn visit_f64<E: de::Error>(self, value: f64) -> Result<Self::Value, E> {
761        self.serializer.serialize_f64(value).map_err(writer_refused)
762    }
763
764    fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
765        self.serializer.serialize_str(value).map_err(writer_refused)
766    }
767
768    fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
769        self.serializer.serialize_unit().map_err(writer_refused)
770    }
771
772    fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
773        self.serializer.serialize_none().map_err(writer_refused)
774    }
775
776    fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
777    where
778        D: Deserializer<'de>,
779    {
780        deserializer.deserialize_any(self)
781    }
782
783    fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
784    where
785        D: Deserializer<'de>,
786    {
787        deserializer.deserialize_any(self)
788    }
789
790    fn visit_seq<A>(self, mut access: A) -> Result<Self::Value, A::Error>
791    where
792        A: de::SeqAccess<'de>,
793    {
794        let mut sequence =
795            self.serializer.serialize_seq(access.size_hint()).map_err(writer_refused)?;
796        while access.next_element_seed(TranscodeElement { sequence: &mut sequence })?.is_some() {}
797        sequence.end().map_err(writer_refused)
798    }
799
800    fn visit_map<A>(self, mut access: A) -> Result<Self::Value, A::Error>
801    where
802        A: de::MapAccess<'de>,
803    {
804        let mut map = self.serializer.serialize_map(access.size_hint()).map_err(writer_refused)?;
805        loop {
806            let key = access.next_key_seed(TranscodeKey { map: &mut map })?;
807            if key.is_none() {
808                break;
809            }
810            access.next_value_seed(TranscodeValue { map: &mut map })?;
811        }
812        map.end().map_err(writer_refused)
813    }
814}
815
816/// Writes the element the deserializer is positioned on into `sequence`.
817struct TranscodeElement<'s, S> {
818    sequence: &'s mut S,
819}
820
821impl<'de, S> de::DeserializeSeed<'de> for TranscodeElement<'_, S>
822where
823    S: SerializeSeq,
824{
825    type Value = ();
826
827    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
828    where
829        D: Deserializer<'de>,
830    {
831        self.sequence.serialize_element(&Transcoder::new(deserializer)).map_err(writer_refused)
832    }
833}
834
835/// Writes the key the deserializer is positioned on into `map`.
836struct TranscodeKey<'s, S> {
837    map: &'s mut S,
838}
839
840impl<'de, S> de::DeserializeSeed<'de> for TranscodeKey<'_, S>
841where
842    S: SerializeMap,
843{
844    type Value = ();
845
846    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
847    where
848        D: Deserializer<'de>,
849    {
850        self.map.serialize_key(&Transcoder::new(deserializer)).map_err(writer_refused)
851    }
852}
853
854/// Writes the value the deserializer is positioned on into `map`.
855struct TranscodeValue<'s, S> {
856    map: &'s mut S,
857}
858
859impl<'de, S> de::DeserializeSeed<'de> for TranscodeValue<'_, S>
860where
861    S: SerializeMap,
862{
863    type Value = ();
864
865    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
866    where
867        D: Deserializer<'de>,
868    {
869        self.map.serialize_value(&Transcoder::new(deserializer)).map_err(writer_refused)
870    }
871}
872
873/// Rejects text that is not exactly one complete JSON value.
874///
875/// A [`RawJson`] is written into a request body without being read again, so
876/// text carrying a second value would splice that value - a key of the
877/// caller's choosing, say - into the enclosing object, and text that is not
878/// JSON at all would make the whole body unparseable. Every value this codec
879/// captures is one value already; what needs guarding is a string handed over
880/// by a deserializer that answered the raw-text request with whatever the
881/// caller had put in it.
882///
883/// The scan allocates nothing on the accepting path: the depth pre-scan reads
884/// the bytes, and the parser then skips one value and checks that only
885/// whitespace follows.
886fn one_json_value<E: de::Error>(text: &str) -> Result<(), E> {
887    decode::<IgnoredAny>(text.as_bytes()).map_err(de::Error::custom)?;
888    Ok(())
889}
890
891/// Reads the next value as its raw JSON text, without interpreting it.
892///
893/// This crate's codec answers the request with the text of the value as the
894/// wire carried it, borrowed from the input whenever it can be - which it
895/// cannot when the value is a string holding escape sequences. Any other
896/// deserializer does not know the request and passes itself on instead; the
897/// value is then read as ordinary JSON and rendered back to compact text, so
898/// what comes out holds the same data rather than failing.
899///
900/// A format that neither knows the request nor forwards itself, but answers it
901/// with a bare string, cannot be told apart from the codec's own raw-text
902/// answer, so the string is read as JSON text rather than as a JSON string.
903/// Such text is checked before it is accepted: one complete JSON value is
904/// taken at face value, and anything else - a second value after the first,
905/// or text that is not JSON - is refused rather than carried into a request
906/// body. No JSON codec behaves that way, so in practice this guards a string
907/// a caller supplied by hand.
908///
909/// # Errors
910///
911/// Returns the deserializer's own error, and a too-deep error when a document
912/// read through a foreign deserializer nests deeper than [`MAX_JSON_DEPTH`].
913pub(crate) fn deserialize_raw<'de, D>(deserializer: D) -> Result<Cow<'de, str>, D::Error>
914where
915    D: Deserializer<'de>,
916{
917    deserializer.deserialize_newtype_struct(SPLICE_TOKEN, RawTextVisitor)
918}
919
920/// The two ways a value arrives at [`deserialize_raw`].
921struct RawTextVisitor;
922
923impl<'de> de::Visitor<'de> for RawTextVisitor {
924    type Value = Cow<'de, str>;
925
926    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
927        formatter.write_str("any JSON value")
928    }
929
930    /// This crate's codec, handing over the raw text of the value.
931    ///
932    /// The check is redundant for that codec, which never hands over anything
933    /// else, and is what holds the invariant for a deserializer that answers
934    /// the raw-text request with a string of the caller's own. The borrow
935    /// survives it.
936    fn visit_borrowed_str<E: de::Error>(self, value: &'de str) -> Result<Self::Value, E> {
937        one_json_value(value)?;
938        Ok(Cow::Borrowed(value))
939    }
940
941    /// The same, for text the codec had to rebuild because it holds escapes.
942    fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
943        one_json_value(value)?;
944        Ok(Cow::Owned(value.to_owned()))
945    }
946
947    /// Any other deserializer: it does not know the request above, so it hands
948    /// itself over and the value is read as data.
949    fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
950    where
951        D: Deserializer<'de>,
952    {
953        let mut out = Vec::new();
954        deserializer.deserialize_any(Render { out: &mut out, depth: 0 })?;
955        Ok(Cow::Owned(rendered_text(out)))
956    }
957
958    fn visit_bool<E: de::Error>(self, value: bool) -> Result<Self::Value, E> {
959        Ok(Cow::Borrowed(if value { "true" } else { "false" }))
960    }
961
962    fn visit_i64<E: de::Error>(self, value: i64) -> Result<Self::Value, E> {
963        render_scalar(&value)
964    }
965
966    fn visit_i128<E: de::Error>(self, value: i128) -> Result<Self::Value, E> {
967        render_scalar(&value)
968    }
969
970    fn visit_u64<E: de::Error>(self, value: u64) -> Result<Self::Value, E> {
971        render_scalar(&value)
972    }
973
974    fn visit_u128<E: de::Error>(self, value: u128) -> Result<Self::Value, E> {
975        render_scalar(&value)
976    }
977
978    fn visit_f64<E: de::Error>(self, value: f64) -> Result<Self::Value, E> {
979        render_scalar(&value)
980    }
981
982    fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
983        Ok(Cow::Borrowed("null"))
984    }
985
986    fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
987        Ok(Cow::Borrowed("null"))
988    }
989
990    fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
991    where
992        D: Deserializer<'de>,
993    {
994        self.visit_newtype_struct(deserializer)
995    }
996
997    fn visit_seq<A>(self, access: A) -> Result<Self::Value, A::Error>
998    where
999        A: de::SeqAccess<'de>,
1000    {
1001        let mut out = Vec::new();
1002        de::Visitor::visit_seq(Render { out: &mut out, depth: 0 }, access)?;
1003        Ok(Cow::Owned(rendered_text(out)))
1004    }
1005
1006    fn visit_map<A>(self, access: A) -> Result<Self::Value, A::Error>
1007    where
1008        A: de::MapAccess<'de>,
1009    {
1010        let mut out = Vec::new();
1011        de::Visitor::visit_map(Render { out: &mut out, depth: 0 }, access)?;
1012        Ok(Cow::Owned(rendered_text(out)))
1013    }
1014}
1015
1016/// Encodes one scalar on its own, for a value that reached
1017/// [`RawTextVisitor`] without any surrounding structure.
1018fn render_scalar<'de, T, E>(value: &T) -> Result<Cow<'de, str>, E>
1019where
1020    T: Serialize + ?Sized,
1021    E: de::Error,
1022{
1023    let mut out = Vec::new();
1024    encode_into(&mut out, value).map_err(de::Error::custom)?;
1025    Ok(Cow::Owned(rendered_text(out)))
1026}
1027
1028/// The bytes a render wrote, as text.
1029fn rendered_text(out: Vec<u8>) -> String {
1030    String::from_utf8(out).expect("invariant: the renderer emits UTF-8")
1031}
1032
1033/// Writes one JSON value, read from a deserializer that is not this crate's
1034/// codec, into `out` as compact JSON text.
1035///
1036/// It is both the seed that a container hands to its elements and the visitor
1037/// that writes them, so a nested document costs one stack frame per level and
1038/// no intermediate value.
1039struct Render<'b> {
1040    out: &'b mut Vec<u8>,
1041    depth: usize,
1042}
1043
1044/// The depth one level in, or a too-deep error at the cap.
1045fn one_level_in<E: de::Error>(depth: usize) -> Result<usize, E> {
1046    if depth >= MAX_JSON_DEPTH {
1047        return Err(de::Error::custom(DecodeError::too_deep()));
1048    }
1049    Ok(depth + 1)
1050}
1051
1052impl<'de> de::DeserializeSeed<'de> for Render<'_> {
1053    type Value = ();
1054
1055    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
1056    where
1057        D: Deserializer<'de>,
1058    {
1059        deserializer.deserialize_any(self)
1060    }
1061}
1062
1063impl<'de> de::Visitor<'de> for Render<'_> {
1064    type Value = ();
1065
1066    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1067        formatter.write_str("any JSON value")
1068    }
1069
1070    fn visit_bool<E: de::Error>(self, value: bool) -> Result<Self::Value, E> {
1071        self.out.extend_from_slice(if value { b"true" } else { b"false" });
1072        Ok(())
1073    }
1074
1075    fn visit_i64<E: de::Error>(self, value: i64) -> Result<Self::Value, E> {
1076        encode_into(self.out, &value).map_err(de::Error::custom)
1077    }
1078
1079    fn visit_i128<E: de::Error>(self, value: i128) -> Result<Self::Value, E> {
1080        encode_into(self.out, &value).map_err(de::Error::custom)
1081    }
1082
1083    fn visit_u64<E: de::Error>(self, value: u64) -> Result<Self::Value, E> {
1084        encode_into(self.out, &value).map_err(de::Error::custom)
1085    }
1086
1087    fn visit_u128<E: de::Error>(self, value: u128) -> Result<Self::Value, E> {
1088        encode_into(self.out, &value).map_err(de::Error::custom)
1089    }
1090
1091    fn visit_f64<E: de::Error>(self, value: f64) -> Result<Self::Value, E> {
1092        encode_into(self.out, &value).map_err(de::Error::custom)
1093    }
1094
1095    fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
1096        write_json_string(self.out, value);
1097        Ok(())
1098    }
1099
1100    fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
1101        self.out.extend_from_slice(b"null");
1102        Ok(())
1103    }
1104
1105    fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
1106        self.out.extend_from_slice(b"null");
1107        Ok(())
1108    }
1109
1110    fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
1111    where
1112        D: Deserializer<'de>,
1113    {
1114        deserializer.deserialize_any(self)
1115    }
1116
1117    fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
1118    where
1119        D: Deserializer<'de>,
1120    {
1121        deserializer.deserialize_any(self)
1122    }
1123
1124    fn visit_seq<A>(self, mut access: A) -> Result<Self::Value, A::Error>
1125    where
1126        A: de::SeqAccess<'de>,
1127    {
1128        let inner = one_level_in(self.depth)?;
1129        let out = self.out;
1130        out.push(b'[');
1131        let mut first = true;
1132        loop {
1133            let element = RenderElement { out: &mut *out, depth: inner, first };
1134            if access.next_element_seed(element)?.is_none() {
1135                break;
1136            }
1137            first = false;
1138        }
1139        out.push(b']');
1140        Ok(())
1141    }
1142
1143    fn visit_map<A>(self, mut access: A) -> Result<Self::Value, A::Error>
1144    where
1145        A: de::MapAccess<'de>,
1146    {
1147        let inner = one_level_in(self.depth)?;
1148        let out = self.out;
1149        out.push(b'{');
1150        let mut first = true;
1151        loop {
1152            let key = RenderKey { out: &mut *out, first };
1153            if access.next_key_seed(key)?.is_none() {
1154                break;
1155            }
1156            out.push(b':');
1157            access.next_value_seed(Render { out: &mut *out, depth: inner })?;
1158            first = false;
1159        }
1160        out.push(b'}');
1161        Ok(())
1162    }
1163}
1164
1165/// One element of an array, with the comma that precedes it.
1166///
1167/// The separator is written here rather than in the loop because whether there
1168/// is another element is only known once the deserializer has been asked for
1169/// it, and asking is what renders it.
1170struct RenderElement<'b> {
1171    out: &'b mut Vec<u8>,
1172    depth: usize,
1173    first: bool,
1174}
1175
1176impl<'de> de::DeserializeSeed<'de> for RenderElement<'_> {
1177    type Value = ();
1178
1179    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
1180    where
1181        D: Deserializer<'de>,
1182    {
1183        if !self.first {
1184            self.out.push(b',');
1185        }
1186        deserializer.deserialize_any(Render { out: self.out, depth: self.depth })
1187    }
1188}
1189
1190/// One key of an object, with the comma that precedes it. A JSON key is always
1191/// a string, so anything else is a type error rather than a rendered value.
1192struct RenderKey<'b> {
1193    out: &'b mut Vec<u8>,
1194    first: bool,
1195}
1196
1197impl<'de> de::DeserializeSeed<'de> for RenderKey<'_> {
1198    type Value = ();
1199
1200    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
1201    where
1202        D: Deserializer<'de>,
1203    {
1204        if !self.first {
1205            self.out.push(b',');
1206        }
1207        deserializer.deserialize_str(self)
1208    }
1209}
1210
1211impl<'de> de::Visitor<'de> for RenderKey<'_> {
1212    type Value = ();
1213
1214    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1215        formatter.write_str("a JSON object key")
1216    }
1217
1218    fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
1219        write_json_string(self.out, value);
1220        Ok(())
1221    }
1222}
1223
1224/// An owned piece of JSON text that travels through the SDK unchanged.
1225///
1226/// It holds whatever value it was built from - an object, an array or a
1227/// scalar - as the text the wire carried, so a response field of a shape this
1228/// version does not know survives a decode and can be read later with
1229/// [`decode`](RawJson::decode). Two values are equal when their text
1230/// is equal, which means equality is textual: `{"a":1}` and `{ "a": 1 }` are
1231/// different values.
1232///
1233/// # Invariant
1234///
1235/// The text is always exactly one complete JSON value whose structure is
1236/// valid. Nothing builds a `RawJson` without the codec having established
1237/// that, because the text is written into a request body unread: a second
1238/// value in it would become a field of the enclosing object. Escapes inside
1239/// strings are passed through unchecked: a `\u` escape with bad hex digits,
1240/// or a lone surrogate half, is kept as it was written, and a strict server
1241/// refuses the request that carries it. String boundaries are found the same
1242/// way either way, so such an escape cannot end a string early.
1243///
1244/// # Serialization
1245///
1246/// Inside the SDK the text is spliced into the request body byte for byte:
1247/// key order, spacing and the exact spelling of every number are what the
1248/// caller or the server wrote. Through any other serializer - `serde_json`,
1249/// for instance - the value is written out as ordinary JSON data instead, so
1250/// the data survives while its spelling may not: numbers are re-rendered by
1251/// that serializer and insignificant whitespace is dropped.
1252///
1253/// Which of the two happens is decided by whether the SDK's own encoder is
1254/// running on this thread, not by the type of the serializer, because serde
1255/// offers no way to ask a serializer what it is. A `RawJson` handed to a
1256/// foreign serializer from inside a caller's own `Serialize` implementation
1257/// while the SDK is encoding a request is therefore spliced rather than
1258/// transcoded; use [`as_str`](RawJson::as_str) there.
1259#[derive(Clone, PartialEq, Eq, Hash)]
1260pub struct RawJson {
1261    text: Box<str>,
1262}
1263
1264impl RawJson {
1265    /// Encodes `value` and keeps the resulting JSON text.
1266    ///
1267    /// # Errors
1268    ///
1269    /// Returns [`EncodeError`] when the value cannot be represented as JSON.
1270    pub fn from_value<T>(value: &T) -> Result<Self, EncodeError>
1271    where
1272        T: Serialize + ?Sized,
1273    {
1274        let mut buffer = Vec::new();
1275        encode_into(&mut buffer, value)?;
1276        Ok(Self::from_text(String::from_utf8(buffer).expect("invariant: the codec emits UTF-8")))
1277    }
1278
1279    /// The JSON text, exactly as it was received or encoded.
1280    #[must_use]
1281    pub fn as_str(&self) -> &str {
1282        &self.text
1283    }
1284
1285    /// Decodes the held text into `T`.
1286    ///
1287    /// It is `decode` rather than `deserialize` so that it does not shadow
1288    /// [`Deserialize::deserialize`], which a caller reaches for when they read
1289    /// a `RawJson` out of a document with a codec of their own.
1290    ///
1291    /// # Errors
1292    ///
1293    /// Returns [`DecodeError`] when the text does not have the shape `T`
1294    /// expects, or when it is nested deeper than the decoder allows - which a
1295    /// value built by [`from_value`](RawJson::from_value) can be, since
1296    /// encoding is not depth limited.
1297    pub fn decode<'de, T>(&'de self) -> Result<T, DecodeError>
1298    where
1299        T: Deserialize<'de>,
1300    {
1301        decode(self.text.as_bytes())
1302    }
1303
1304    /// Wraps text the codec has already established to be one JSON value:
1305    /// what [`encode_into`] wrote, or what [`deserialize_raw`] captured and
1306    /// checked.
1307    pub(crate) fn from_text(text: String) -> Self {
1308        Self { text: text.into_boxed_str() }
1309    }
1310}
1311
1312impl fmt::Debug for RawJson {
1313    /// Prints the JSON text itself, with control characters and the format
1314    /// characters that reorder or hide text written as Rust escapes: JSON
1315    /// allows those raw inside a string, the text usually came from a server,
1316    /// and a `{:?}` usually ends up in a log line. Backslashes are kept as
1317    /// they are, since they are the JSON's own escapes. `Display`,
1318    /// [`as_str`](RawJson::as_str) and serialization give the text byte for
1319    /// byte. The default derive would wrap the text in a struct with one
1320    /// field and quote it a second time.
1321    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1322        let mut shown = SafeText::new(usize::MAX, Backslash::Keep);
1323        shown.untrusted(&self.text, usize::MAX);
1324        formatter.write_str(&shown.into_string())
1325    }
1326}
1327
1328impl fmt::Display for RawJson {
1329    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1330        formatter.write_str(&self.text)
1331    }
1332}
1333
1334impl Serialize for RawJson {
1335    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1336    where
1337        S: Serializer,
1338    {
1339        serialize_raw(&self.text, serializer)
1340    }
1341}
1342
1343impl<'de> Deserialize<'de> for RawJson {
1344    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1345    where
1346        D: Deserializer<'de>,
1347    {
1348        deserialize_raw(deserializer).map(|raw| Self::from_text(raw.into_owned()))
1349    }
1350}
1351
1352#[cfg(test)]
1353#[path = "codec_tests.rs"]
1354mod tests;