protobuf/
wire_format.rs

1//! Constants used in serializations.
2
3use crate::descriptor::field_descriptor_proto;
4use crate::error::WireError;
5
6/// Tag occupies three bits.
7pub(crate) const TAG_TYPE_BITS: u32 = 3;
8/// Apply this mask to varint value to obtain a tag.
9pub(crate) const TAG_TYPE_MASK: u32 = (1u32 << TAG_TYPE_BITS as usize) - 1;
10/// Max possible field number
11pub(crate) const FIELD_NUMBER_MAX: u32 = 0x1fffffff;
12
13pub(crate) const MAX_MESSAGE_SIZE: u64 = i32::MAX as u64;
14
15#[inline]
16pub(crate) fn check_message_size(size: u64) -> crate::Result<u32> {
17    if size <= MAX_MESSAGE_SIZE {
18        Ok(size as u32)
19    } else {
20        #[cold]
21        fn message_too_large(size: u64) -> crate::Error {
22            WireError::MessageTooLarge(size).into()
23        }
24
25        Err(message_too_large(size))
26    }
27}
28
29/// All supported "wire types" are listed in this enum.
30#[derive(PartialEq, Eq, Clone, Copy, Debug)]
31pub enum WireType {
32    /// Variable-length integer
33    Varint = 0,
34    /// 64-bit field (e. g. `fixed64` or `double`)
35    Fixed64 = 1,
36    /// Length-delimited field
37    LengthDelimited = 2,
38    /// Groups are not supported in rust-protobuf
39    StartGroup = 3,
40    /// Groups are not supported in rust-protobuf
41    EndGroup = 4,
42    /// 32-bit field (e. g. `fixed32` or `float`)
43    Fixed32 = 5,
44}
45
46impl WireType {
47    /// Construct `WireType` from number, or return `None` if type is unknown.
48    pub fn new(n: u32) -> Option<WireType> {
49        match n {
50            0 => Some(WireType::Varint),
51            1 => Some(WireType::Fixed64),
52            2 => Some(WireType::LengthDelimited),
53            3 => Some(WireType::StartGroup),
54            4 => Some(WireType::EndGroup),
55            5 => Some(WireType::Fixed32),
56            _ => None,
57        }
58    }
59
60    #[doc(hidden)]
61    pub fn for_type(field_type: field_descriptor_proto::Type) -> WireType {
62        use field_descriptor_proto::Type;
63        match field_type {
64            Type::TYPE_INT32 => WireType::Varint,
65            Type::TYPE_INT64 => WireType::Varint,
66            Type::TYPE_UINT32 => WireType::Varint,
67            Type::TYPE_UINT64 => WireType::Varint,
68            Type::TYPE_SINT32 => WireType::Varint,
69            Type::TYPE_SINT64 => WireType::Varint,
70            Type::TYPE_BOOL => WireType::Varint,
71            Type::TYPE_ENUM => WireType::Varint,
72            Type::TYPE_FIXED32 => WireType::Fixed32,
73            Type::TYPE_FIXED64 => WireType::Fixed64,
74            Type::TYPE_SFIXED32 => WireType::Fixed32,
75            Type::TYPE_SFIXED64 => WireType::Fixed64,
76            Type::TYPE_FLOAT => WireType::Fixed32,
77            Type::TYPE_DOUBLE => WireType::Fixed64,
78            Type::TYPE_STRING => WireType::LengthDelimited,
79            Type::TYPE_BYTES => WireType::LengthDelimited,
80            Type::TYPE_MESSAGE => WireType::LengthDelimited,
81            Type::TYPE_GROUP => WireType::LengthDelimited, // not true
82        }
83    }
84}
85
86/// Parsed field tag (a pair of field number and wire type)
87#[derive(Clone, Copy, PartialEq, Eq, Debug)]
88pub(crate) struct Tag {
89    field_number: u32,
90    wire_type: WireType,
91}
92
93impl Tag {
94    /// Fold tag to a number to be serialized.
95    pub(crate) fn value(self) -> u32 {
96        (self.field_number << TAG_TYPE_BITS) | (self.wire_type as u32)
97    }
98
99    /// Extract wire type and field number from integer tag
100    pub(crate) fn new(value: u32) -> crate::Result<Tag> {
101        let wire_type = WireType::new(value & TAG_TYPE_MASK);
102        if wire_type.is_none() {
103            return Err(WireError::IncorrectTag(value).into());
104        }
105        let field_number = value >> TAG_TYPE_BITS;
106        if field_number == 0 {
107            return Err(WireError::IncorrectTag(value).into());
108        }
109        Ok(Tag {
110            field_number,
111            wire_type: wire_type.unwrap(),
112        })
113    }
114
115    /// Construct a tag from a field number and wire type.
116    ///
117    /// # Panics
118    ///
119    /// If field number is outside of valid range.
120    pub(crate) fn make(field_number: u32, wire_type: WireType) -> Tag {
121        assert!(field_number > 0 && field_number <= FIELD_NUMBER_MAX);
122        Tag {
123            field_number,
124            wire_type,
125        }
126    }
127
128    /// Get field number and wire type
129    pub(crate) fn unpack(self) -> (u32, WireType) {
130        (self.field_number(), self.wire_type())
131    }
132
133    /// Get wire type
134    fn wire_type(self) -> WireType {
135        self.wire_type
136    }
137
138    /// Get field number
139    pub(crate) fn field_number(self) -> u32 {
140        self.field_number
141    }
142}