pub trait JsonWrite {
type Error;
Show 15 methods
// Required methods
fn write_byte(&mut self, b: u8) -> Result<(), Self::Error>;
fn write_str_raw(&mut self, s: &str) -> Result<(), Self::Error>;
fn write_float_f64(&mut self, f: f64) -> Result<(), Self::Error>;
// Provided methods
fn reserve_hint(&mut self, _additional: usize) { ... }
unsafe fn write_byte_unchecked(&mut self, b: u8) -> Result<(), Self::Error> { ... }
fn write_escaped_str(&mut self, s: &str) -> Result<(), Self::Error> { ... }
fn write_raw_bytes(&mut self, b: &[u8]) -> Result<(), Self::Error> { ... }
fn write_int_i64(&mut self, n: i64) -> Result<(), Self::Error> { ... }
fn write_int_u64(&mut self, n: u64) -> Result<(), Self::Error> { ... }
fn write_int_i128(&mut self, n: i128) -> Result<(), Self::Error> { ... }
fn write_int_u128(&mut self, n: u128) -> Result<(), Self::Error> { ... }
unsafe fn write_float_f64_unchecked(
&mut self,
f: f64,
) -> Result<(), Self::Error> { ... }
unsafe fn write_float_f64_unchecked_finite(
&mut self,
f: f64,
) -> Result<(), Self::Error> { ... }
unsafe fn write_float_f64_taint(
&mut self,
f: f64,
) -> Result<(), Self::Error> { ... }
fn take_nonfinite_taint(&mut self) -> u64 { ... }
}Expand description
Output sink for ToJson impls.
Implementors expose per-primitive writers so the trait impls below can
avoid the core::fmt machinery. The default integer/float methods
land on write_str_raw after formatting into a small stack buffer, but
implementations that can write directly (e.g. StringSink’s integer
LUT) override them.
Required Associated Types§
Sourcetype Error
type Error
Sink-specific error type. StringSink uses core::convert::Infallible
for the byte/string writes; the typed-level to_string entry point
widens to crate::Error so non-finite floats can surface.
Required Methods§
Sourcefn write_byte(&mut self, b: u8) -> Result<(), Self::Error>
fn write_byte(&mut self, b: u8) -> Result<(), Self::Error>
Append a single ASCII byte. Used for structural punctuation
({, }, [, ], ,, :, ").
Sourcefn write_str_raw(&mut self, s: &str) -> Result<(), Self::Error>
fn write_str_raw(&mut self, s: &str) -> Result<(), Self::Error>
Append a &str verbatim. Caller is responsible for any escaping
— this is the structural / pre-escaped path. For user string
payloads, call Self::write_escaped_str instead.
Sourcefn write_float_f64(&mut self, f: f64) -> Result<(), Self::Error>
fn write_float_f64(&mut self, f: f64) -> Result<(), Self::Error>
Write a finite f64 as a JSON number. Non-finite inputs (inf,
-inf, NaN) have no JSON representation; sinks reject them
via their Self::Error type.
The default routes through core::fmt::Write after stack-buffer
formatting via format! — this is the “good enough” path that
works for any sink. Sinks that want shortest-round-trip output
without fmt overhead override with a direct ryu call.
Provided Methods§
Sourcefn reserve_hint(&mut self, _additional: usize)
fn reserve_hint(&mut self, _additional: usize)
Hint that at least additional more bytes will be written. Sinks
backed by a growable buffer (like ByteSink) can amortize
capacity growth across a known-size sequence; sinks without a
reservation concept treat this as a no-op.
Hot path: the array writer in this module calls this once at the
start of a slice/Vec serialization so per-element reserve calls
become predictable no-ops.
Sourceunsafe fn write_byte_unchecked(&mut self, b: u8) -> Result<(), Self::Error>
unsafe fn write_byte_unchecked(&mut self, b: u8) -> Result<(), Self::Error>
Append a single ASCII byte WITHOUT a per-write capacity check.
§Safety
The caller MUST have previously called Self::reserve_hint with
at least enough bytes to cover this write plus all subsequent
writes up to the next reserve_hint (or the end of writing).
Sinks that don’t track a tail capacity (e.g. fmt::Write-backed)
fall back to the safe write_byte.
Why this exists: under random f64 inputs the per-element
capacity-check branch in Vec::push at the comma site mispredicts
at ~13% in perf record -e branch-misses — the single largest
mispredict source in the array hot loop. Hoisting the check via
reserve_hint and emitting the byte unchecked removes that
branch entirely from the inner loop.
Default impl forwards to write_byte (safe but checked) so
non-ByteSink sinks aren’t required to opt in.
§Safety contract example (matches what write_array does)
w.reserve_hint(n * MAX + brackets_and_commas);
for _ in 0..count {
// SAFETY: reserve_hint covered all of these.
unsafe { w.write_byte_unchecked(b','); }
w.write_int_u64(...); // also covered by reserve_hint
}Sourcefn write_escaped_str(&mut self, s: &str) -> Result<(), Self::Error>
fn write_escaped_str(&mut self, s: &str) -> Result<(), Self::Error>
Append a JSON-quoted, escaped string (including the surrounding
" characters). The default impl escapes one byte at a time
through write_byte; sinks with bulk-write capability (like
StringSink) override with a literal-run fast path.
Sourcefn write_raw_bytes(&mut self, b: &[u8]) -> Result<(), Self::Error>
fn write_raw_bytes(&mut self, b: &[u8]) -> Result<(), Self::Error>
Append a byte slice whose contents are known-valid UTF-8.
Used by macro-generated code to fuse adjacent structural literals
(e.g. b"{\"id\":") into a single write. The default routes
through Self::write_str_raw; byte-oriented sinks like
ByteSink override to avoid the &str conversion.
Sourcefn write_int_i64(&mut self, n: i64) -> Result<(), Self::Error>
fn write_int_i64(&mut self, n: i64) -> Result<(), Self::Error>
Write a signed 64-bit integer as a JSON number.
Sourcefn write_int_u64(&mut self, n: u64) -> Result<(), Self::Error>
fn write_int_u64(&mut self, n: u64) -> Result<(), Self::Error>
Write an unsigned 64-bit integer as a JSON number.
Sourcefn write_int_i128(&mut self, n: i128) -> Result<(), Self::Error>
fn write_int_i128(&mut self, n: i128) -> Result<(), Self::Error>
Write a signed 128-bit integer as a JSON number.
Sourcefn write_int_u128(&mut self, n: u128) -> Result<(), Self::Error>
fn write_int_u128(&mut self, n: u128) -> Result<(), Self::Error>
Write an unsigned 128-bit integer as a JSON number.
Sourceunsafe fn write_float_f64_unchecked(
&mut self,
f: f64,
) -> Result<(), Self::Error>
unsafe fn write_float_f64_unchecked( &mut self, f: f64, ) -> Result<(), Self::Error>
Write a finite f64 ASSUMING the caller has reserved at least
f64::MAX_SERIALIZED_LEN (32) bytes of sink capacity. Skips the
per-call cap check in Vec::extend_from_slice — the second-largest
mispredict source after the comma Vec::push.
Default impl forwards to write_float_f64. ByteSink overrides
with a raw-pointer write directly into the Vec’s reserved tail.
§Safety
f64::MAX_SERIALIZED_LEN (32) bytes of sink capacity must be
guaranteed available before this call. Used by [f64]:: write_json_in_reserved after [T]::write_json’s reserve_hint.
Sourceunsafe fn write_float_f64_unchecked_finite(
&mut self,
f: f64,
) -> Result<(), Self::Error>
unsafe fn write_float_f64_unchecked_finite( &mut self, f: f64, ) -> Result<(), Self::Error>
Like write_float_f64_unchecked, but additionally requires the
caller to have validated that f is finite. The per-element
finiteness branch in the bench’s hot loop was the dominant
remaining mispredict source after the cap-check elimination;
hoisting validation to a one-shot pre-scan over the whole slice
removes that branch from the inner loop entirely.
Default impl forwards to write_float_f64_unchecked. ByteSink
overrides with the finite-known float path.
§Safety
All preconditions of write_float_f64_unchecked, plus f
must be finite. Used after a successful [f64]::pre_validate_slice.
Sourceunsafe fn write_float_f64_taint(&mut self, f: f64) -> Result<(), Self::Error>
unsafe fn write_float_f64_taint(&mut self, f: f64) -> Result<(), Self::Error>
Per-element float write that branchlessly tolerates non-finite
input. Tainted bytes (junk ASCII for non-finite values) land in
the sink; the caller is expected to query the sink’s
take_nonfinite_taint() once at the end of the slice and turn a
non-zero result into a typed error.
This avoids both the per-element finiteness branch AND the
pre-scan pass that hoisted it out of the loop in the previous
design (the SIMD-vectorised pand/pcmpeqd scan was costing ~20%
of total cycles per perf record -c cycles).
Default impl forwards to write_float_f64_unchecked and emits a
dummy taint of 0 — sinks without taint tracking should never be
driven through this path.
§Safety
MAX_SERIALIZED_LEN (32) bytes of sink capacity must be available.
Sourcefn take_nonfinite_taint(&mut self) -> u64
fn take_nonfinite_taint(&mut self) -> u64
Read and clear the accumulated non-finite taint from the sink.
Returns 0 for sinks without taint tracking. The array writer
queries this once after a batch of write_float_f64_taint
calls; a non-zero result means at least one input was inf/NaN
and the call must return Err(NonFiniteFloat).
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".
Implementors§
Source§impl JsonWrite for PrettyStringSink<'_>
Available on crate feature alloc only.
impl JsonWrite for PrettyStringSink<'_>
alloc only.Source§impl JsonWrite for StringSink<'_>
Available on crate feature alloc only.
impl JsonWrite for StringSink<'_>
alloc only.