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