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 mod read;
47
48#[cfg(feature = "write")]
49pub mod write;
50
51// Re-export read functionality
52#[cfg(feature = "read")]
53pub use self::read::{ProtobufFieldIterator, ReadExtProtobuf};
54
55// Re-export write functionality
56#[cfg(feature = "write")]
57pub use self::write::WriteExtProtobuf;
58
59/// A raw field value read from the wire
60///
61/// This represents the raw bytes of a field value without semantic interpretation.
62/// The caller is responsible for converting these raw values to the appropriate types
63/// based on the field's schema definition.
64#[derive(Debug, Clone, PartialEq)]
65pub enum FieldValue {
66 /// Variable-width integers (Int32, Int64, UInt32, UInt64, SInt32, SInt64, Bool, Enum)
67 Varint(Varint),
68 /// 32-bit fixed-width values (Fixed32, SFixed32, Float)
69 I32([u8; 4]),
70 /// 64-bit fixed-width values (Fixed64, SFixed64, Double)
71 I64([u8; 8]),
72 /// Length-delimited values (String, Bytes, embedded messages, packed repeated fields)
73 Len(Vec<u8>),
74}
75
76impl FieldValue {
77 // Varint constructors
78
79 /// Create a field value from a Varint
80 pub fn from_varint(varint: Varint) -> Self {
81 Self::Varint(varint)
82 }
83
84 /// Create a field value from a UInt64 protobuf type
85 pub fn from_uint64(value: u64) -> Self {
86 Self::Varint(Varint::from_uint64(value))
87 }
88
89 /// Create a field value from a UInt32 protobuf type
90 pub fn from_uint32(value: u32) -> Self {
91 Self::Varint(Varint::from_uint32(value))
92 }
93
94 /// Create a field value from a SInt64 protobuf type (ZigZag encoded)
95 pub fn from_sint64(value: i64) -> Self {
96 Self::Varint(Varint::from_sint64(value))
97 }
98
99 /// Create a field value from a SInt32 protobuf type (ZigZag encoded)
100 pub fn from_sint32(value: i32) -> Self {
101 Self::Varint(Varint::from_sint32(value))
102 }
103
104 /// Create a field value from an Int64 protobuf type (non-ZigZag)
105 pub fn from_int64(value: i64) -> Self {
106 Self::Varint(Varint::from_int64(value))
107 }
108
109 /// Create a field value from an Int32 protobuf type (non-ZigZag)
110 pub fn from_int32(value: i32) -> Self {
111 Self::Varint(Varint::from_int32(value))
112 }
113
114 /// Create a field value from a Bool protobuf type
115 pub fn from_bool(value: bool) -> Self {
116 Self::Varint(Varint::from_bool(value))
117 }
118
119 // Fixed-width constructors
120
121 /// Create a field value from a Fixed32 protobuf type
122 pub fn from_fixed32(value: u32) -> Self {
123 Self::I32(value.to_le_bytes())
124 }
125
126 /// Create a field value from a SFixed32 protobuf type
127 pub fn from_sfixed32(value: i32) -> Self {
128 Self::I32(value.to_le_bytes())
129 }
130
131 /// Create a field value from a Float protobuf type
132 pub fn from_float(value: f32) -> Self {
133 Self::I32(value.to_le_bytes())
134 }
135
136 /// Create a field value from a Fixed64 protobuf type
137 pub fn from_fixed64(value: u64) -> Self {
138 Self::I64(value.to_le_bytes())
139 }
140
141 /// Create a field value from a SFixed64 protobuf type
142 pub fn from_sfixed64(value: i64) -> Self {
143 Self::I64(value.to_le_bytes())
144 }
145
146 /// Create a field value from a Double protobuf type
147 pub fn from_double(value: f64) -> Self {
148 Self::I64(value.to_le_bytes())
149 }
150
151 // Length-delimited constructors
152
153 /// Create a field value from raw bytes (Bytes protobuf type)
154 pub fn from_bytes(data: Vec<u8>) -> Self {
155 Self::Len(data)
156 }
157
158 /// Create a field value from a String protobuf type
159 pub fn from_string(s: String) -> Self {
160 Self::Len(s.into_bytes())
161 }
162
163 /// Calculate the encoded size of this field value in bytes (excluding the tag)
164 ///
165 /// For Len values, this includes the length varint plus the data bytes.
166 pub fn encoded_size(&self) -> usize {
167 match self {
168 Self::Varint(varint) => varint.varint_size(),
169 Self::I32(_) => 4,
170 Self::I64(_) => 8,
171 Self::Len(data) => {
172 let length = data.len() as u64;
173 let length_varint = Varint::from_uint64(length);
174 length_varint.varint_size() + data.len()
175 }
176 }
177 }
178}
179
180/// A raw field read from the wire
181///
182/// Contains the field number and the raw field value.
183/// The caller must interpret the value based on the message schema.
184#[derive(Debug, Clone, PartialEq)]
185pub struct Field {
186 pub field_number: FieldNumber,
187 pub value: FieldValue,
188}
189
190impl Field {
191 /// Create a new field with the given field number and value
192 pub fn new(field_number: FieldNumber, value: FieldValue) -> Self {
193 Self {
194 field_number,
195 value,
196 }
197 }
198
199 /// Calculate the total encoded size of this field in bytes (tag + value)
200 pub fn encoded_size(&self) -> usize {
201 // Tag size (field number shifted left by 3 bits to make room for wire type)
202 let wire_type = match &self.value {
203 FieldValue::Varint(_) => WireType::Varint,
204 FieldValue::I32(_) => WireType::Int32,
205 FieldValue::I64(_) => WireType::Int64,
206 FieldValue::Len(_) => WireType::Len,
207 };
208 let tag = Tag {
209 field_number: self.field_number,
210 wire_type,
211 };
212 let tag_varint = tag.to_encoded();
213 let tag_size = tag_varint.varint_size();
214
215 // Value size
216 let value_size = self.value.encoded_size();
217
218 tag_size + value_size
219 }
220}