protobuf_core/field/
write.rs

1// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Field writing utilities for Protocol Buffers
16//!
17//! This module provides low-level utilities for writing raw protobuf fields to byte streams.
18
19use crate::Result;
20use crate::field::{Field, FieldValue};
21use crate::tag::Tag;
22use crate::varint::{Varint, WriteExtVarint};
23use crate::wire_format::WireType;
24use ::std::io::Write;
25
26/// Extension trait for writing raw Protocol Buffer fields to `Write` types
27///
28/// This trait provides low-level utilities for writing fields to a byte stream.
29/// It is the counterpart to `ReadExtProtobuf` for serialization.
30pub trait WriteExtProtobuf {
31    /// Write a single raw protobuf field to the writer (tag + value)
32    ///
33    /// Returns the number of bytes written.
34    ///
35    /// # Example
36    /// ```
37    /// use ::protobuf_core::{WriteExtProtobuf, Field, FieldValue, FieldNumber};
38    ///
39    /// fn main() -> Result<(), Box<dyn ::std::error::Error>> {
40    ///     let mut buffer = Vec::new();
41    ///     
42    ///     let field: Field<Vec<u8>> = Field::new(
43    ///         FieldNumber::try_from(1)?,
44    ///         FieldValue::from_uint64(150)
45    ///     );
46    ///     
47    ///     buffer.write_protobuf_field(&field)?;
48    ///     assert_eq!(buffer, vec![0x08, 0x96, 0x01]); // field 1: 150
49    ///     Ok(())
50    /// }
51    /// ```
52    fn write_protobuf_field<L: AsRef<[u8]>>(&mut self, field: &Field<L>) -> Result<usize>;
53
54    /// Write multiple raw protobuf fields to the writer
55    ///
56    /// Returns the total number of bytes written.
57    ///
58    /// # Example
59    /// ```
60    /// use ::protobuf_core::{WriteExtProtobuf, Field, FieldValue, FieldNumber};
61    ///
62    /// fn main() -> Result<(), Box<dyn ::std::error::Error>> {
63    ///     let mut buffer = Vec::new();
64    ///     
65    ///     let fields = vec![
66    ///         Field::new(FieldNumber::try_from(1)?, FieldValue::from_uint64(150)),
67    ///         Field::new(FieldNumber::try_from(2)?, FieldValue::Len("Hello".to_string().into_bytes())),
68    ///     ];
69    ///     
70    ///     buffer.write_protobuf_fields(&fields)?;
71    ///     Ok(())
72    /// }
73    /// ```
74    fn write_protobuf_fields<'a, L: AsRef<[u8]> + 'a, I>(&mut self, fields: I) -> Result<usize>
75    where
76        I: IntoIterator<Item = &'a Field<L>>;
77}
78
79impl<W> WriteExtProtobuf for W
80where
81    W: Write,
82{
83    fn write_protobuf_field<L: AsRef<[u8]>>(&mut self, field: &Field<L>) -> Result<usize> {
84        let mut bytes_written = 0;
85
86        // Write tag
87        let wire_type = match &field.value {
88            FieldValue::Varint(_) => WireType::Varint,
89            FieldValue::I32(_) => WireType::Int32,
90            FieldValue::I64(_) => WireType::Int64,
91            FieldValue::Len(_) => WireType::Len,
92        };
93        let tag = Tag {
94            field_number: field.field_number,
95            wire_type,
96        };
97        let tag_varint = tag.to_encoded();
98        bytes_written += self.write_varint(&tag_varint)?;
99
100        // Write value
101        match &field.value {
102            FieldValue::Varint(varint) => {
103                bytes_written += self.write_varint(varint)?;
104            }
105            FieldValue::I32(bytes) => {
106                self.write_all(bytes)?;
107                bytes_written += 4;
108            }
109            FieldValue::I64(bytes) => {
110                self.write_all(bytes)?;
111                bytes_written += 8;
112            }
113            FieldValue::Len(data) => {
114                // Write length
115                let data_slice = data.as_ref();
116                let length_varint = Varint::from_uint64(data_slice.len() as u64);
117                bytes_written += self.write_varint(&length_varint)?;
118                // Write data
119                self.write_all(data_slice)?;
120                bytes_written += data_slice.len();
121            }
122        }
123
124        Ok(bytes_written)
125    }
126
127    fn write_protobuf_fields<'a, L: AsRef<[u8]> + 'a, I>(&mut self, fields: I) -> Result<usize>
128    where
129        I: IntoIterator<Item = &'a Field<L>>,
130    {
131        let mut total_bytes = 0;
132        for field in fields {
133            total_bytes += self.write_protobuf_field(field)?;
134        }
135        Ok(total_bytes)
136    }
137}
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142    use crate::field_number::FieldNumber;
143
144    #[test]
145    fn test_write_single_varint_field() {
146        let mut buffer = Vec::new();
147
148        let field: Field<Vec<u8>> = Field::new(
149            FieldNumber::try_from(1).unwrap(),
150            FieldValue::from_uint64(150),
151        );
152
153        let bytes_written = buffer.write_protobuf_field(&field).unwrap();
154        assert_eq!(bytes_written, 3); // tag (1 byte) + value (2 bytes)
155        assert_eq!(buffer, vec![0x08, 0x96, 0x01]); // field 1: 150
156    }
157
158    #[test]
159    fn test_write_len_field() {
160        let mut buffer = Vec::new();
161
162        let field: Field<Vec<u8>> = Field::new(
163            FieldNumber::try_from(2).unwrap(),
164            FieldValue::Len("Hel".to_string().into_bytes()),
165        );
166
167        buffer.write_protobuf_field(&field).unwrap();
168        assert_eq!(buffer, vec![0x12, 0x03, 0x48, 0x65, 0x6c]); // field 2: "Hel"
169    }
170
171    #[test]
172    fn test_write_i32_field() {
173        let mut buffer = Vec::new();
174
175        let field: Field<Vec<u8>> = Field::new(
176            FieldNumber::try_from(2).unwrap(),
177            FieldValue::from_fixed32(0x12345678),
178        );
179
180        buffer.write_protobuf_field(&field).unwrap();
181        assert_eq!(buffer, vec![0x15, 0x78, 0x56, 0x34, 0x12]); // field 2: 0x12345678
182    }
183
184    #[test]
185    fn test_write_i64_field() {
186        let mut buffer = Vec::new();
187
188        let field: Field<Vec<u8>> = Field::new(
189            FieldNumber::try_from(3).unwrap(),
190            FieldValue::from_fixed64(0x1234567890ABCDEF),
191        );
192
193        buffer.write_protobuf_field(&field).unwrap();
194        assert_eq!(
195            buffer,
196            vec![0x19, 0xEF, 0xCD, 0xAB, 0x90, 0x78, 0x56, 0x34, 0x12]
197        ); // field 3: 0x1234567890ABCDEF
198    }
199
200    #[test]
201    fn test_write_multiple_fields() {
202        let mut buffer = Vec::new();
203
204        let fields: Vec<Field<Vec<u8>>> = vec![
205            Field::new(
206                FieldNumber::try_from(1).unwrap(),
207                FieldValue::from_uint64(150),
208            ),
209            Field::new(
210                FieldNumber::try_from(2).unwrap(),
211                FieldValue::Len("Hel".to_string().into_bytes()),
212            ),
213        ];
214
215        buffer.write_protobuf_fields(&fields).unwrap();
216        assert_eq!(
217            buffer,
218            vec![
219                0x08, 0x96, 0x01, // field 1: 150
220                0x12, 0x03, 0x48, 0x65, 0x6c, // field 2: "Hel"
221            ]
222        );
223    }
224
225    #[test]
226    fn test_field_encoded_size() {
227        let field: Field<Vec<u8>> = Field::new(
228            FieldNumber::try_from(1).unwrap(),
229            FieldValue::from_uint64(150),
230        );
231        assert_eq!(field.encoded_size(), 3); // tag (1 byte) + value (2 bytes)
232
233        let field: Field<Vec<u8>> = Field::new(
234            FieldNumber::try_from(2).unwrap(),
235            FieldValue::Len("Hello".to_string().into_bytes()),
236        );
237        assert_eq!(field.encoded_size(), 7); // tag (1 byte) + length (1 byte) + data (5 bytes)
238    }
239
240    #[test]
241    fn test_fieldvalue_constructors() {
242        // Varint types
243        assert!(matches!(
244            FieldValue::<Vec<u8>>::from_uint64(42),
245            FieldValue::Varint(_)
246        ));
247        assert!(matches!(
248            FieldValue::<Vec<u8>>::from_uint32(42),
249            FieldValue::Varint(_)
250        ));
251        assert!(matches!(
252            FieldValue::<Vec<u8>>::from_sint64(-42),
253            FieldValue::Varint(_)
254        ));
255        assert!(matches!(
256            FieldValue::<Vec<u8>>::from_sint32(-42),
257            FieldValue::Varint(_)
258        ));
259        assert!(matches!(
260            FieldValue::<Vec<u8>>::from_int64(-42),
261            FieldValue::Varint(_)
262        ));
263        assert!(matches!(
264            FieldValue::<Vec<u8>>::from_int32(-42),
265            FieldValue::Varint(_)
266        ));
267        assert!(matches!(
268            FieldValue::<Vec<u8>>::from_bool(true),
269            FieldValue::Varint(_)
270        ));
271
272        // Fixed-width types
273        assert!(matches!(
274            FieldValue::<Vec<u8>>::from_fixed32(42),
275            FieldValue::I32(_)
276        ));
277        assert!(matches!(
278            FieldValue::<Vec<u8>>::from_sfixed32(-42),
279            FieldValue::I32(_)
280        ));
281        assert!(matches!(
282            FieldValue::<Vec<u8>>::from_float(3.14),
283            FieldValue::I32(_)
284        ));
285        assert!(matches!(
286            FieldValue::<Vec<u8>>::from_fixed64(42),
287            FieldValue::I64(_)
288        ));
289        assert!(matches!(
290            FieldValue::<Vec<u8>>::from_sfixed64(-42),
291            FieldValue::I64(_)
292        ));
293        assert!(matches!(
294            FieldValue::<Vec<u8>>::from_double(3.14),
295            FieldValue::I64(_)
296        ));
297
298        // Length-delimited types
299        assert!(matches!(FieldValue::Len(vec![1, 2, 3]), FieldValue::Len(_)));
300        assert!(matches!(
301            FieldValue::Len("test".to_string().into_bytes()),
302            FieldValue::Len(_)
303        ));
304    }
305
306    // Roundtrip tests (require both read and write features)
307    #[cfg(feature = "read")]
308    mod roundtrip_tests {
309        use super::*;
310        use crate::field::read::ReadExtProtobuf;
311
312        #[test]
313        fn test_roundtrip_varint() {
314            let mut buffer = Vec::new();
315
316            // Write
317            let original_field: Field<Vec<u8>> = Field::new(
318                FieldNumber::try_from(1).unwrap(),
319                FieldValue::from_uint64(150),
320            );
321            buffer.write_protobuf_field(&original_field).unwrap();
322
323            // Read
324            let reader = buffer.as_slice();
325            let fields: Vec<_> = reader
326                .read_protobuf_fields()
327                .collect::<::std::result::Result<Vec<_>, _>>()
328                .unwrap();
329            assert_eq!(fields.len(), 1);
330            assert_eq!(fields[0], original_field);
331        }
332
333        #[test]
334        fn test_roundtrip_string() {
335            let mut buffer = Vec::new();
336
337            // Write
338            let original_field: Field<Vec<u8>> = Field::new(
339                FieldNumber::try_from(2).unwrap(),
340                FieldValue::Len("Hello, Protocol Buffers!".to_string().into_bytes()),
341            );
342            buffer.write_protobuf_field(&original_field).unwrap();
343
344            // Read
345            let reader = buffer.as_slice();
346            let fields: Vec<_> = reader
347                .read_protobuf_fields()
348                .collect::<::std::result::Result<Vec<_>, _>>()
349                .unwrap();
350            assert_eq!(fields.len(), 1);
351            let read_field = &fields[0];
352
353            assert_eq!(*read_field, original_field);
354        }
355
356        #[test]
357        fn test_roundtrip_multiple_fields() {
358            let mut buffer = Vec::new();
359
360            // Write
361            let original_fields: Vec<Field<Vec<u8>>> = vec![
362                Field::new(
363                    FieldNumber::try_from(1).unwrap(),
364                    FieldValue::from_uint64(150),
365                ),
366                Field::new(
367                    FieldNumber::try_from(2).unwrap(),
368                    FieldValue::Len("Hello".to_string().into_bytes()),
369                ),
370                Field::new(
371                    FieldNumber::try_from(3).unwrap(),
372                    FieldValue::from_fixed32(0x12345678),
373                ),
374            ];
375            buffer.write_protobuf_fields(&original_fields).unwrap();
376
377            // Read
378            let reader = buffer.as_slice();
379            let read_fields: Vec<_> = reader
380                .read_protobuf_fields()
381                .collect::<::std::result::Result<Vec<_>, _>>()
382                .unwrap();
383
384            assert_eq!(read_fields, original_fields);
385        }
386    }
387}