protobuf_core/field.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-level I/O utilities for Protocol Buffers
16//!
17//! This module provides primitive utilities for reading and writing raw protobuf fields.
18//! These are building blocks for constructing higher-level parsers and serializers,
19//! not a complete message parser or serializer.
20//!
21//! ## Core Types
22//!
23//! The `Field` and `FieldValue` types are always available when this module is enabled.
24//!
25//! ## Reading (Deserialization)
26//!
27//! Available when the `read` feature is enabled.
28//!
29//! The utilities read fields sequentially from input sources that implement `std::io::Read`,
30//! returning raw field values (varint bytes, fixed-width bytes, or length-delimited bytes)
31//! without interpretation of the semantic meaning.
32//!
33//! ## Writing (Serialization)
34//!
35//! Available when the `write` feature is enabled.
36//!
37//! The utilities write fields to output targets that implement `std::io::Write`,
38//! encoding field numbers, wire types, and values into the protobuf wire format.
39
40use crate::field_number::FieldNumber;
41use crate::tag::Tag;
42use crate::varint::Varint;
43use crate::wire_format::WireType;
44
45#[cfg(feature = "read")]
46pub(crate) mod read;
47
48#[cfg(feature = "write")]
49pub(crate) mod write;
50
51// Re-export read functionality
52#[cfg(feature = "read")]
53pub use self::read::{
54 AsRefExtProtobuf, IteratorExtProtobuf, ProtobufFieldIterator, ProtobufFieldIteratorFromBytes,
55 ProtobufFieldSliceIterator, ReadExtProtobuf, TryIteratorExtProtobuf,
56};
57
58// Re-export write functionality
59#[cfg(feature = "write")]
60pub use self::write::WriteExtProtobuf;
61
62/// A raw field value read from the wire
63///
64/// This represents the raw bytes of a field value without semantic interpretation.
65/// The caller is responsible for converting these raw values to the appropriate types
66/// based on the field's schema definition.
67///
68/// `L` is the type for length-delimited values (Len variant).
69/// - For owned data (from `std::io::Read`): use `Vec<u8>`
70/// - For borrowed data (from slices): use `&'a [u8]`
71#[derive(Debug, Clone, PartialEq)]
72pub enum FieldValue<L> {
73 /// Variable-width integers (`Int32`, `Int64`, `UInt32`, `UInt64`, `SInt32`, `SInt64`, `Bool`, `Enum`)
74 Varint(Varint),
75 /// 32-bit fixed-width values (`Fixed32`, `SFixed32`, `Float`)
76 I32([u8; 4]),
77 /// 64-bit fixed-width values (`Fixed64`, `SFixed64`, `Double`)
78 I64([u8; 8]),
79 /// Length-delimited values (`String`, `Bytes`, embedded messages, packed repeated fields)
80 Len(L),
81}
82
83impl<L> FieldValue<L> {
84 // Varint constructors
85
86 /// Create a field value from a Varint
87 pub fn from_varint(varint: Varint) -> Self {
88 Self::Varint(varint)
89 }
90
91 /// Create a field value from a `UInt64` protobuf type
92 pub fn from_uint64(value: u64) -> Self {
93 Self::Varint(Varint::from_uint64(value))
94 }
95
96 /// Create a field value from a `UInt32` protobuf type
97 pub fn from_uint32(value: u32) -> Self {
98 Self::Varint(Varint::from_uint32(value))
99 }
100
101 /// Create a field value from a `SInt64` protobuf type (ZigZag encoded)
102 pub fn from_sint64(value: i64) -> Self {
103 Self::Varint(Varint::from_sint64(value))
104 }
105
106 /// Create a field value from a `SInt32` protobuf type (ZigZag encoded)
107 pub fn from_sint32(value: i32) -> Self {
108 Self::Varint(Varint::from_sint32(value))
109 }
110
111 /// Create a field value from an `Int64` protobuf type (non-ZigZag)
112 pub fn from_int64(value: i64) -> Self {
113 Self::Varint(Varint::from_int64(value))
114 }
115
116 /// Create a field value from an `Int32` protobuf type (non-ZigZag)
117 pub fn from_int32(value: i32) -> Self {
118 Self::Varint(Varint::from_int32(value))
119 }
120
121 /// Create a field value from a `Bool` protobuf type
122 pub fn from_bool(value: bool) -> Self {
123 Self::Varint(Varint::from_bool(value))
124 }
125
126 // Fixed-width constructors
127
128 /// Create a field value from a `Fixed32` protobuf type
129 pub fn from_fixed32(value: u32) -> Self {
130 Self::I32(value.to_le_bytes())
131 }
132
133 /// Create a field value from a `SFixed32` protobuf type
134 pub fn from_sfixed32(value: i32) -> Self {
135 Self::I32(value.to_le_bytes())
136 }
137
138 /// Create a field value from a `Float` protobuf type
139 pub fn from_float(value: f32) -> Self {
140 Self::I32(value.to_le_bytes())
141 }
142
143 /// Create a field value from a `Fixed64` protobuf type
144 pub fn from_fixed64(value: u64) -> Self {
145 Self::I64(value.to_le_bytes())
146 }
147
148 /// Create a field value from a `SFixed64` protobuf type
149 pub fn from_sfixed64(value: i64) -> Self {
150 Self::I64(value.to_le_bytes())
151 }
152
153 /// Create a field value from a `Double` protobuf type
154 pub fn from_double(value: f64) -> Self {
155 Self::I64(value.to_le_bytes())
156 }
157
158 /// Calculate the encoded size of this field value in bytes (excluding the tag)
159 ///
160 /// For Len values, this includes the length varint plus the data bytes.
161 pub fn encoded_size(&self) -> usize
162 where
163 L: AsRef<[u8]>,
164 {
165 match self {
166 Self::Varint(varint) => varint.varint_size(),
167 Self::I32(_) => 4,
168 Self::I64(_) => 8,
169 Self::Len(data) => {
170 let data_slice = data.as_ref();
171 let length = data_slice.len() as u64;
172 let length_varint = Varint::from_uint64(length);
173 length_varint.varint_size() + data_slice.len()
174 }
175 }
176 }
177}
178
179/// A raw field read from the wire
180///
181/// Contains the field number and the raw field value.
182/// The caller must interpret the value based on the message schema.
183///
184/// `L` is the type for length-delimited values (FieldValue::Len).
185/// For owned data (from `std::io::Read`): use `Vec<u8>`
186/// For borrowed data (from slices): use `&'a [u8]`
187#[derive(Debug, Clone, PartialEq)]
188pub struct Field<L> {
189 pub field_number: FieldNumber,
190 pub value: FieldValue<L>,
191}
192
193impl<L> Field<L> {
194 /// Create a new field with the given field number and value
195 pub fn new(field_number: FieldNumber, value: FieldValue<L>) -> Self {
196 Self {
197 field_number,
198 value,
199 }
200 }
201
202 /// Calculate the total encoded size of this field in bytes (tag + value)
203 pub fn encoded_size(&self) -> usize
204 where
205 L: AsRef<[u8]>,
206 {
207 // Tag size (field number shifted left by 3 bits to make room for wire type)
208 let wire_type = match &self.value {
209 FieldValue::Varint(_) => WireType::Varint,
210 FieldValue::I32(_) => WireType::Int32,
211 FieldValue::I64(_) => WireType::Int64,
212 FieldValue::Len(_) => WireType::Len,
213 };
214 let tag = Tag {
215 field_number: self.field_number,
216 wire_type,
217 };
218 let tag_varint = tag.to_encoded();
219 let tag_size = tag_varint.varint_size();
220
221 // Value size
222 let value_size = self.value.encoded_size();
223
224 tag_size + value_size
225 }
226}