qubit_value/value_wire/value_wire_ref_v1.rs
1// =============================================================================
2// Copyright (c) 2025 - 2026 Haixing Hu.
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Licensed under the Apache License, Version 2.0.
7// =============================================================================
8
9//! Borrowed V1 envelope serialization.
10
11#[cfg(feature = "json")]
12use std::io::Write;
13
14#[cfg(feature = "json")]
15use qubit_budget::json::JsonEncodeLimits;
16#[cfg(feature = "json")]
17use qubit_budget::json::JsonEncodeSession;
18#[cfg(feature = "json")]
19use qubit_json::encode::JsonEncoder;
20use serde::Serialize;
21use serde::Serializer;
22
23use super::ValueWireEncodeError;
24use super::ValueWirePayloadRefV1;
25use super::serialize_wire;
26use crate::MultiValues;
27use crate::Value;
28use crate::ValueContainer;
29
30/// Borrowed standalone V1 envelope for serialization without cloning.
31///
32/// Runtime JSON numbers must round trip to the same `serde_json::Number` under
33/// the strict `qubit-json` number model. A number that would change identity
34/// returns the JSON-gated `JsonNumberNotRoundTrippable` error; the error does
35/// not expose the number text.
36///
37/// # Type Parameters
38///
39/// * `'a` - Lifetime of the runtime payload borrowed for serialization.
40///
41/// # Examples
42///
43/// ```
44/// use qubit_value::{Value, ValueWireRefV1};
45///
46/// let value = Value::from(42_i32);
47/// let wire = ValueWireRefV1::from_value(&value).unwrap();
48/// let encoded = serde_json::to_string(&wire).unwrap();
49/// assert_eq!(encoded, r#"{"version":1,"value":{"scalar":{"int32":42}}}"#);
50/// let owned = qubit_value::ValueWireV1::try_from(Value::from(42_i32)).unwrap();
51/// assert_eq!(encoded, serde_json::to_string(&owned).unwrap());
52/// ```
53#[must_use]
54pub struct ValueWireRefV1<'a> {
55 /// Borrowed V1 payload carried by this versioned envelope.
56 value: ValueWirePayloadRefV1<'a>,
57}
58
59impl<'a> ValueWireRefV1<'a> {
60 /// Borrows a scalar after validating V1's representational constraints.
61 ///
62 /// # Parameters
63 ///
64 /// * `value` - Scalar runtime value to validate and borrow.
65 ///
66 /// # Returns
67 ///
68 /// A standalone borrowed V1 envelope containing the scalar.
69 ///
70 /// # Errors
71 ///
72 /// Returns [`ValueWireEncodeError`] when the scalar violates V1 numeric
73 /// representation constraints, including the supported UTC year range
74 /// for instants.
75 #[inline(always)]
76 pub fn from_value(value: &'a Value) -> Result<Self, ValueWireEncodeError> {
77 ValueWirePayloadRefV1::from_value(value).map(Self::new)
78 }
79 /// Borrows a collection after validating V1's representational constraints.
80 ///
81 /// # Parameters
82 ///
83 /// * `values` - Homogeneous runtime collection to validate and borrow.
84 ///
85 /// # Returns
86 ///
87 /// A standalone borrowed V1 envelope containing the collection.
88 ///
89 /// # Errors
90 ///
91 /// Returns [`ValueWireEncodeError`] when an element violates V1 numeric
92 /// representation constraints, including the supported UTC year range
93 /// for instants.
94 #[inline(always)]
95 pub fn from_values(values: &'a MultiValues) -> Result<Self, ValueWireEncodeError> {
96 ValueWirePayloadRefV1::from_values(values).map(Self::new)
97 }
98 /// Borrows an explicit shape after validating V1's representational
99 /// constraints.
100 ///
101 /// # Parameters
102 ///
103 /// * `value` - Explicit scalar-or-collection value to validate and borrow.
104 ///
105 /// # Returns
106 ///
107 /// A standalone borrowed V1 envelope preserving the original shape.
108 ///
109 /// # Errors
110 ///
111 /// Returns [`ValueWireEncodeError`] when any contained value violates V1
112 /// numeric representation constraints, including the supported UTC year
113 /// range for instants.
114 #[inline(always)]
115 pub fn from_container(value: &'a ValueContainer) -> Result<Self, ValueWireEncodeError> {
116 ValueWirePayloadRefV1::from_container(value).map(Self::new)
117 }
118 /// Wraps an already validated borrowed payload.
119 ///
120 /// # Parameters
121 ///
122 /// * `value` - Validated borrowed payload to place in the V1 envelope.
123 ///
124 /// # Returns
125 ///
126 /// A standalone borrowed V1 envelope.
127 #[inline(always)]
128 pub const fn new(value: ValueWirePayloadRefV1<'a>) -> Self {
129 Self { value }
130 }
131
132 /// Encodes the borrowed V1 envelope into a compact JSON vector.
133 ///
134 /// # Returns
135 ///
136 /// Compact UTF-8 JSON bytes for the complete V1 envelope.
137 ///
138 /// # Errors
139 ///
140 /// Returns [`ValueWireEncodeError`] for resource or serialization failures.
141 #[cfg(feature = "json")]
142 #[inline(always)]
143 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
144 pub fn to_json_vec(&self) -> Result<Vec<u8>, ValueWireEncodeError> {
145 self.to_json_vec_with_limits(super::default_json_encode_limits())
146 }
147
148 /// Encodes the borrowed V1 envelope with explicit JSON resource limits.
149 ///
150 /// # Parameters
151 ///
152 /// * `limits` - Resource limits enforced during JSON encoding.
153 ///
154 /// # Returns
155 ///
156 /// Compact UTF-8 JSON bytes for the complete V1 envelope.
157 ///
158 /// Runs a conservative payload preflight before encoding, then enforces
159 /// `limits` authoritatively while encoding the full envelope. The preflight
160 /// may report a lower-bound budget error and does not bound every
161 /// preparation allocation.
162 ///
163 /// # Errors
164 ///
165 /// Returns [`ValueWireEncodeError`] when preflight or final encoding
166 /// exceeds `limits`, or Serde rejects the envelope.
167 #[cfg(feature = "json")]
168 #[inline]
169 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
170 pub fn to_json_vec_with_limits(
171 &self,
172 limits: JsonEncodeLimits,
173 ) -> Result<Vec<u8>, ValueWireEncodeError> {
174 self.value.check_encode_preflight(limits)?;
175 let session = JsonEncodeSession::from_limits(limits);
176 JsonEncoder::new(session)
177 .to_vec(self)
178 .map_err(ValueWireEncodeError::from)
179 }
180
181 /// Encodes the borrowed V1 envelope to a writer with default limits.
182 ///
183 /// # Type Parameters
184 ///
185 /// * `W` - Destination writer type.
186 ///
187 /// # Parameters
188 ///
189 /// * `writer` - Destination receiving the complete V1 JSON envelope.
190 ///
191 /// # Returns
192 ///
193 /// `Ok(())` after the complete envelope is written.
194 ///
195 /// The complete document is buffered and admitted before this method writes
196 /// its bytes to the destination. Preflight, serialization, or budget
197 /// rejection does not write this document. An I/O error may leave an
198 /// accepted prefix in the writer; do not blindly retry a complete
199 /// document on the same destination.
200 ///
201 /// This method does not explicitly flush the writer. Success means the
202 /// writer accepted all document bytes, not that they were flushed,
203 /// persisted, or received by a remote peer. Pass `&mut writer` to
204 /// retain ownership of a buffered writer, then call `flush()` and
205 /// handle its error separately. Passing an owned writer may invoke that
206 /// writer's drop behavior; errors from an implicit drop-time flush are
207 /// not returned by this method.
208 ///
209 /// # Errors
210 ///
211 /// Returns [`ValueWireEncodeError`] for resource, serialization, or writer
212 /// failures.
213 #[cfg(feature = "json")]
214 #[inline(always)]
215 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
216 pub fn to_json_writer<W>(&self, writer: W) -> Result<(), ValueWireEncodeError>
217 where
218 W: Write,
219 {
220 self.to_json_writer_with_limits(writer, super::default_json_encode_limits())
221 }
222
223 /// Encodes the borrowed V1 envelope to a writer with explicit limits.
224 ///
225 /// # Type Parameters
226 ///
227 /// * `W` - Destination writer type.
228 ///
229 /// # Parameters
230 ///
231 /// * `writer` - Destination receiving the complete V1 JSON envelope.
232 /// * `limits` - Resource limits enforced during JSON encoding.
233 ///
234 /// # Returns
235 ///
236 /// `Ok(())` after the complete envelope is written.
237 ///
238 /// Runs a conservative payload preflight before encoding, then enforces
239 /// `limits` authoritatively while encoding the full envelope. The preflight
240 /// may report a lower-bound budget error and does not bound every
241 /// preparation allocation.
242 ///
243 /// The complete document is buffered and admitted before this method writes
244 /// its bytes to the destination. Preflight, serialization, or budget
245 /// rejection does not write this document. An I/O error may leave an
246 /// accepted prefix in the writer; do not blindly retry a complete
247 /// document on the same destination.
248 ///
249 /// This method does not explicitly flush the writer. Success means the
250 /// writer accepted all document bytes, not that they were flushed,
251 /// persisted, or received by a remote peer. Pass `&mut writer` to
252 /// retain ownership of a buffered writer, then call `flush()` and
253 /// handle its error separately. Passing an owned writer may invoke that
254 /// writer's drop behavior; errors from an implicit drop-time flush are
255 /// not returned by this method.
256 ///
257 /// # Errors
258 ///
259 /// Returns [`ValueWireEncodeError`] when preflight or final encoding
260 /// exceeds `limits`, Serde rejects the envelope, or `writer` rejects
261 /// output.
262 #[cfg(feature = "json")]
263 #[inline]
264 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
265 pub fn to_json_writer_with_limits<W>(
266 &self,
267 mut writer: W,
268 limits: JsonEncodeLimits,
269 ) -> Result<(), ValueWireEncodeError>
270 where
271 W: Write,
272 {
273 self.value.check_encode_preflight(limits)?;
274 let session = JsonEncodeSession::from_limits(limits);
275 JsonEncoder::new(session)
276 .write_buffered(&mut writer, self)
277 .map_err(ValueWireEncodeError::from)
278 }
279}
280
281impl<'a> TryFrom<&'a Value> for ValueWireRefV1<'a> {
282 /// Validation failure when the borrowed input cannot be represented in V1.
283 type Error = ValueWireEncodeError;
284
285 /// Validates and borrows the input without cloning its payload.
286 ///
287 /// # Parameters
288 ///
289 /// * `value` - Scalar runtime value to validate and borrow for `'a`.
290 ///
291 /// # Returns
292 ///
293 /// A borrowed V1 envelope preserving the input shape.
294 ///
295 /// # Errors
296 ///
297 /// Returns the same representational validation errors as
298 /// [`Self::from_value`].
299 #[inline]
300 fn try_from(value: &'a Value) -> Result<Self, Self::Error> {
301 Self::from_value(value)
302 }
303}
304
305impl<'a> TryFrom<&'a MultiValues> for ValueWireRefV1<'a> {
306 /// Validation failure when the borrowed input cannot be represented in V1.
307 type Error = ValueWireEncodeError;
308
309 /// Validates and borrows the input without cloning its payload.
310 ///
311 /// # Parameters
312 ///
313 /// * `values` - Homogeneous runtime collection to validate and borrow for
314 /// `'a`.
315 ///
316 /// # Returns
317 ///
318 /// A borrowed V1 envelope preserving the input shape.
319 ///
320 /// # Errors
321 ///
322 /// Returns the same representational validation errors as
323 /// [`Self::from_values`].
324 #[inline]
325 fn try_from(values: &'a MultiValues) -> Result<Self, Self::Error> {
326 Self::from_values(values)
327 }
328}
329
330impl<'a> TryFrom<&'a ValueContainer> for ValueWireRefV1<'a> {
331 /// Validation failure when the borrowed input cannot be represented in V1.
332 type Error = ValueWireEncodeError;
333
334 /// Validates and borrows the input without cloning its payload.
335 ///
336 /// # Parameters
337 ///
338 /// * `value` - Explicit scalar-or-collection value to validate and borrow
339 /// for `'a`.
340 ///
341 /// # Returns
342 ///
343 /// A borrowed V1 envelope preserving the input shape.
344 ///
345 /// # Errors
346 ///
347 /// Returns the same representational validation errors as
348 /// [`Self::from_container`].
349 #[inline]
350 fn try_from(value: &'a ValueContainer) -> Result<Self, Self::Error> {
351 Self::from_container(value)
352 }
353}
354
355impl Serialize for ValueWireRefV1<'_> {
356 /// Serializes the borrowed runtime shape through the V1 envelope.
357 ///
358 /// # Type Parameters
359 ///
360 /// * `S` - Serde serializer defining the output format and error type.
361 ///
362 /// # Parameters
363 ///
364 /// * `serializer` - Consumed serializer receiving the version and payload.
365 ///
366 /// # Returns
367 ///
368 /// The serializer's success value after encoding the complete V1 envelope.
369 ///
370 /// # Errors
371 ///
372 /// Returns the serializer's error if encoding the envelope or payload
373 /// fails.
374 #[inline]
375 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
376 where
377 S: Serializer,
378 {
379 serialize_wire(self.value.shape(), serializer)
380 }
381}