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