/rust/registry/src/index.crates.io-1949cf8c6b5b557f/prost-0.14.3/src/encoding.rs
Line | Count | Source |
1 | | //! Utility functions and types for encoding and decoding Protobuf types. |
2 | | //! |
3 | | //! This module contains the encoding and decoding primitives for Protobuf as described in |
4 | | //! <https://protobuf.dev/programming-guides/encoding/>. |
5 | | //! |
6 | | //! This module is `pub`, but is only for prost internal use. The `prost-derive` crate needs access for its `Message` implementations. |
7 | | |
8 | | use alloc::collections::BTreeMap; |
9 | | use alloc::string::String; |
10 | | use alloc::vec::Vec; |
11 | | use core::mem; |
12 | | use core::str; |
13 | | |
14 | | use ::bytes::{Buf, BufMut, Bytes}; |
15 | | |
16 | | use crate::error::DecodeErrorKind; |
17 | | use crate::DecodeError; |
18 | | use crate::Message; |
19 | | |
20 | | pub mod varint; |
21 | | pub use varint::{decode_varint, encode_varint, encoded_len_varint}; |
22 | | |
23 | | pub mod length_delimiter; |
24 | | pub use length_delimiter::{ |
25 | | decode_length_delimiter, encode_length_delimiter, length_delimiter_len, |
26 | | }; |
27 | | |
28 | | pub mod wire_type; |
29 | | pub use wire_type::{check_wire_type, WireType}; |
30 | | |
31 | | /// Additional information passed to every decode/merge function. |
32 | | /// |
33 | | /// The context should be passed by value and can be freely cloned. When passing |
34 | | /// to a function which is decoding a nested object, then use `enter_recursion`. |
35 | | #[derive(Clone, Debug)] |
36 | | #[cfg_attr(feature = "no-recursion-limit", derive(Default))] |
37 | | pub struct DecodeContext { |
38 | | /// How many times we can recurse in the current decode stack before we hit |
39 | | /// the recursion limit. |
40 | | /// |
41 | | /// The recursion limit is defined by `RECURSION_LIMIT` and cannot be |
42 | | /// customized. The recursion limit can be ignored by building the Prost |
43 | | /// crate with the `no-recursion-limit` feature. |
44 | | #[cfg(not(feature = "no-recursion-limit"))] |
45 | | recurse_count: u32, |
46 | | } |
47 | | |
48 | | #[cfg(not(feature = "no-recursion-limit"))] |
49 | | impl Default for DecodeContext { |
50 | | #[inline] |
51 | 0 | fn default() -> DecodeContext { |
52 | 0 | DecodeContext { |
53 | 0 | recurse_count: crate::RECURSION_LIMIT, |
54 | 0 | } |
55 | 0 | } |
56 | | } |
57 | | |
58 | | impl DecodeContext { |
59 | | /// Call this function before recursively decoding. |
60 | | /// |
61 | | /// There is no `exit` function since this function creates a new `DecodeContext` |
62 | | /// to be used at the next level of recursion. Continue to use the old context |
63 | | // at the previous level of recursion. |
64 | | #[cfg(not(feature = "no-recursion-limit"))] |
65 | | #[inline] |
66 | 0 | pub(crate) fn enter_recursion(&self) -> DecodeContext { |
67 | 0 | DecodeContext { |
68 | 0 | recurse_count: self.recurse_count - 1, |
69 | 0 | } |
70 | 0 | } |
71 | | |
72 | | #[cfg(feature = "no-recursion-limit")] |
73 | | #[inline] |
74 | | pub(crate) fn enter_recursion(&self) -> DecodeContext { |
75 | | DecodeContext {} |
76 | | } |
77 | | |
78 | | /// Checks whether the recursion limit has been reached in the stack of |
79 | | /// decodes described by the `DecodeContext` at `self.ctx`. |
80 | | /// |
81 | | /// Returns `Ok<()>` if it is ok to continue recursing. |
82 | | /// Returns `Err<DecodeError>` if the recursion limit has been reached. |
83 | | #[cfg(not(feature = "no-recursion-limit"))] |
84 | | #[inline] |
85 | 0 | pub(crate) fn limit_reached(&self) -> Result<(), DecodeError> { |
86 | 0 | if self.recurse_count == 0 { |
87 | 0 | Err(DecodeErrorKind::RecursionLimitReached.into()) |
88 | | } else { |
89 | 0 | Ok(()) |
90 | | } |
91 | 0 | } |
92 | | |
93 | | #[cfg(feature = "no-recursion-limit")] |
94 | | #[inline] |
95 | | pub(crate) fn limit_reached(&self) -> Result<(), DecodeError> { |
96 | | Ok(()) |
97 | | } |
98 | | } |
99 | | |
100 | | pub const MIN_TAG: u32 = 1; |
101 | | pub const MAX_TAG: u32 = (1 << 29) - 1; |
102 | | |
103 | | /// Encodes a Protobuf field key, which consists of a wire type designator and |
104 | | /// the field tag. |
105 | | #[inline] |
106 | 0 | pub fn encode_key(tag: u32, wire_type: WireType, buf: &mut impl BufMut) { |
107 | 0 | debug_assert!((MIN_TAG..=MAX_TAG).contains(&tag)); |
108 | 0 | let key = (tag << 3) | wire_type as u32; |
109 | 0 | encode_varint(u64::from(key), buf); |
110 | 0 | } |
111 | | |
112 | | /// Decodes a Protobuf field key, which consists of a wire type designator and |
113 | | /// the field tag. |
114 | | #[inline(always)] |
115 | 0 | pub fn decode_key(buf: &mut impl Buf) -> Result<(u32, WireType), DecodeError> { |
116 | 0 | let key = decode_varint(buf)?; |
117 | 0 | if key > u64::from(u32::MAX) { |
118 | 0 | return Err(DecodeErrorKind::InvalidKey { key }.into()); |
119 | 0 | } |
120 | 0 | let wire_type = WireType::try_from(key & 0x07)?; |
121 | 0 | let tag = key as u32 >> 3; |
122 | | |
123 | 0 | if tag < MIN_TAG { |
124 | 0 | return Err(DecodeErrorKind::InvalidTag.into()); |
125 | 0 | } |
126 | | |
127 | 0 | Ok((tag, wire_type)) |
128 | 0 | } |
129 | | |
130 | | /// Returns the width of an encoded Protobuf field key with the given tag. |
131 | | /// The returned width will be between 1 and 5 bytes (inclusive). |
132 | | #[inline] |
133 | 0 | pub const fn key_len(tag: u32) -> usize { |
134 | 0 | encoded_len_varint((tag << 3) as u64) |
135 | 0 | } |
136 | | |
137 | | /// Helper function which abstracts reading a length delimiter prefix followed |
138 | | /// by decoding values until the length of bytes is exhausted. |
139 | 0 | pub fn merge_loop<T, M, B>( |
140 | 0 | value: &mut T, |
141 | 0 | buf: &mut B, |
142 | 0 | ctx: DecodeContext, |
143 | 0 | mut merge: M, |
144 | 0 | ) -> Result<(), DecodeError> |
145 | 0 | where |
146 | 0 | M: FnMut(&mut T, &mut B, DecodeContext) -> Result<(), DecodeError>, |
147 | 0 | B: Buf, |
148 | | { |
149 | 0 | let len = decode_varint(buf)?; |
150 | 0 | let remaining = buf.remaining(); |
151 | 0 | if len > remaining as u64 { |
152 | 0 | return Err(DecodeErrorKind::BufferUnderflow.into()); |
153 | 0 | } |
154 | | |
155 | 0 | let limit = remaining - len as usize; |
156 | 0 | while buf.remaining() > limit { |
157 | 0 | merge(value, buf, ctx.clone())?; |
158 | | } |
159 | | |
160 | 0 | if buf.remaining() != limit { |
161 | 0 | return Err(DecodeErrorKind::DelimitedLengthExceeded.into()); |
162 | 0 | } |
163 | 0 | Ok(()) |
164 | 0 | } |
165 | | |
166 | 0 | pub fn skip_field( |
167 | 0 | wire_type: WireType, |
168 | 0 | tag: u32, |
169 | 0 | buf: &mut impl Buf, |
170 | 0 | ctx: DecodeContext, |
171 | 0 | ) -> Result<(), DecodeError> { |
172 | 0 | ctx.limit_reached()?; |
173 | 0 | let len = match wire_type { |
174 | 0 | WireType::Varint => decode_varint(buf).map(|_| 0)?, |
175 | 0 | WireType::ThirtyTwoBit => 4, |
176 | 0 | WireType::SixtyFourBit => 8, |
177 | 0 | WireType::LengthDelimited => decode_varint(buf)?, |
178 | | WireType::StartGroup => loop { |
179 | 0 | let (inner_tag, inner_wire_type) = decode_key(buf)?; |
180 | 0 | match inner_wire_type { |
181 | | WireType::EndGroup => { |
182 | 0 | if inner_tag != tag { |
183 | 0 | return Err(DecodeErrorKind::UnexpectedEndGroupTag.into()); |
184 | 0 | } |
185 | 0 | break 0; |
186 | | } |
187 | 0 | _ => skip_field(inner_wire_type, inner_tag, buf, ctx.enter_recursion())?, |
188 | | } |
189 | | }, |
190 | 0 | WireType::EndGroup => return Err(DecodeErrorKind::UnexpectedEndGroupTag.into()), |
191 | | }; |
192 | | |
193 | 0 | if len > buf.remaining() as u64 { |
194 | 0 | return Err(DecodeErrorKind::BufferUnderflow.into()); |
195 | 0 | } |
196 | | |
197 | 0 | buf.advance(len as usize); |
198 | 0 | Ok(()) |
199 | 0 | } |
200 | | |
201 | | /// Helper macro which emits an `encode_repeated` function for the type. |
202 | | macro_rules! encode_repeated { |
203 | | ($ty:ty) => { |
204 | 0 | pub fn encode_repeated(tag: u32, values: &[$ty], buf: &mut impl BufMut) { |
205 | 0 | for value in values { |
206 | 0 | encode(tag, value, buf); |
207 | 0 | } |
208 | 0 | } Unexecuted instantiation: prost::encoding::bool::encode_repeated::<_> Unexecuted instantiation: prost::encoding::bytes::encode_repeated::<_, _> Unexecuted instantiation: prost::encoding::float::encode_repeated::<_> Unexecuted instantiation: prost::encoding::int32::encode_repeated::<_> Unexecuted instantiation: prost::encoding::int64::encode_repeated::<_> Unexecuted instantiation: prost::encoding::double::encode_repeated::<_> Unexecuted instantiation: prost::encoding::sint32::encode_repeated::<_> Unexecuted instantiation: prost::encoding::sint64::encode_repeated::<_> Unexecuted instantiation: prost::encoding::string::encode_repeated::<_> Unexecuted instantiation: prost::encoding::uint32::encode_repeated::<_> Unexecuted instantiation: prost::encoding::uint64::encode_repeated::<_> Unexecuted instantiation: prost::encoding::fixed32::encode_repeated::<_> Unexecuted instantiation: prost::encoding::fixed64::encode_repeated::<_> Unexecuted instantiation: prost::encoding::sfixed32::encode_repeated::<_> Unexecuted instantiation: prost::encoding::sfixed64::encode_repeated::<_> |
209 | | }; |
210 | | } |
211 | | |
212 | | /// Helper macro which emits a `merge_repeated` function for the numeric type. |
213 | | macro_rules! merge_repeated_numeric { |
214 | | ($ty:ty, |
215 | | $wire_type:expr, |
216 | | $merge:ident, |
217 | | $merge_repeated:ident) => { |
218 | 0 | pub fn $merge_repeated( |
219 | 0 | wire_type: WireType, |
220 | 0 | values: &mut Vec<$ty>, |
221 | 0 | buf: &mut impl Buf, |
222 | 0 | ctx: DecodeContext, |
223 | 0 | ) -> Result<(), DecodeError> { |
224 | 0 | if wire_type == WireType::LengthDelimited { |
225 | | // Packed. |
226 | 0 | merge_loop(values, buf, ctx, |values, buf, ctx| { |
227 | 0 | let mut value = Default::default(); |
228 | 0 | $merge($wire_type, &mut value, buf, ctx)?; |
229 | 0 | values.push(value); |
230 | 0 | Ok(()) |
231 | 0 | }) Unexecuted instantiation: prost::encoding::bool::merge_repeated::<_>::{closure#0}Unexecuted instantiation: prost::encoding::float::merge_repeated::<_>::{closure#0}Unexecuted instantiation: prost::encoding::int32::merge_repeated::<_>::{closure#0}Unexecuted instantiation: prost::encoding::int64::merge_repeated::<_>::{closure#0}Unexecuted instantiation: prost::encoding::double::merge_repeated::<_>::{closure#0}Unexecuted instantiation: prost::encoding::sint32::merge_repeated::<_>::{closure#0}Unexecuted instantiation: prost::encoding::sint64::merge_repeated::<_>::{closure#0}Unexecuted instantiation: prost::encoding::uint32::merge_repeated::<_>::{closure#0}Unexecuted instantiation: prost::encoding::uint64::merge_repeated::<_>::{closure#0}Unexecuted instantiation: prost::encoding::fixed32::merge_repeated::<_>::{closure#0}Unexecuted instantiation: prost::encoding::fixed64::merge_repeated::<_>::{closure#0}Unexecuted instantiation: prost::encoding::sfixed32::merge_repeated::<_>::{closure#0}Unexecuted instantiation: prost::encoding::sfixed64::merge_repeated::<_>::{closure#0} |
232 | | } else { |
233 | | // Unpacked. |
234 | 0 | check_wire_type($wire_type, wire_type)?; |
235 | 0 | let mut value = Default::default(); |
236 | 0 | $merge(wire_type, &mut value, buf, ctx)?; |
237 | 0 | values.push(value); |
238 | 0 | Ok(()) |
239 | | } |
240 | 0 | } Unexecuted instantiation: prost::encoding::bool::merge_repeated::<_> Unexecuted instantiation: prost::encoding::float::merge_repeated::<_> Unexecuted instantiation: prost::encoding::int32::merge_repeated::<_> Unexecuted instantiation: prost::encoding::int64::merge_repeated::<_> Unexecuted instantiation: prost::encoding::double::merge_repeated::<_> Unexecuted instantiation: prost::encoding::sint32::merge_repeated::<_> Unexecuted instantiation: prost::encoding::sint64::merge_repeated::<_> Unexecuted instantiation: prost::encoding::uint32::merge_repeated::<_> Unexecuted instantiation: prost::encoding::uint64::merge_repeated::<_> Unexecuted instantiation: prost::encoding::fixed32::merge_repeated::<_> Unexecuted instantiation: prost::encoding::fixed64::merge_repeated::<_> Unexecuted instantiation: prost::encoding::sfixed32::merge_repeated::<_> Unexecuted instantiation: prost::encoding::sfixed64::merge_repeated::<_> |
241 | | }; |
242 | | } |
243 | | |
244 | | /// Macro which emits a module containing a set of encoding functions for a |
245 | | /// variable width numeric type. |
246 | | macro_rules! varint { |
247 | | ($ty:ty, |
248 | | $proto_ty:ident) => ( |
249 | | varint!($ty, |
250 | | $proto_ty, |
251 | | to_uint64(value) { *value as u64 }, |
252 | | from_uint64(value) { value as $ty }); |
253 | | ); |
254 | | |
255 | | ($ty:ty, |
256 | | $proto_ty:ident, |
257 | | to_uint64($to_uint64_value:ident) $to_uint64:expr, |
258 | | from_uint64($from_uint64_value:ident) $from_uint64:expr) => ( |
259 | | |
260 | | pub mod $proto_ty { |
261 | | use crate::encoding::*; |
262 | | |
263 | 0 | pub fn encode(tag: u32, $to_uint64_value: &$ty, buf: &mut impl BufMut) { |
264 | 0 | encode_key(tag, WireType::Varint, buf); |
265 | 0 | encode_varint($to_uint64, buf); |
266 | 0 | } Unexecuted instantiation: prost::encoding::bool::encode::<_> Unexecuted instantiation: prost::encoding::int32::encode::<_> Unexecuted instantiation: prost::encoding::int64::encode::<_> Unexecuted instantiation: prost::encoding::sint32::encode::<_> Unexecuted instantiation: prost::encoding::sint64::encode::<_> Unexecuted instantiation: prost::encoding::uint32::encode::<_> Unexecuted instantiation: prost::encoding::uint64::encode::<_> |
267 | | |
268 | 0 | pub fn merge(wire_type: WireType, value: &mut $ty, buf: &mut impl Buf, _ctx: DecodeContext) -> Result<(), DecodeError> { |
269 | 0 | check_wire_type(WireType::Varint, wire_type)?; |
270 | 0 | let $from_uint64_value = decode_varint(buf)?; |
271 | 0 | *value = $from_uint64; |
272 | 0 | Ok(()) |
273 | 0 | } Unexecuted instantiation: prost::encoding::bool::merge::<_> Unexecuted instantiation: prost::encoding::int32::merge::<_> Unexecuted instantiation: prost::encoding::int64::merge::<_> Unexecuted instantiation: prost::encoding::sint32::merge::<_> Unexecuted instantiation: prost::encoding::sint64::merge::<_> Unexecuted instantiation: prost::encoding::uint32::merge::<_> Unexecuted instantiation: prost::encoding::uint64::merge::<_> |
274 | | |
275 | | encode_repeated!($ty); |
276 | | |
277 | 0 | pub fn encode_packed(tag: u32, values: &[$ty], buf: &mut impl BufMut) { |
278 | 0 | if values.is_empty() { return; } |
279 | | |
280 | 0 | encode_key(tag, WireType::LengthDelimited, buf); |
281 | 0 | let len: usize = values.iter().map(|$to_uint64_value| { |
282 | 0 | encoded_len_varint($to_uint64) |
283 | 0 | }).sum(); Unexecuted instantiation: prost::encoding::bool::encode_packed::<_>::{closure#0}Unexecuted instantiation: prost::encoding::int32::encode_packed::<_>::{closure#0}Unexecuted instantiation: prost::encoding::int64::encode_packed::<_>::{closure#0}Unexecuted instantiation: prost::encoding::sint32::encode_packed::<_>::{closure#0}Unexecuted instantiation: prost::encoding::sint64::encode_packed::<_>::{closure#0}Unexecuted instantiation: prost::encoding::uint32::encode_packed::<_>::{closure#0}Unexecuted instantiation: prost::encoding::uint64::encode_packed::<_>::{closure#0} |
284 | 0 | encode_varint(len as u64, buf); |
285 | | |
286 | 0 | for $to_uint64_value in values { |
287 | 0 | encode_varint($to_uint64, buf); |
288 | 0 | } |
289 | 0 | } Unexecuted instantiation: prost::encoding::bool::encode_packed::<_> Unexecuted instantiation: prost::encoding::int32::encode_packed::<_> Unexecuted instantiation: prost::encoding::int64::encode_packed::<_> Unexecuted instantiation: prost::encoding::sint32::encode_packed::<_> Unexecuted instantiation: prost::encoding::sint64::encode_packed::<_> Unexecuted instantiation: prost::encoding::uint32::encode_packed::<_> Unexecuted instantiation: prost::encoding::uint64::encode_packed::<_> |
290 | | |
291 | | merge_repeated_numeric!($ty, WireType::Varint, merge, merge_repeated); |
292 | | |
293 | | #[inline] |
294 | 0 | pub fn encoded_len(tag: u32, $to_uint64_value: &$ty) -> usize { |
295 | 0 | key_len(tag) + encoded_len_varint($to_uint64) |
296 | 0 | } Unexecuted instantiation: prost::encoding::int32::encoded_len Unexecuted instantiation: prost::encoding::int64::encoded_len Unexecuted instantiation: prost::encoding::uint32::encoded_len Unexecuted instantiation: prost::encoding::uint64::encoded_len Unexecuted instantiation: prost::encoding::bool::encoded_len Unexecuted instantiation: prost::encoding::sint32::encoded_len Unexecuted instantiation: prost::encoding::sint64::encoded_len |
297 | | |
298 | | #[inline] |
299 | 0 | pub fn encoded_len_repeated(tag: u32, values: &[$ty]) -> usize { |
300 | 0 | key_len(tag) * values.len() + values.iter().map(|$to_uint64_value| { |
301 | 0 | encoded_len_varint($to_uint64) |
302 | 0 | }).sum::<usize>() Unexecuted instantiation: prost::encoding::bool::encoded_len_repeated::{closure#0}Unexecuted instantiation: prost::encoding::int32::encoded_len_repeated::{closure#0}Unexecuted instantiation: prost::encoding::int64::encoded_len_repeated::{closure#0}Unexecuted instantiation: prost::encoding::sint32::encoded_len_repeated::{closure#0}Unexecuted instantiation: prost::encoding::sint64::encoded_len_repeated::{closure#0}Unexecuted instantiation: prost::encoding::uint32::encoded_len_repeated::{closure#0}Unexecuted instantiation: prost::encoding::uint64::encoded_len_repeated::{closure#0} |
303 | 0 | } Unexecuted instantiation: prost::encoding::bool::encoded_len_repeated Unexecuted instantiation: prost::encoding::int32::encoded_len_repeated Unexecuted instantiation: prost::encoding::int64::encoded_len_repeated Unexecuted instantiation: prost::encoding::sint32::encoded_len_repeated Unexecuted instantiation: prost::encoding::sint64::encoded_len_repeated Unexecuted instantiation: prost::encoding::uint32::encoded_len_repeated Unexecuted instantiation: prost::encoding::uint64::encoded_len_repeated |
304 | | |
305 | | #[inline] |
306 | 0 | pub fn encoded_len_packed(tag: u32, values: &[$ty]) -> usize { |
307 | 0 | if values.is_empty() { |
308 | 0 | 0 |
309 | | } else { |
310 | 0 | let len = values.iter() |
311 | 0 | .map(|$to_uint64_value| encoded_len_varint($to_uint64)) Unexecuted instantiation: prost::encoding::bool::encoded_len_packed::{closure#0}Unexecuted instantiation: prost::encoding::int32::encoded_len_packed::{closure#0}Unexecuted instantiation: prost::encoding::int64::encoded_len_packed::{closure#0}Unexecuted instantiation: prost::encoding::sint32::encoded_len_packed::{closure#0}Unexecuted instantiation: prost::encoding::sint64::encoded_len_packed::{closure#0}Unexecuted instantiation: prost::encoding::uint32::encoded_len_packed::{closure#0}Unexecuted instantiation: prost::encoding::uint64::encoded_len_packed::{closure#0} |
312 | 0 | .sum::<usize>(); |
313 | 0 | key_len(tag) + encoded_len_varint(len as u64) + len |
314 | | } |
315 | 0 | } Unexecuted instantiation: prost::encoding::bool::encoded_len_packed Unexecuted instantiation: prost::encoding::int32::encoded_len_packed Unexecuted instantiation: prost::encoding::int64::encoded_len_packed Unexecuted instantiation: prost::encoding::sint32::encoded_len_packed Unexecuted instantiation: prost::encoding::sint64::encoded_len_packed Unexecuted instantiation: prost::encoding::uint32::encoded_len_packed Unexecuted instantiation: prost::encoding::uint64::encoded_len_packed |
316 | | |
317 | | #[cfg(test)] |
318 | | mod test { |
319 | | use proptest::prelude::*; |
320 | | |
321 | | use crate::encoding::$proto_ty::*; |
322 | | use crate::encoding::test::{ |
323 | | check_collection_type, |
324 | | check_type, |
325 | | }; |
326 | | |
327 | | proptest! { |
328 | | #[test] |
329 | | fn check(value: $ty, tag in MIN_TAG..=MAX_TAG) { |
330 | | check_type(value, tag, WireType::Varint, |
331 | | encode, merge, encoded_len)?; |
332 | | } |
333 | | #[test] |
334 | | fn check_repeated(value: Vec<$ty>, tag in MIN_TAG..=MAX_TAG) { |
335 | | check_collection_type(value, tag, WireType::Varint, |
336 | | encode_repeated, merge_repeated, |
337 | | encoded_len_repeated)?; |
338 | | } |
339 | | #[test] |
340 | | fn check_packed(value: Vec<$ty>, tag in MIN_TAG..=MAX_TAG) { |
341 | | check_type(value, tag, WireType::LengthDelimited, |
342 | | encode_packed, merge_repeated, |
343 | | encoded_len_packed)?; |
344 | | } |
345 | | } |
346 | | } |
347 | | } |
348 | | |
349 | | ); |
350 | | } |
351 | | varint!(bool, bool, |
352 | | to_uint64(value) u64::from(*value), |
353 | | from_uint64(value) value != 0); |
354 | | varint!(i32, int32); |
355 | | varint!(i64, int64); |
356 | | varint!(u32, uint32); |
357 | | varint!(u64, uint64); |
358 | | varint!(i32, sint32, |
359 | | to_uint64(value) { |
360 | | ((value << 1) ^ (value >> 31)) as u32 as u64 |
361 | | }, |
362 | | from_uint64(value) { |
363 | | let value = value as u32; |
364 | | ((value >> 1) as i32) ^ (-((value & 1) as i32)) |
365 | | }); |
366 | | varint!(i64, sint64, |
367 | | to_uint64(value) { |
368 | | ((value << 1) ^ (value >> 63)) as u64 |
369 | | }, |
370 | | from_uint64(value) { |
371 | | ((value >> 1) as i64) ^ (-((value & 1) as i64)) |
372 | | }); |
373 | | |
374 | | /// Macro which emits a module containing a set of encoding functions for a |
375 | | /// fixed width numeric type. |
376 | | macro_rules! fixed_width { |
377 | | ($ty:ty, |
378 | | $width:expr, |
379 | | $wire_type:expr, |
380 | | $proto_ty:ident, |
381 | | $put:ident, |
382 | | $get:ident) => { |
383 | | pub mod $proto_ty { |
384 | | use crate::encoding::*; |
385 | | |
386 | 0 | pub fn encode(tag: u32, value: &$ty, buf: &mut impl BufMut) { |
387 | 0 | encode_key(tag, $wire_type, buf); |
388 | 0 | buf.$put(*value); |
389 | 0 | } Unexecuted instantiation: prost::encoding::float::encode::<_> Unexecuted instantiation: prost::encoding::double::encode::<_> Unexecuted instantiation: prost::encoding::fixed32::encode::<_> Unexecuted instantiation: prost::encoding::fixed64::encode::<_> Unexecuted instantiation: prost::encoding::sfixed32::encode::<_> Unexecuted instantiation: prost::encoding::sfixed64::encode::<_> |
390 | | |
391 | 0 | pub fn merge( |
392 | 0 | wire_type: WireType, |
393 | 0 | value: &mut $ty, |
394 | 0 | buf: &mut impl Buf, |
395 | 0 | _ctx: DecodeContext, |
396 | 0 | ) -> Result<(), DecodeError> { |
397 | 0 | check_wire_type($wire_type, wire_type)?; |
398 | 0 | if buf.remaining() < $width { |
399 | 0 | return Err(DecodeErrorKind::BufferUnderflow.into()); |
400 | 0 | } |
401 | 0 | *value = buf.$get(); |
402 | 0 | Ok(()) |
403 | 0 | } Unexecuted instantiation: prost::encoding::float::merge::<_> Unexecuted instantiation: prost::encoding::double::merge::<_> Unexecuted instantiation: prost::encoding::fixed32::merge::<_> Unexecuted instantiation: prost::encoding::fixed64::merge::<_> Unexecuted instantiation: prost::encoding::sfixed32::merge::<_> Unexecuted instantiation: prost::encoding::sfixed64::merge::<_> |
404 | | |
405 | | encode_repeated!($ty); |
406 | | |
407 | 0 | pub fn encode_packed(tag: u32, values: &[$ty], buf: &mut impl BufMut) { |
408 | 0 | if values.is_empty() { |
409 | 0 | return; |
410 | 0 | } |
411 | | |
412 | 0 | encode_key(tag, WireType::LengthDelimited, buf); |
413 | 0 | let len = values.len() as u64 * $width; |
414 | 0 | encode_varint(len as u64, buf); |
415 | | |
416 | 0 | for value in values { |
417 | 0 | buf.$put(*value); |
418 | 0 | } |
419 | 0 | } Unexecuted instantiation: prost::encoding::float::encode_packed::<_> Unexecuted instantiation: prost::encoding::double::encode_packed::<_> Unexecuted instantiation: prost::encoding::fixed32::encode_packed::<_> Unexecuted instantiation: prost::encoding::fixed64::encode_packed::<_> Unexecuted instantiation: prost::encoding::sfixed32::encode_packed::<_> Unexecuted instantiation: prost::encoding::sfixed64::encode_packed::<_> |
420 | | |
421 | | merge_repeated_numeric!($ty, $wire_type, merge, merge_repeated); |
422 | | |
423 | | #[inline] |
424 | 0 | pub fn encoded_len(tag: u32, _: &$ty) -> usize { |
425 | 0 | key_len(tag) + $width |
426 | 0 | } Unexecuted instantiation: prost::encoding::float::encoded_len Unexecuted instantiation: prost::encoding::double::encoded_len Unexecuted instantiation: prost::encoding::fixed32::encoded_len Unexecuted instantiation: prost::encoding::fixed64::encoded_len Unexecuted instantiation: prost::encoding::sfixed32::encoded_len Unexecuted instantiation: prost::encoding::sfixed64::encoded_len |
427 | | |
428 | | #[inline] |
429 | 0 | pub fn encoded_len_repeated(tag: u32, values: &[$ty]) -> usize { |
430 | 0 | (key_len(tag) + $width) * values.len() |
431 | 0 | } Unexecuted instantiation: prost::encoding::float::encoded_len_repeated Unexecuted instantiation: prost::encoding::double::encoded_len_repeated Unexecuted instantiation: prost::encoding::fixed32::encoded_len_repeated Unexecuted instantiation: prost::encoding::fixed64::encoded_len_repeated Unexecuted instantiation: prost::encoding::sfixed32::encoded_len_repeated Unexecuted instantiation: prost::encoding::sfixed64::encoded_len_repeated |
432 | | |
433 | | #[inline] |
434 | 0 | pub fn encoded_len_packed(tag: u32, values: &[$ty]) -> usize { |
435 | 0 | if values.is_empty() { |
436 | 0 | 0 |
437 | | } else { |
438 | 0 | let len = $width * values.len(); |
439 | 0 | key_len(tag) + encoded_len_varint(len as u64) + len |
440 | | } |
441 | 0 | } Unexecuted instantiation: prost::encoding::float::encoded_len_packed Unexecuted instantiation: prost::encoding::double::encoded_len_packed Unexecuted instantiation: prost::encoding::fixed32::encoded_len_packed Unexecuted instantiation: prost::encoding::fixed64::encoded_len_packed Unexecuted instantiation: prost::encoding::sfixed32::encoded_len_packed Unexecuted instantiation: prost::encoding::sfixed64::encoded_len_packed |
442 | | |
443 | | #[cfg(test)] |
444 | | mod test { |
445 | | use proptest::prelude::*; |
446 | | |
447 | | use super::super::test::{check_collection_type, check_type}; |
448 | | use super::*; |
449 | | |
450 | | proptest! { |
451 | | #[test] |
452 | | fn check(value: $ty, tag in MIN_TAG..=MAX_TAG) { |
453 | | check_type(value, tag, $wire_type, |
454 | | encode, merge, encoded_len)?; |
455 | | } |
456 | | #[test] |
457 | | fn check_repeated(value: Vec<$ty>, tag in MIN_TAG..=MAX_TAG) { |
458 | | check_collection_type(value, tag, $wire_type, |
459 | | encode_repeated, merge_repeated, |
460 | | encoded_len_repeated)?; |
461 | | } |
462 | | #[test] |
463 | | fn check_packed(value: Vec<$ty>, tag in MIN_TAG..=MAX_TAG) { |
464 | | check_type(value, tag, WireType::LengthDelimited, |
465 | | encode_packed, merge_repeated, |
466 | | encoded_len_packed)?; |
467 | | } |
468 | | } |
469 | | } |
470 | | } |
471 | | }; |
472 | | } |
473 | | fixed_width!( |
474 | | f32, |
475 | | 4, |
476 | | WireType::ThirtyTwoBit, |
477 | | float, |
478 | | put_f32_le, |
479 | | get_f32_le |
480 | | ); |
481 | | fixed_width!( |
482 | | f64, |
483 | | 8, |
484 | | WireType::SixtyFourBit, |
485 | | double, |
486 | | put_f64_le, |
487 | | get_f64_le |
488 | | ); |
489 | | fixed_width!( |
490 | | u32, |
491 | | 4, |
492 | | WireType::ThirtyTwoBit, |
493 | | fixed32, |
494 | | put_u32_le, |
495 | | get_u32_le |
496 | | ); |
497 | | fixed_width!( |
498 | | u64, |
499 | | 8, |
500 | | WireType::SixtyFourBit, |
501 | | fixed64, |
502 | | put_u64_le, |
503 | | get_u64_le |
504 | | ); |
505 | | fixed_width!( |
506 | | i32, |
507 | | 4, |
508 | | WireType::ThirtyTwoBit, |
509 | | sfixed32, |
510 | | put_i32_le, |
511 | | get_i32_le |
512 | | ); |
513 | | fixed_width!( |
514 | | i64, |
515 | | 8, |
516 | | WireType::SixtyFourBit, |
517 | | sfixed64, |
518 | | put_i64_le, |
519 | | get_i64_le |
520 | | ); |
521 | | |
522 | | /// Macro which emits encoding functions for a length-delimited type. |
523 | | macro_rules! length_delimited { |
524 | | ($ty:ty) => { |
525 | | encode_repeated!($ty); |
526 | | |
527 | 0 | pub fn merge_repeated( |
528 | 0 | wire_type: WireType, |
529 | 0 | values: &mut Vec<$ty>, |
530 | 0 | buf: &mut impl Buf, |
531 | 0 | ctx: DecodeContext, |
532 | 0 | ) -> Result<(), DecodeError> { |
533 | 0 | check_wire_type(WireType::LengthDelimited, wire_type)?; |
534 | 0 | let mut value = Default::default(); |
535 | 0 | merge(wire_type, &mut value, buf, ctx)?; |
536 | 0 | values.push(value); |
537 | 0 | Ok(()) |
538 | 0 | } Unexecuted instantiation: prost::encoding::bytes::merge_repeated::<_, _> Unexecuted instantiation: prost::encoding::string::merge_repeated::<_> |
539 | | |
540 | | #[inline] |
541 | | #[allow(clippy::ptr_arg)] |
542 | 0 | pub fn encoded_len(tag: u32, value: &$ty) -> usize { |
543 | 0 | key_len(tag) + encoded_len_varint(value.len() as u64) + value.len() |
544 | 0 | } Unexecuted instantiation: prost::encoding::bytes::encoded_len::<alloc::vec::Vec<u8>> Unexecuted instantiation: prost::encoding::bytes::encoded_len::<bytes::bytes::Bytes> Unexecuted instantiation: prost::encoding::string::encoded_len |
545 | | |
546 | | #[inline] |
547 | 0 | pub fn encoded_len_repeated(tag: u32, values: &[$ty]) -> usize { |
548 | 0 | key_len(tag) * values.len() |
549 | 0 | + values |
550 | 0 | .iter() |
551 | 0 | .map(|value| encoded_len_varint(value.len() as u64) + value.len()) Unexecuted instantiation: prost::encoding::bytes::encoded_len_repeated::<_>::{closure#0}Unexecuted instantiation: prost::encoding::string::encoded_len_repeated::{closure#0} |
552 | 0 | .sum::<usize>() |
553 | 0 | } Unexecuted instantiation: prost::encoding::bytes::encoded_len_repeated::<_> Unexecuted instantiation: prost::encoding::string::encoded_len_repeated |
554 | | }; |
555 | | } |
556 | | |
557 | | pub mod string { |
558 | | use super::*; |
559 | | |
560 | 0 | pub fn encode(tag: u32, value: &String, buf: &mut impl BufMut) { |
561 | 0 | encode_key(tag, WireType::LengthDelimited, buf); |
562 | 0 | encode_varint(value.len() as u64, buf); |
563 | 0 | buf.put_slice(value.as_bytes()); |
564 | 0 | } |
565 | | |
566 | 0 | pub fn merge( |
567 | 0 | wire_type: WireType, |
568 | 0 | value: &mut String, |
569 | 0 | buf: &mut impl Buf, |
570 | 0 | ctx: DecodeContext, |
571 | 0 | ) -> Result<(), DecodeError> { |
572 | | // ## Unsafety |
573 | | // |
574 | | // `string::merge` reuses `bytes::merge`, with an additional check of utf-8 |
575 | | // well-formedness. If the utf-8 is not well-formed, or if any other error occurs, then the |
576 | | // string is cleared, so as to avoid leaking a string field with invalid data. |
577 | | // |
578 | | // This implementation uses the unsafe `String::as_mut_vec` method instead of the safe |
579 | | // alternative of temporarily swapping an empty `String` into the field, because it results |
580 | | // in up to 10% better performance on the protobuf message decoding benchmarks. |
581 | | // |
582 | | // It's required when using `String::as_mut_vec` that invalid utf-8 data not be leaked into |
583 | | // the backing `String`. To enforce this, even in the event of a panic in `bytes::merge` or |
584 | | // in the buf implementation, a drop guard is used. |
585 | | unsafe { |
586 | | struct DropGuard<'a>(&'a mut Vec<u8>); |
587 | | impl Drop for DropGuard<'_> { |
588 | | #[inline] |
589 | 0 | fn drop(&mut self) { |
590 | 0 | self.0.clear(); |
591 | 0 | } |
592 | | } |
593 | | |
594 | 0 | let drop_guard = DropGuard(value.as_mut_vec()); |
595 | 0 | bytes::merge_one_copy(wire_type, drop_guard.0, buf, ctx)?; |
596 | 0 | match str::from_utf8(drop_guard.0) { |
597 | | Ok(_) => { |
598 | | // Success; do not clear the bytes. |
599 | 0 | mem::forget(drop_guard); |
600 | 0 | Ok(()) |
601 | | } |
602 | 0 | Err(_) => Err(DecodeErrorKind::InvalidString.into()), |
603 | | } |
604 | | } |
605 | 0 | } |
606 | | |
607 | | length_delimited!(String); |
608 | | |
609 | | #[cfg(test)] |
610 | | mod test { |
611 | | use proptest::prelude::*; |
612 | | |
613 | | use super::super::test::{check_collection_type, check_type}; |
614 | | use super::*; |
615 | | |
616 | | proptest! { |
617 | | #[test] |
618 | | fn check(value: String, tag in MIN_TAG..=MAX_TAG) { |
619 | | super::test::check_type(value, tag, WireType::LengthDelimited, |
620 | | encode, merge, encoded_len)?; |
621 | | } |
622 | | #[test] |
623 | | fn check_repeated(value: Vec<String>, tag in MIN_TAG..=MAX_TAG) { |
624 | | super::test::check_collection_type(value, tag, WireType::LengthDelimited, |
625 | | encode_repeated, merge_repeated, |
626 | | encoded_len_repeated)?; |
627 | | } |
628 | | } |
629 | | } |
630 | | } |
631 | | |
632 | | pub trait BytesAdapter: sealed::BytesAdapter {} |
633 | | |
634 | | mod sealed { |
635 | | use super::{Buf, BufMut}; |
636 | | |
637 | | pub trait BytesAdapter: Default + Sized + 'static { |
638 | | fn len(&self) -> usize; |
639 | | |
640 | | /// Replace contents of this buffer with the contents of another buffer. |
641 | | fn replace_with(&mut self, buf: impl Buf); |
642 | | |
643 | | /// Appends this buffer to the (contents of) other buffer. |
644 | | fn append_to(&self, buf: &mut impl BufMut); |
645 | | |
646 | 0 | fn is_empty(&self) -> bool { |
647 | 0 | self.len() == 0 |
648 | 0 | } |
649 | | } |
650 | | } |
651 | | |
652 | | impl BytesAdapter for Bytes {} |
653 | | |
654 | | impl sealed::BytesAdapter for Bytes { |
655 | 0 | fn len(&self) -> usize { |
656 | 0 | Buf::remaining(self) |
657 | 0 | } |
658 | | |
659 | 0 | fn replace_with(&mut self, mut buf: impl Buf) { |
660 | 0 | *self = buf.copy_to_bytes(buf.remaining()); |
661 | 0 | } |
662 | | |
663 | 0 | fn append_to(&self, buf: &mut impl BufMut) { |
664 | 0 | buf.put(self.clone()) |
665 | 0 | } |
666 | | } |
667 | | |
668 | | impl BytesAdapter for Vec<u8> {} |
669 | | |
670 | | impl sealed::BytesAdapter for Vec<u8> { |
671 | 0 | fn len(&self) -> usize { |
672 | 0 | Vec::len(self) |
673 | 0 | } |
674 | | |
675 | 0 | fn replace_with(&mut self, buf: impl Buf) { |
676 | 0 | self.clear(); |
677 | 0 | self.reserve(buf.remaining()); |
678 | 0 | self.put(buf); |
679 | 0 | } |
680 | | |
681 | 0 | fn append_to(&self, buf: &mut impl BufMut) { |
682 | 0 | buf.put(self.as_slice()) |
683 | 0 | } |
684 | | } |
685 | | |
686 | | pub mod bytes { |
687 | | use crate::error::DecodeErrorKind; |
688 | | |
689 | | use super::*; |
690 | | |
691 | 0 | pub fn encode(tag: u32, value: &impl BytesAdapter, buf: &mut impl BufMut) { |
692 | 0 | encode_key(tag, WireType::LengthDelimited, buf); |
693 | 0 | encode_varint(value.len() as u64, buf); |
694 | 0 | value.append_to(buf); |
695 | 0 | } |
696 | | |
697 | 0 | pub fn merge( |
698 | 0 | wire_type: WireType, |
699 | 0 | value: &mut impl BytesAdapter, |
700 | 0 | buf: &mut impl Buf, |
701 | 0 | _ctx: DecodeContext, |
702 | 0 | ) -> Result<(), DecodeError> { |
703 | 0 | check_wire_type(WireType::LengthDelimited, wire_type)?; |
704 | 0 | let len = decode_varint(buf)?; |
705 | 0 | if len > buf.remaining() as u64 { |
706 | 0 | return Err(DecodeErrorKind::BufferUnderflow.into()); |
707 | 0 | } |
708 | 0 | let len = len as usize; |
709 | | |
710 | | // Clear the existing value. This follows from the following rule in the encoding guide[1]: |
711 | | // |
712 | | // > Normally, an encoded message would never have more than one instance of a non-repeated |
713 | | // > field. However, parsers are expected to handle the case in which they do. For numeric |
714 | | // > types and strings, if the same field appears multiple times, the parser accepts the |
715 | | // > last value it sees. |
716 | | // |
717 | | // [1]: https://protobuf.dev/programming-guides/encoding/#last-one-wins |
718 | | // |
719 | | // This is intended for A and B both being Bytes so it is zero-copy. |
720 | | // Some combinations of A and B types may cause a double-copy, |
721 | | // in which case merge_one_copy() should be used instead. |
722 | 0 | value.replace_with(buf.copy_to_bytes(len)); |
723 | 0 | Ok(()) |
724 | 0 | } |
725 | | |
726 | 0 | pub(super) fn merge_one_copy( |
727 | 0 | wire_type: WireType, |
728 | 0 | value: &mut impl BytesAdapter, |
729 | 0 | buf: &mut impl Buf, |
730 | 0 | _ctx: DecodeContext, |
731 | 0 | ) -> Result<(), DecodeError> { |
732 | 0 | check_wire_type(WireType::LengthDelimited, wire_type)?; |
733 | 0 | let len = decode_varint(buf)?; |
734 | 0 | if len > buf.remaining() as u64 { |
735 | 0 | return Err(DecodeErrorKind::BufferUnderflow.into()); |
736 | 0 | } |
737 | 0 | let len = len as usize; |
738 | | |
739 | | // If we must copy, make sure to copy only once. |
740 | 0 | value.replace_with(buf.take(len)); |
741 | 0 | Ok(()) |
742 | 0 | } |
743 | | |
744 | | length_delimited!(impl BytesAdapter); |
745 | | |
746 | | #[cfg(test)] |
747 | | mod test { |
748 | | use proptest::prelude::*; |
749 | | |
750 | | use super::super::test::{check_collection_type, check_type}; |
751 | | use super::*; |
752 | | |
753 | | proptest! { |
754 | | #[test] |
755 | | fn check_vec(value: Vec<u8>, tag in MIN_TAG..=MAX_TAG) { |
756 | | super::test::check_type::<Vec<u8>, Vec<u8>>(value, tag, WireType::LengthDelimited, |
757 | | encode, merge, encoded_len)?; |
758 | | } |
759 | | |
760 | | #[test] |
761 | | fn check_bytes(value: Vec<u8>, tag in MIN_TAG..=MAX_TAG) { |
762 | | let value = Bytes::from(value); |
763 | | super::test::check_type::<Bytes, Bytes>(value, tag, WireType::LengthDelimited, |
764 | | encode, merge, encoded_len)?; |
765 | | } |
766 | | |
767 | | #[test] |
768 | | fn check_repeated_vec(value: Vec<Vec<u8>>, tag in MIN_TAG..=MAX_TAG) { |
769 | | super::test::check_collection_type(value, tag, WireType::LengthDelimited, |
770 | | encode_repeated, merge_repeated, |
771 | | encoded_len_repeated)?; |
772 | | } |
773 | | |
774 | | #[test] |
775 | | fn check_repeated_bytes(value: Vec<Vec<u8>>, tag in MIN_TAG..=MAX_TAG) { |
776 | | let value = value.into_iter().map(Bytes::from).collect(); |
777 | | super::test::check_collection_type(value, tag, WireType::LengthDelimited, |
778 | | encode_repeated, merge_repeated, |
779 | | encoded_len_repeated)?; |
780 | | } |
781 | | } |
782 | | } |
783 | | } |
784 | | |
785 | | pub mod message { |
786 | | use super::*; |
787 | | |
788 | 0 | pub fn encode<M>(tag: u32, msg: &M, buf: &mut impl BufMut) |
789 | 0 | where |
790 | 0 | M: Message, |
791 | | { |
792 | 0 | encode_key(tag, WireType::LengthDelimited, buf); |
793 | 0 | encode_varint(msg.encoded_len() as u64, buf); |
794 | 0 | msg.encode_raw(buf); |
795 | 0 | } |
796 | | |
797 | 0 | pub fn merge<M, B>( |
798 | 0 | wire_type: WireType, |
799 | 0 | msg: &mut M, |
800 | 0 | buf: &mut B, |
801 | 0 | ctx: DecodeContext, |
802 | 0 | ) -> Result<(), DecodeError> |
803 | 0 | where |
804 | 0 | M: Message, |
805 | 0 | B: Buf, |
806 | | { |
807 | 0 | check_wire_type(WireType::LengthDelimited, wire_type)?; |
808 | 0 | ctx.limit_reached()?; |
809 | 0 | merge_loop( |
810 | 0 | msg, |
811 | 0 | buf, |
812 | 0 | ctx.enter_recursion(), |
813 | 0 | |msg: &mut M, buf: &mut B, ctx| { |
814 | 0 | let (tag, wire_type) = decode_key(buf)?; |
815 | 0 | msg.merge_field(tag, wire_type, buf, ctx) |
816 | 0 | }, |
817 | | ) |
818 | 0 | } |
819 | | |
820 | 0 | pub fn encode_repeated<M>(tag: u32, messages: &[M], buf: &mut impl BufMut) |
821 | 0 | where |
822 | 0 | M: Message, |
823 | | { |
824 | 0 | for msg in messages { |
825 | 0 | encode(tag, msg, buf); |
826 | 0 | } |
827 | 0 | } |
828 | | |
829 | 0 | pub fn merge_repeated<M>( |
830 | 0 | wire_type: WireType, |
831 | 0 | messages: &mut Vec<M>, |
832 | 0 | buf: &mut impl Buf, |
833 | 0 | ctx: DecodeContext, |
834 | 0 | ) -> Result<(), DecodeError> |
835 | 0 | where |
836 | 0 | M: Message + Default, |
837 | | { |
838 | 0 | check_wire_type(WireType::LengthDelimited, wire_type)?; |
839 | 0 | let mut msg = M::default(); |
840 | 0 | merge(WireType::LengthDelimited, &mut msg, buf, ctx)?; |
841 | 0 | messages.push(msg); |
842 | 0 | Ok(()) |
843 | 0 | } |
844 | | |
845 | | #[inline] |
846 | 0 | pub fn encoded_len<M>(tag: u32, msg: &M) -> usize |
847 | 0 | where |
848 | 0 | M: Message, |
849 | | { |
850 | 0 | let len = msg.encoded_len(); |
851 | 0 | key_len(tag) + encoded_len_varint(len as u64) + len |
852 | 0 | } |
853 | | |
854 | | #[inline] |
855 | 0 | pub fn encoded_len_repeated<M>(tag: u32, messages: &[M]) -> usize |
856 | 0 | where |
857 | 0 | M: Message, |
858 | | { |
859 | 0 | key_len(tag) * messages.len() |
860 | 0 | + messages |
861 | 0 | .iter() |
862 | 0 | .map(Message::encoded_len) |
863 | 0 | .map(|len| len + encoded_len_varint(len as u64)) |
864 | 0 | .sum::<usize>() |
865 | 0 | } |
866 | | } |
867 | | |
868 | | pub mod group { |
869 | | use crate::error::DecodeErrorKind; |
870 | | |
871 | | use super::*; |
872 | | |
873 | 0 | pub fn encode<M>(tag: u32, msg: &M, buf: &mut impl BufMut) |
874 | 0 | where |
875 | 0 | M: Message, |
876 | | { |
877 | 0 | encode_key(tag, WireType::StartGroup, buf); |
878 | 0 | msg.encode_raw(buf); |
879 | 0 | encode_key(tag, WireType::EndGroup, buf); |
880 | 0 | } |
881 | | |
882 | 0 | pub fn merge<M>( |
883 | 0 | tag: u32, |
884 | 0 | wire_type: WireType, |
885 | 0 | msg: &mut M, |
886 | 0 | buf: &mut impl Buf, |
887 | 0 | ctx: DecodeContext, |
888 | 0 | ) -> Result<(), DecodeError> |
889 | 0 | where |
890 | 0 | M: Message, |
891 | | { |
892 | 0 | check_wire_type(WireType::StartGroup, wire_type)?; |
893 | | |
894 | 0 | ctx.limit_reached()?; |
895 | | loop { |
896 | 0 | let (field_tag, field_wire_type) = decode_key(buf)?; |
897 | 0 | if field_wire_type == WireType::EndGroup { |
898 | 0 | if field_tag != tag { |
899 | 0 | return Err(DecodeErrorKind::UnexpectedEndGroupTag.into()); |
900 | 0 | } |
901 | 0 | return Ok(()); |
902 | 0 | } |
903 | | |
904 | 0 | M::merge_field(msg, field_tag, field_wire_type, buf, ctx.enter_recursion())?; |
905 | | } |
906 | 0 | } |
907 | | |
908 | 0 | pub fn encode_repeated<M>(tag: u32, messages: &[M], buf: &mut impl BufMut) |
909 | 0 | where |
910 | 0 | M: Message, |
911 | | { |
912 | 0 | for msg in messages { |
913 | 0 | encode(tag, msg, buf); |
914 | 0 | } |
915 | 0 | } |
916 | | |
917 | 0 | pub fn merge_repeated<M>( |
918 | 0 | tag: u32, |
919 | 0 | wire_type: WireType, |
920 | 0 | messages: &mut Vec<M>, |
921 | 0 | buf: &mut impl Buf, |
922 | 0 | ctx: DecodeContext, |
923 | 0 | ) -> Result<(), DecodeError> |
924 | 0 | where |
925 | 0 | M: Message + Default, |
926 | | { |
927 | 0 | check_wire_type(WireType::StartGroup, wire_type)?; |
928 | 0 | let mut msg = M::default(); |
929 | 0 | merge(tag, WireType::StartGroup, &mut msg, buf, ctx)?; |
930 | 0 | messages.push(msg); |
931 | 0 | Ok(()) |
932 | 0 | } |
933 | | |
934 | | #[inline] |
935 | 0 | pub fn encoded_len<M>(tag: u32, msg: &M) -> usize |
936 | 0 | where |
937 | 0 | M: Message, |
938 | | { |
939 | 0 | 2 * key_len(tag) + msg.encoded_len() |
940 | 0 | } |
941 | | |
942 | | #[inline] |
943 | 0 | pub fn encoded_len_repeated<M>(tag: u32, messages: &[M]) -> usize |
944 | 0 | where |
945 | 0 | M: Message, |
946 | | { |
947 | 0 | 2 * key_len(tag) * messages.len() + messages.iter().map(Message::encoded_len).sum::<usize>() |
948 | 0 | } |
949 | | } |
950 | | |
951 | | /// Rust doesn't have a `Map` trait, so macros are currently the best way to be |
952 | | /// generic over `HashMap` and `BTreeMap`. |
953 | | macro_rules! map { |
954 | | ($map_ty:ident) => { |
955 | | use crate::encoding::*; |
956 | | use core::hash::Hash; |
957 | | |
958 | | /// Generic protobuf map encode function. |
959 | 0 | pub fn encode<K, V, B, KE, KL, VE, VL>( |
960 | 0 | key_encode: KE, |
961 | 0 | key_encoded_len: KL, |
962 | 0 | val_encode: VE, |
963 | 0 | val_encoded_len: VL, |
964 | 0 | tag: u32, |
965 | 0 | values: &$map_ty<K, V>, |
966 | 0 | buf: &mut B, |
967 | 0 | ) where |
968 | 0 | K: Default + Eq + Hash + Ord, |
969 | 0 | V: Default + PartialEq, |
970 | 0 | B: BufMut, |
971 | 0 | KE: Fn(u32, &K, &mut B), |
972 | 0 | KL: Fn(u32, &K) -> usize, |
973 | 0 | VE: Fn(u32, &V, &mut B), |
974 | 0 | VL: Fn(u32, &V) -> usize, |
975 | | { |
976 | 0 | encode_with_default( |
977 | 0 | key_encode, |
978 | 0 | key_encoded_len, |
979 | 0 | val_encode, |
980 | 0 | val_encoded_len, |
981 | 0 | &V::default(), |
982 | 0 | tag, |
983 | 0 | values, |
984 | 0 | buf, |
985 | | ) |
986 | 0 | } Unexecuted instantiation: prost::encoding::hash_map::encode::<_, _, _, _, _, _, _> Unexecuted instantiation: prost::encoding::btree_map::encode::<_, _, _, _, _, _, _> |
987 | | |
988 | | /// Generic protobuf map merge function. |
989 | 0 | pub fn merge<K, V, B, KM, VM>( |
990 | 0 | key_merge: KM, |
991 | 0 | val_merge: VM, |
992 | 0 | values: &mut $map_ty<K, V>, |
993 | 0 | buf: &mut B, |
994 | 0 | ctx: DecodeContext, |
995 | 0 | ) -> Result<(), DecodeError> |
996 | 0 | where |
997 | 0 | K: Default + Eq + Hash + Ord, |
998 | 0 | V: Default, |
999 | 0 | B: Buf, |
1000 | 0 | KM: Fn(WireType, &mut K, &mut B, DecodeContext) -> Result<(), DecodeError>, |
1001 | 0 | VM: Fn(WireType, &mut V, &mut B, DecodeContext) -> Result<(), DecodeError>, |
1002 | | { |
1003 | 0 | merge_with_default(key_merge, val_merge, V::default(), values, buf, ctx) |
1004 | 0 | } Unexecuted instantiation: prost::encoding::hash_map::merge::<_, _, _, _, _> Unexecuted instantiation: prost::encoding::btree_map::merge::<_, _, _, _, _> |
1005 | | |
1006 | | /// Generic protobuf map encode function. |
1007 | 0 | pub fn encoded_len<K, V, KL, VL>( |
1008 | 0 | key_encoded_len: KL, |
1009 | 0 | val_encoded_len: VL, |
1010 | 0 | tag: u32, |
1011 | 0 | values: &$map_ty<K, V>, |
1012 | 0 | ) -> usize |
1013 | 0 | where |
1014 | 0 | K: Default + Eq + Hash + Ord, |
1015 | 0 | V: Default + PartialEq, |
1016 | 0 | KL: Fn(u32, &K) -> usize, |
1017 | 0 | VL: Fn(u32, &V) -> usize, |
1018 | | { |
1019 | 0 | encoded_len_with_default(key_encoded_len, val_encoded_len, &V::default(), tag, values) |
1020 | 0 | } Unexecuted instantiation: prost::encoding::hash_map::encoded_len::<_, _, _, _> Unexecuted instantiation: prost::encoding::btree_map::encoded_len::<_, _, _, _> |
1021 | | |
1022 | | /// Generic protobuf map encode function with an overridden value default. |
1023 | | /// |
1024 | | /// This is necessary because enumeration values can have a default value other |
1025 | | /// than 0 in proto2. |
1026 | 0 | pub fn encode_with_default<K, V, B, KE, KL, VE, VL>( |
1027 | 0 | key_encode: KE, |
1028 | 0 | key_encoded_len: KL, |
1029 | 0 | val_encode: VE, |
1030 | 0 | val_encoded_len: VL, |
1031 | 0 | val_default: &V, |
1032 | 0 | tag: u32, |
1033 | 0 | values: &$map_ty<K, V>, |
1034 | 0 | buf: &mut B, |
1035 | 0 | ) where |
1036 | 0 | K: Default + Eq + Hash + Ord, |
1037 | 0 | V: PartialEq, |
1038 | 0 | B: BufMut, |
1039 | 0 | KE: Fn(u32, &K, &mut B), |
1040 | 0 | KL: Fn(u32, &K) -> usize, |
1041 | 0 | VE: Fn(u32, &V, &mut B), |
1042 | 0 | VL: Fn(u32, &V) -> usize, |
1043 | | { |
1044 | 0 | for (key, val) in values.iter() { |
1045 | 0 | let skip_key = key == &K::default(); |
1046 | 0 | let skip_val = val == val_default; |
1047 | | |
1048 | 0 | let len = (if skip_key { 0 } else { key_encoded_len(1, key) }) |
1049 | 0 | + (if skip_val { 0 } else { val_encoded_len(2, val) }); |
1050 | | |
1051 | 0 | encode_key(tag, WireType::LengthDelimited, buf); |
1052 | 0 | encode_varint(len as u64, buf); |
1053 | 0 | if !skip_key { |
1054 | 0 | key_encode(1, key, buf); |
1055 | 0 | } |
1056 | 0 | if !skip_val { |
1057 | 0 | val_encode(2, val, buf); |
1058 | 0 | } |
1059 | | } |
1060 | 0 | } Unexecuted instantiation: prost::encoding::hash_map::encode_with_default::<_, _, _, _, _, _, _> Unexecuted instantiation: prost::encoding::btree_map::encode_with_default::<_, _, _, _, _, _, _> |
1061 | | |
1062 | | /// Generic protobuf map merge function with an overridden value default. |
1063 | | /// |
1064 | | /// This is necessary because enumeration values can have a default value other |
1065 | | /// than 0 in proto2. |
1066 | 0 | pub fn merge_with_default<K, V, B, KM, VM>( |
1067 | 0 | key_merge: KM, |
1068 | 0 | val_merge: VM, |
1069 | 0 | val_default: V, |
1070 | 0 | values: &mut $map_ty<K, V>, |
1071 | 0 | buf: &mut B, |
1072 | 0 | ctx: DecodeContext, |
1073 | 0 | ) -> Result<(), DecodeError> |
1074 | 0 | where |
1075 | 0 | K: Default + Eq + Hash + Ord, |
1076 | 0 | B: Buf, |
1077 | 0 | KM: Fn(WireType, &mut K, &mut B, DecodeContext) -> Result<(), DecodeError>, |
1078 | 0 | VM: Fn(WireType, &mut V, &mut B, DecodeContext) -> Result<(), DecodeError>, |
1079 | | { |
1080 | 0 | let mut key = Default::default(); |
1081 | 0 | let mut val = val_default; |
1082 | 0 | ctx.limit_reached()?; |
1083 | 0 | merge_loop( |
1084 | 0 | &mut (&mut key, &mut val), |
1085 | 0 | buf, |
1086 | 0 | ctx.enter_recursion(), |
1087 | 0 | |&mut (ref mut key, ref mut val), buf, ctx| { |
1088 | 0 | let (tag, wire_type) = decode_key(buf)?; |
1089 | 0 | match tag { |
1090 | 0 | 1 => key_merge(wire_type, key, buf, ctx), |
1091 | 0 | 2 => val_merge(wire_type, val, buf, ctx), |
1092 | 0 | _ => skip_field(wire_type, tag, buf, ctx), |
1093 | | } |
1094 | 0 | }, Unexecuted instantiation: prost::encoding::hash_map::merge_with_default::<_, _, _, _, _>::{closure#0}Unexecuted instantiation: prost::encoding::btree_map::merge_with_default::<_, _, _, _, _>::{closure#0} |
1095 | 0 | )?; |
1096 | 0 | values.insert(key, val); |
1097 | | |
1098 | 0 | Ok(()) |
1099 | 0 | } Unexecuted instantiation: prost::encoding::hash_map::merge_with_default::<_, _, _, _, _> Unexecuted instantiation: prost::encoding::btree_map::merge_with_default::<_, _, _, _, _> |
1100 | | |
1101 | | /// Generic protobuf map encode function with an overridden value default. |
1102 | | /// |
1103 | | /// This is necessary because enumeration values can have a default value other |
1104 | | /// than 0 in proto2. |
1105 | 0 | pub fn encoded_len_with_default<K, V, KL, VL>( |
1106 | 0 | key_encoded_len: KL, |
1107 | 0 | val_encoded_len: VL, |
1108 | 0 | val_default: &V, |
1109 | 0 | tag: u32, |
1110 | 0 | values: &$map_ty<K, V>, |
1111 | 0 | ) -> usize |
1112 | 0 | where |
1113 | 0 | K: Default + Eq + Hash + Ord, |
1114 | 0 | V: PartialEq, |
1115 | 0 | KL: Fn(u32, &K) -> usize, |
1116 | 0 | VL: Fn(u32, &V) -> usize, |
1117 | | { |
1118 | 0 | key_len(tag) * values.len() |
1119 | 0 | + values |
1120 | 0 | .iter() |
1121 | 0 | .map(|(key, val)| { |
1122 | 0 | let len = (if key == &K::default() { |
1123 | 0 | 0 |
1124 | | } else { |
1125 | 0 | key_encoded_len(1, key) |
1126 | 0 | }) + (if val == val_default { |
1127 | 0 | 0 |
1128 | | } else { |
1129 | 0 | val_encoded_len(2, val) |
1130 | | }); |
1131 | 0 | encoded_len_varint(len as u64) + len |
1132 | 0 | }) Unexecuted instantiation: prost::encoding::hash_map::encoded_len_with_default::<_, _, _, _>::{closure#0}Unexecuted instantiation: prost::encoding::btree_map::encoded_len_with_default::<_, _, _, _>::{closure#0} |
1133 | 0 | .sum::<usize>() |
1134 | 0 | } Unexecuted instantiation: prost::encoding::hash_map::encoded_len_with_default::<_, _, _, _> Unexecuted instantiation: prost::encoding::btree_map::encoded_len_with_default::<_, _, _, _> |
1135 | | }; |
1136 | | } |
1137 | | |
1138 | | #[cfg(feature = "std")] |
1139 | | pub mod hash_map { |
1140 | | use std::collections::HashMap; |
1141 | | map!(HashMap); |
1142 | | } |
1143 | | |
1144 | | pub mod btree_map { |
1145 | | map!(BTreeMap); |
1146 | | } |
1147 | | |
1148 | | #[cfg(test)] |
1149 | | mod test { |
1150 | | #[cfg(not(feature = "std"))] |
1151 | | use alloc::string::ToString; |
1152 | | use core::borrow::Borrow; |
1153 | | use core::fmt::Debug; |
1154 | | |
1155 | | use ::bytes::BytesMut; |
1156 | | use proptest::{prelude::*, test_runner::TestCaseResult}; |
1157 | | |
1158 | | use super::*; |
1159 | | |
1160 | | pub fn check_type<T, B>( |
1161 | | value: T, |
1162 | | tag: u32, |
1163 | | wire_type: WireType, |
1164 | | encode: fn(u32, &B, &mut BytesMut), |
1165 | | merge: fn(WireType, &mut T, &mut Bytes, DecodeContext) -> Result<(), DecodeError>, |
1166 | | encoded_len: fn(u32, &B) -> usize, |
1167 | | ) -> TestCaseResult |
1168 | | where |
1169 | | T: Debug + Default + PartialEq + Borrow<B>, |
1170 | | B: ?Sized, |
1171 | | { |
1172 | | prop_assume!((MIN_TAG..=MAX_TAG).contains(&tag)); |
1173 | | |
1174 | | let expected_len = encoded_len(tag, value.borrow()); |
1175 | | |
1176 | | let mut buf = BytesMut::with_capacity(expected_len); |
1177 | | encode(tag, value.borrow(), &mut buf); |
1178 | | |
1179 | | let mut buf = buf.freeze(); |
1180 | | |
1181 | | prop_assert_eq!( |
1182 | | buf.remaining(), |
1183 | | expected_len, |
1184 | | "encoded_len wrong; expected: {}, actual: {}", |
1185 | | expected_len, |
1186 | | buf.remaining() |
1187 | | ); |
1188 | | |
1189 | | if !buf.has_remaining() { |
1190 | | // Short circuit for empty packed values. |
1191 | | return Ok(()); |
1192 | | } |
1193 | | |
1194 | | let (decoded_tag, decoded_wire_type) = |
1195 | | decode_key(&mut buf).map_err(|error| TestCaseError::fail(error.to_string()))?; |
1196 | | prop_assert_eq!( |
1197 | | tag, |
1198 | | decoded_tag, |
1199 | | "decoded tag does not match; expected: {}, actual: {}", |
1200 | | tag, |
1201 | | decoded_tag |
1202 | | ); |
1203 | | |
1204 | | prop_assert_eq!( |
1205 | | wire_type, |
1206 | | decoded_wire_type, |
1207 | | "decoded wire type does not match; expected: {:?}, actual: {:?}", |
1208 | | wire_type, |
1209 | | decoded_wire_type, |
1210 | | ); |
1211 | | |
1212 | | match wire_type { |
1213 | | WireType::SixtyFourBit if buf.remaining() != 8 => Err(TestCaseError::fail(format!( |
1214 | | "64bit wire type illegal remaining: {}, tag: {}", |
1215 | | buf.remaining(), |
1216 | | tag |
1217 | | ))), |
1218 | | WireType::ThirtyTwoBit if buf.remaining() != 4 => Err(TestCaseError::fail(format!( |
1219 | | "32bit wire type illegal remaining: {}, tag: {}", |
1220 | | buf.remaining(), |
1221 | | tag |
1222 | | ))), |
1223 | | _ => Ok(()), |
1224 | | }?; |
1225 | | |
1226 | | let mut roundtrip_value = T::default(); |
1227 | | merge( |
1228 | | wire_type, |
1229 | | &mut roundtrip_value, |
1230 | | &mut buf, |
1231 | | DecodeContext::default(), |
1232 | | ) |
1233 | | .map_err(|error| TestCaseError::fail(error.to_string()))?; |
1234 | | |
1235 | | prop_assert!( |
1236 | | !buf.has_remaining(), |
1237 | | "expected buffer to be empty, remaining: {}", |
1238 | | buf.remaining() |
1239 | | ); |
1240 | | |
1241 | | prop_assert_eq!(value, roundtrip_value); |
1242 | | |
1243 | | Ok(()) |
1244 | | } |
1245 | | |
1246 | | pub fn check_collection_type<T, B, E, M, L>( |
1247 | | value: T, |
1248 | | tag: u32, |
1249 | | wire_type: WireType, |
1250 | | encode: E, |
1251 | | mut merge: M, |
1252 | | encoded_len: L, |
1253 | | ) -> TestCaseResult |
1254 | | where |
1255 | | T: Debug + Default + PartialEq + Borrow<B>, |
1256 | | B: ?Sized, |
1257 | | E: FnOnce(u32, &B, &mut BytesMut), |
1258 | | M: FnMut(WireType, &mut T, &mut Bytes, DecodeContext) -> Result<(), DecodeError>, |
1259 | | L: FnOnce(u32, &B) -> usize, |
1260 | | { |
1261 | | prop_assume!((MIN_TAG..=MAX_TAG).contains(&tag)); |
1262 | | |
1263 | | let expected_len = encoded_len(tag, value.borrow()); |
1264 | | |
1265 | | let mut buf = BytesMut::with_capacity(expected_len); |
1266 | | encode(tag, value.borrow(), &mut buf); |
1267 | | |
1268 | | let mut buf = buf.freeze(); |
1269 | | |
1270 | | prop_assert_eq!( |
1271 | | buf.remaining(), |
1272 | | expected_len, |
1273 | | "encoded_len wrong; expected: {}, actual: {}", |
1274 | | expected_len, |
1275 | | buf.remaining() |
1276 | | ); |
1277 | | |
1278 | | let mut roundtrip_value = Default::default(); |
1279 | | while buf.has_remaining() { |
1280 | | let (decoded_tag, decoded_wire_type) = |
1281 | | decode_key(&mut buf).map_err(|error| TestCaseError::fail(error.to_string()))?; |
1282 | | |
1283 | | prop_assert_eq!( |
1284 | | tag, |
1285 | | decoded_tag, |
1286 | | "decoded tag does not match; expected: {}, actual: {}", |
1287 | | tag, |
1288 | | decoded_tag |
1289 | | ); |
1290 | | |
1291 | | prop_assert_eq!( |
1292 | | wire_type, |
1293 | | decoded_wire_type, |
1294 | | "decoded wire type does not match; expected: {:?}, actual: {:?}", |
1295 | | wire_type, |
1296 | | decoded_wire_type |
1297 | | ); |
1298 | | |
1299 | | merge( |
1300 | | wire_type, |
1301 | | &mut roundtrip_value, |
1302 | | &mut buf, |
1303 | | DecodeContext::default(), |
1304 | | ) |
1305 | | .map_err(|error| TestCaseError::fail(error.to_string()))?; |
1306 | | } |
1307 | | |
1308 | | prop_assert_eq!(value, roundtrip_value); |
1309 | | |
1310 | | Ok(()) |
1311 | | } |
1312 | | |
1313 | | #[test] |
1314 | | fn string_merge_invalid_utf8() { |
1315 | | let mut s = String::new(); |
1316 | | let buf = b"\x02\x80\x80"; |
1317 | | |
1318 | | let r = string::merge( |
1319 | | WireType::LengthDelimited, |
1320 | | &mut s, |
1321 | | &mut &buf[..], |
1322 | | DecodeContext::default(), |
1323 | | ); |
1324 | | r.expect_err("must be an error"); |
1325 | | assert!(s.is_empty()); |
1326 | | } |
1327 | | |
1328 | | /// This big bowl o' macro soup generates an encoding property test for each combination of map |
1329 | | /// type, scalar map key, and value type. |
1330 | | /// TODO: these tests take a long time to compile, can this be improved? |
1331 | | #[cfg(feature = "std")] |
1332 | | macro_rules! map_tests { |
1333 | | (keys: $keys:tt, |
1334 | | vals: $vals:tt) => { |
1335 | | mod hash_map { |
1336 | | map_tests!(@private HashMap, hash_map, $keys, $vals); |
1337 | | } |
1338 | | mod btree_map { |
1339 | | map_tests!(@private BTreeMap, btree_map, $keys, $vals); |
1340 | | } |
1341 | | }; |
1342 | | |
1343 | | (@private $map_type:ident, |
1344 | | $mod_name:ident, |
1345 | | [$(($key_ty:ty, $key_proto:ident)),*], |
1346 | | $vals:tt) => { |
1347 | | $( |
1348 | | mod $key_proto { |
1349 | | use std::collections::$map_type; |
1350 | | |
1351 | | use proptest::prelude::*; |
1352 | | |
1353 | | use crate::encoding::*; |
1354 | | use crate::encoding::test::check_collection_type; |
1355 | | |
1356 | | map_tests!(@private $map_type, $mod_name, ($key_ty, $key_proto), $vals); |
1357 | | } |
1358 | | )* |
1359 | | }; |
1360 | | |
1361 | | (@private $map_type:ident, |
1362 | | $mod_name:ident, |
1363 | | ($key_ty:ty, $key_proto:ident), |
1364 | | [$(($val_ty:ty, $val_proto:ident)),*]) => { |
1365 | | $( |
1366 | | proptest! { |
1367 | | #[test] |
1368 | | fn $val_proto(values: $map_type<$key_ty, $val_ty>, tag in MIN_TAG..=MAX_TAG) { |
1369 | | check_collection_type(values, tag, WireType::LengthDelimited, |
1370 | | |tag, values, buf| { |
1371 | | $mod_name::encode($key_proto::encode, |
1372 | | $key_proto::encoded_len, |
1373 | | $val_proto::encode, |
1374 | | $val_proto::encoded_len, |
1375 | | tag, |
1376 | | values, |
1377 | | buf) |
1378 | | }, |
1379 | | |wire_type, values, buf, ctx| { |
1380 | | check_wire_type(WireType::LengthDelimited, wire_type)?; |
1381 | | $mod_name::merge($key_proto::merge, |
1382 | | $val_proto::merge, |
1383 | | values, |
1384 | | buf, |
1385 | | ctx) |
1386 | | }, |
1387 | | |tag, values| { |
1388 | | $mod_name::encoded_len($key_proto::encoded_len, |
1389 | | $val_proto::encoded_len, |
1390 | | tag, |
1391 | | values) |
1392 | | })?; |
1393 | | } |
1394 | | } |
1395 | | )* |
1396 | | }; |
1397 | | } |
1398 | | |
1399 | | #[cfg(feature = "std")] |
1400 | | map_tests!(keys: [ |
1401 | | (i32, int32), |
1402 | | (i64, int64), |
1403 | | (u32, uint32), |
1404 | | (u64, uint64), |
1405 | | (i32, sint32), |
1406 | | (i64, sint64), |
1407 | | (u32, fixed32), |
1408 | | (u64, fixed64), |
1409 | | (i32, sfixed32), |
1410 | | (i64, sfixed64), |
1411 | | (bool, bool), |
1412 | | (String, string) |
1413 | | ], |
1414 | | vals: [ |
1415 | | (f32, float), |
1416 | | (f64, double), |
1417 | | (i32, int32), |
1418 | | (i64, int64), |
1419 | | (u32, uint32), |
1420 | | (u64, uint64), |
1421 | | (i32, sint32), |
1422 | | (i64, sint64), |
1423 | | (u32, fixed32), |
1424 | | (u64, fixed64), |
1425 | | (i32, sfixed32), |
1426 | | (i64, sfixed64), |
1427 | | (bool, bool), |
1428 | | (String, string), |
1429 | | (Vec<u8>, bytes) |
1430 | | ]); |
1431 | | |
1432 | | #[test] |
1433 | | /// `decode_varint` accepts a `Buf`, which can be multiple concatenated buffers. |
1434 | | /// This test ensures that future optimizations don't break the |
1435 | | /// `decode_varint` for non-continuous memory. |
1436 | | fn split_varint_decoding() { |
1437 | | let mut test_values = Vec::<u64>::with_capacity(10 * 2); |
1438 | | test_values.push(128); |
1439 | | for i in 2..9 { |
1440 | | test_values.push((1 << (7 * i)) - 1); |
1441 | | test_values.push(1 << (7 * i)); |
1442 | | } |
1443 | | |
1444 | | for v in test_values { |
1445 | | let mut buf = BytesMut::with_capacity(10); |
1446 | | encode_varint(v, &mut buf); |
1447 | | let half_len = buf.len() / 2; |
1448 | | let len = buf.len(); |
1449 | | // this weird sequence here splits the buffer into two instances of Bytes |
1450 | | // which we then stitch together with `bytes::buf::Buf::chain` |
1451 | | // which ensures the varint bytes are not in a single chunk |
1452 | | let b2 = buf.split_off(half_len); |
1453 | | let mut c = buf.chain(b2); |
1454 | | |
1455 | | // make sure all the bytes are inside |
1456 | | assert_eq!(c.remaining(), len); |
1457 | | // make sure the first chunk is split as we expected |
1458 | | assert_eq!(c.chunk().len(), half_len); |
1459 | | assert_eq!(v, decode_varint(&mut c).unwrap()); |
1460 | | } |
1461 | | } |
1462 | | } |