protobuf_core/lib.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//! A primitive utility library for Protocol Buffers in Rust.
16//!
17//! # ⚠️ NOT A GOOGLE OFFICIAL PRODUCT
18//!
19//! **This library is not an official Google product.** Google provides its own Protocol Buffers
20//! implementation for Rust (see [protocolbuffers/protobuf](https://github.com/protocolbuffers/protobuf)
21//! and official Rust support). This project is an **independent, community-maintained** library.
22//!
23//! ---
24//!
25//! This library provides common definitions, constants, enums, and basic logic for implementing
26//! Protocol Buffers. It is designed to minimize entry barriers for developers who want to
27//! implement Protocol Buffers functionality.
28//!
29//! ## Overview
30//!
31//! This library provides **building blocks** for implementing Protocol Buffers, not a complete
32//! message parser or serializer. It focuses on:
33//!
34//! - **Low-level primitives**: Raw field I/O without semantic interpretation
35//! - **Flexibility**: Support for both owned and borrowed data
36//! - **Minimal dependencies**: Only depends on `thiserror` for error handling
37//! - **Clear API**: Trait-based extension methods following Rust conventions
38//!
39//! ## Quick Start
40//!
41//! ### Reading Fields
42//!
43//! This library provides multiple ways to read protobuf fields from different sources:
44//!
45//! ```rust
46//! use protobuf_core::{Field, IteratorExtProtobuf, AsRefExtProtobuf};
47//!
48//! // From a byte iterator - returns Field<Vec<u8>> (Len values are Vec<u8>)
49//! let bytes = vec![0x08, 0x96, 0x01]; // field 1: 150
50//! let fields: Vec<Field<Vec<u8>>> = bytes
51//! .into_iter()
52//! .protobuf_fields()
53//! .collect::<Result<Vec<Field<Vec<u8>>>, _>>()
54//! .unwrap();
55//!
56//! // From a slice - returns Field<&[u8]> (Len values are &[u8], zero-copy)
57//! let slice: &[u8] = &[0x08, 0x96, 0x01];
58//! let fields: Vec<Field<&[u8]>> = AsRefExtProtobuf::read_protobuf_fields(&slice)
59//! .collect::<Result<Vec<Field<&[u8]>>, _>>()
60//! .unwrap();
61//! ```
62//!
63//! ### Writing Fields
64//!
65//! ```rust
66//! use protobuf_core::{WriteExtProtobuf, Field, FieldValue, FieldNumber};
67//!
68//! let mut buffer = Vec::new();
69//! let field: Field<Vec<u8>> = Field::new(
70//! FieldNumber::try_from(1)?,
71//! FieldValue::from_uint64(150)
72//! );
73//! buffer.write_protobuf_field(&field)?;
74//! # Ok::<(), protobuf_core::ProtobufError>(())
75//! ```
76//!
77//! ## Core Types
78//!
79//! ### Fields
80//!
81//! - [`Field<L>`]: Represents a raw protobuf field with a field number and value.
82//! The `L` type parameter represents the type used for length-delimited values (e.g., `Vec<u8>`
83//! for owned data, `&'a [u8]` for borrowed data).
84//! - [`FieldValue<L>`]: Represents the raw value of a field. It can be:
85//! - `Varint(Varint)`: Variable-width integers (Int32, Int64, UInt32, UInt64, SInt32, SInt64,
86//! Bool, Enum)
87//! - `I32([u8; 4])`: 32-bit fixed-width values (Fixed32, SFixed32, Float)
88//! - `I64([u8; 8])`: 64-bit fixed-width values (Fixed64, SFixed64, Double)
89//! - `Len(L)`: Length-delimited values (String, Bytes, embedded messages, packed repeated
90//! fields)
91//!
92//! ### Basic Types
93//!
94//! - [`Tag`]: Represents a protobuf tag (field number + wire type)
95//! - [`Varint`]: Represents a deserialized varint value (8-byte internal
96//! representation)
97//! - [`FieldNumber`]: A validated field number (range: 1 to 2^29 - 1)
98//! - [`WireType`]: Represents the protobuf wire type (Varint, Int32, Int64,
99//! Len, StartGroup, EndGroup)
100//!
101//! ### Error Handling
102//!
103//! - [`ProtobufError`]: Unified error type for all protobuf operations
104//! - [`Result<T>`]: Type alias for `Result<T, ProtobufError>`
105//!
106//! ## Reading Traits
107//!
108//! The library provides several traits for reading protobuf fields from different sources:
109//!
110//! - [`IteratorExtProtobuf`]: Read fields from `Iterator<Item = u8>`
111//! - Output: [`Field<Vec<u8>>`] - Len values are owned `Vec<u8>`
112//! - [`TryIteratorExtProtobuf`]: Read fields from
113//! `Iterator<Item = Result<u8, E>>`
114//! - Output: [`Field<Vec<u8>>`] - Len values are owned `Vec<u8>`
115//! - [`AsRefExtProtobuf`]: Read fields from `AsRef<[u8]>` types
116//! (slices, arrays, etc.)
117//! - Output: [`Field<&[u8]>`] - Len values are borrowed `&[u8]` slices (zero-copy)
118//! - [`ReadExtProtobuf`]: Read fields from `std::io::Read` types
119//! - Output: [`Field<Vec<u8>>`] - Len values are owned `Vec<u8>`
120//!
121//! ## Writing Traits
122//!
123//! - [`WriteExtProtobuf`]: Write fields to `std::io::Write`
124//!
125//! ## Tag/Varint Traits
126//!
127//! For lower-level operations, the library provides traits for reading and writing tags and
128//! varints:
129//!
130//! - [`IteratorExtTag`] / [`TryIteratorExtTag`]
131//! / [`ReadExtTag`]: Read tags (sync, with partial/resume for chunked input)
132//! - [`IteratorExtVarint`] / [`TryIteratorExtVarint`]
133//! / [`ReadExtVarint`]: Read varints (sync, with partial/resume for chunked input)
134//! - [`WriteExtVarint`]: Write varints
135//!
136//! ## Feature Flags
137//!
138//! - `read` (enabled by default): Enables field reading utilities
139//! - `write` (enabled by default): Enables field writing utilities
140//!
141//! You can use features independently:
142//!
143//! ```toml
144//! [dependencies]
145//! protobuf-core = { version = "0.1.0", default-features = false, features = ["read"] }
146//! ```
147//!
148//! ## Constants
149//!
150//! The library also provides various constants related to the protobuf wire format:
151//!
152//! - Field number limits: [`MIN_FIELD_NUMBER`], [`MAX_FIELD_NUMBER`]
153//! - Size limits: [`MAX_MESSAGE_SIZE`], [`MAX_STRING_SIZE`], [`MAX_VARINT_BYTES`]
154//! - Wire format constants: [`FIXED32_BYTES`], [`FIXED64_BYTES`], etc.
155
156#[cfg(any(feature = "read", feature = "write"))]
157pub(crate) mod field;
158pub(crate) mod field_number;
159pub(crate) mod tag;
160pub(crate) mod varint;
161pub(crate) mod wire_format;
162
163#[cfg(feature = "write")]
164pub use self::field::WriteExtProtobuf;
165#[cfg(feature = "read")]
166pub use self::field::{
167 AsRefExtProtobuf, IteratorExtProtobuf, ProtobufFieldIterator, ProtobufFieldIteratorFromBytes,
168 ProtobufFieldSliceIterator, ReadExtProtobuf, TryIteratorExtProtobuf,
169};
170#[cfg(any(feature = "read", feature = "write"))]
171pub use self::field::{Field, FieldValue};
172pub use self::field_number::FieldNumber;
173pub use self::tag::{IteratorExtTag, Outcome as TagOutcome, ReadExtTag, Tag, TryIteratorExtTag};
174pub use self::varint::{
175 DecodeOutcome, DecodeState, IteratorExtVarint, ReadExtVarint, TryIteratorExtVarint, Varint,
176 WriteExtVarint,
177};
178pub use self::wire_format::{
179 FIELD_NUMBER_SHIFT, FIXED32_BYTES, FIXED64_BYTES, MAX_1_BYTE_VARINT, MAX_2_BYTE_VARINT,
180 MAX_3_BYTE_VARINT, MAX_4_BYTE_VARINT, MAX_5_BYTE_VARINT, MAX_6_BYTE_VARINT, MAX_7_BYTE_VARINT,
181 MAX_8_BYTE_VARINT, MAX_9_BYTE_VARINT, MAX_FIELD_NUMBER, MAX_MESSAGE_SIZE, MAX_STRING_SIZE,
182 MAX_VARINT_BYTES, MIN_FIELD_NUMBER, VARINT_CONTINUATION_BIT, VARINT_PAYLOAD_MASK,
183 WIRE_TYPE_MASK, WireType,
184};
185
186use ::std::convert::Infallible;
187use ::thiserror::Error;
188
189/// Unified error type for all protobuf operations
190#[derive(Error, Debug)]
191pub enum ProtobufError {
192 #[error("Field number {value} is out of valid range [1, 536_870_911]")]
193 FieldNumberOutOfRange { value: String },
194
195 #[error("Invalid wire type: {value} (must be 0-5)")]
196 InvalidWireType { value: u8 },
197
198 #[error("Varint value {value} is out of range for target type: {target_type}")]
199 VarintDowncastOutOfRange {
200 value: u64,
201 target_type: &'static str,
202 },
203
204 #[error("Varint exceeds maximum length of 10 bytes")]
205 VarintTooLong,
206
207 #[error("Failed to downcast field value to expected type: {expected_type}")]
208 FieldTypeDowncastError { expected_type: String },
209
210 #[error("Malformed tag: field_number={field_number}, wire_type={wire_type}")]
211 MalformedTag { field_number: u32, wire_type: u8 },
212
213 #[error("Unexpected EOF while parsing field")]
214 UnexpectedEof,
215
216 #[error("I/O error: {0}")]
217 IoError(#[from] ::std::io::Error),
218}
219
220impl From<Infallible> for ProtobufError {
221 fn from(_: Infallible) -> Self {
222 unreachable!()
223 }
224}
225
226/// Custom Result type for protobuf operations
227pub type Result<T> = ::std::result::Result<T, ProtobufError>;