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/// # Type Parameters
33///
34/// * `'a` - Lifetime of the runtime payload borrowed for serialization.
35///
36/// # Examples
37///
38/// ```
39/// use qubit_value::{Value, ValueWireRefV1};
40///
41/// let value = Value::from(42_i32);
42/// let _wire = ValueWireRefV1::from_value(&value).unwrap();
43/// ```
44#[must_use]
45pub struct ValueWireRefV1<'a> {
46 /// Borrowed V1 payload carried by this versioned envelope.
47 value: ValueWirePayloadRefV1<'a>,
48}
49
50impl<'a> ValueWireRefV1<'a> {
51 /// Borrows a scalar after validating V1's finite-float invariant.
52 ///
53 /// # Parameters
54 ///
55 /// * `value` - Scalar runtime value to validate and borrow.
56 ///
57 /// # Returns
58 ///
59 /// A standalone borrowed V1 envelope containing the scalar.
60 ///
61 /// # Errors
62 ///
63 /// Returns [`ValueWireEncodeError`] when the scalar violates V1 numeric
64 /// representation constraints.
65 #[inline(always)]
66 pub fn from_value(value: &'a Value) -> Result<Self, ValueWireEncodeError> {
67 ValueWirePayloadRefV1::from_value(value).map(Self::new)
68 }
69 /// Borrows a collection after validating V1's finite-float invariant.
70 ///
71 /// # Parameters
72 ///
73 /// * `values` - Homogeneous runtime collection to validate and borrow.
74 ///
75 /// # Returns
76 ///
77 /// A standalone borrowed V1 envelope containing the collection.
78 ///
79 /// # Errors
80 ///
81 /// Returns [`ValueWireEncodeError`] when an element violates V1 numeric
82 /// representation constraints.
83 #[inline(always)]
84 pub fn from_values(values: &'a MultiValues) -> Result<Self, ValueWireEncodeError> {
85 ValueWirePayloadRefV1::from_values(values).map(Self::new)
86 }
87 /// Borrows an explicit shape after validating V1's finite-float invariant.
88 ///
89 /// # Parameters
90 ///
91 /// * `value` - Explicit scalar-or-collection value to validate and borrow.
92 ///
93 /// # Returns
94 ///
95 /// A standalone borrowed V1 envelope preserving the original shape.
96 ///
97 /// # Errors
98 ///
99 /// Returns [`ValueWireEncodeError`] when any contained value violates V1
100 /// numeric representation constraints.
101 #[inline(always)]
102 pub fn from_container(value: &'a ValueContainer) -> Result<Self, ValueWireEncodeError> {
103 ValueWirePayloadRefV1::from_container(value).map(Self::new)
104 }
105 /// Wraps an already validated borrowed payload.
106 ///
107 /// # Parameters
108 ///
109 /// * `value` - Validated borrowed payload to place in the V1 envelope.
110 ///
111 /// # Returns
112 ///
113 /// A standalone borrowed V1 envelope.
114 #[inline(always)]
115 pub const fn new(value: ValueWirePayloadRefV1<'a>) -> Self {
116 Self { value }
117 }
118
119 /// Encodes the borrowed V1 envelope into a compact JSON vector.
120 ///
121 /// # Returns
122 ///
123 /// Compact UTF-8 JSON bytes for the complete V1 envelope.
124 ///
125 /// # Errors
126 ///
127 /// Returns [`ValueWireEncodeError`] for resource or serialization failures.
128 #[cfg(feature = "json")]
129 #[inline(always)]
130 pub fn to_json_vec(&self) -> Result<Vec<u8>, ValueWireEncodeError> {
131 self.to_json_vec_with_limits(super::default_json_encode_limits())
132 }
133
134 /// Encodes the borrowed V1 envelope with explicit JSON resource limits.
135 ///
136 /// # Parameters
137 ///
138 /// * `limits` - Resource limits enforced during JSON encoding.
139 ///
140 /// # Returns
141 ///
142 /// Compact UTF-8 JSON bytes for the complete V1 envelope.
143 ///
144 /// # Errors
145 ///
146 /// Returns [`ValueWireEncodeError`] when encoding exceeds `limits` or
147 /// Serde rejects the envelope.
148 #[cfg(feature = "json")]
149 #[inline]
150 pub fn to_json_vec_with_limits(&self, limits: JsonEncodeLimits) -> Result<Vec<u8>, ValueWireEncodeError> {
151 let session = JsonEncodeSession::from_limits(limits);
152 JsonEncoder::new(session)
153 .to_vec(self)
154 .map_err(ValueWireEncodeError::from)
155 }
156
157 /// Encodes the borrowed V1 envelope to a writer with default limits.
158 ///
159 /// # Type Parameters
160 ///
161 /// * `W` - Destination writer type.
162 ///
163 /// # Parameters
164 ///
165 /// * `writer` - Destination receiving the complete V1 JSON envelope.
166 ///
167 /// # Returns
168 ///
169 /// `Ok(())` after the complete envelope is written.
170 ///
171 /// # Errors
172 ///
173 /// Returns [`ValueWireEncodeError`] for resource, serialization, or writer
174 /// failures.
175 #[cfg(feature = "json")]
176 #[inline(always)]
177 pub fn to_json_writer<W>(&self, writer: W) -> Result<(), ValueWireEncodeError>
178 where
179 W: Write,
180 {
181 self.to_json_writer_with_limits(writer, super::default_json_encode_limits())
182 }
183
184 /// Encodes the borrowed V1 envelope to a writer with explicit limits.
185 ///
186 /// # Type Parameters
187 ///
188 /// * `W` - Destination writer type.
189 ///
190 /// # Parameters
191 ///
192 /// * `writer` - Destination receiving the complete V1 JSON envelope.
193 /// * `limits` - Resource limits enforced during JSON encoding.
194 ///
195 /// # Returns
196 ///
197 /// `Ok(())` after the complete envelope is written.
198 ///
199 /// # Errors
200 ///
201 /// Returns [`ValueWireEncodeError`] when encoding exceeds `limits`, Serde
202 /// rejects the envelope, or `writer` rejects output.
203 #[cfg(feature = "json")]
204 #[inline]
205 pub fn to_json_writer_with_limits<W>(&self, writer: W, limits: JsonEncodeLimits) -> Result<(), ValueWireEncodeError>
206 where
207 W: Write,
208 {
209 let session = JsonEncodeSession::from_limits(limits);
210 JsonEncoder::new(session)
211 .write_buffered(writer, self)
212 .map_err(ValueWireEncodeError::from)
213 }
214}
215
216impl<'a> TryFrom<&'a Value> for ValueWireRefV1<'a> {
217 type Error = ValueWireEncodeError;
218 /// Borrows and validates a scalar.
219 fn try_from(value: &'a Value) -> Result<Self, Self::Error> {
220 Self::from_value(value)
221 }
222}
223
224impl<'a> TryFrom<&'a MultiValues> for ValueWireRefV1<'a> {
225 type Error = ValueWireEncodeError;
226 /// Borrows and validates a collection.
227 fn try_from(values: &'a MultiValues) -> Result<Self, Self::Error> {
228 Self::from_values(values)
229 }
230}
231
232impl<'a> TryFrom<&'a ValueContainer> for ValueWireRefV1<'a> {
233 type Error = ValueWireEncodeError;
234 /// Borrows and validates an explicit shape.
235 fn try_from(value: &'a ValueContainer) -> Result<Self, Self::Error> {
236 Self::from_container(value)
237 }
238}
239
240impl Serialize for ValueWireRefV1<'_> {
241 /// Serializes the borrowed runtime shape through the V1 envelope.
242 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
243 where
244 S: Serializer,
245 {
246 serialize_wire(self.value.shape(), serializer)
247 }
248}