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;