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}