protobuf/
wire_format.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//! Constants used in serializations.

use crate::descriptor::field_descriptor_proto;
use crate::error::WireError;

/// Tag occupies three bits.
pub(crate) const TAG_TYPE_BITS: u32 = 3;
/// Apply this mask to varint value to obtain a tag.
pub(crate) const TAG_TYPE_MASK: u32 = (1u32 << TAG_TYPE_BITS as usize) - 1;
/// Max possible field number
pub(crate) const FIELD_NUMBER_MAX: u32 = 0x1fffffff;

pub(crate) const MAX_MESSAGE_SIZE: u64 = i32::MAX as u64;

#[inline]
pub(crate) fn check_message_size(size: u64) -> crate::Result<u32> {
    if size <= MAX_MESSAGE_SIZE {
        Ok(size as u32)
    } else {
        #[cold]
        fn message_too_large(size: u64) -> crate::Error {
            WireError::MessageTooLarge(size).into()
        }

        Err(message_too_large(size))
    }
}

/// All supported "wire types" are listed in this enum.
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum WireType {
    /// Variable-length integer
    Varint = 0,
    /// 32-bit field (e. g. `fixed64` or `double`)
    Fixed64 = 1,
    /// Length-delimited field
    LengthDelimited = 2,
    /// Groups are not supported in rust-protobuf
    StartGroup = 3,
    /// Groups are not supported in rust-protobuf
    EndGroup = 4,
    /// 32-bit field (e. g. `fixed32` or `float`)
    Fixed32 = 5,
}

impl WireType {
    /// Construct `WireType` from number, or return `None` if type is unknown.
    pub fn new(n: u32) -> Option<WireType> {
        match n {
            0 => Some(WireType::Varint),
            1 => Some(WireType::Fixed64),
            2 => Some(WireType::LengthDelimited),
            3 => Some(WireType::StartGroup),
            4 => Some(WireType::EndGroup),
            5 => Some(WireType::Fixed32),
            _ => None,
        }
    }

    #[doc(hidden)]
    pub fn for_type(field_type: field_descriptor_proto::Type) -> WireType {
        use field_descriptor_proto::Type;
        match field_type {
            Type::TYPE_INT32 => WireType::Varint,
            Type::TYPE_INT64 => WireType::Varint,
            Type::TYPE_UINT32 => WireType::Varint,
            Type::TYPE_UINT64 => WireType::Varint,
            Type::TYPE_SINT32 => WireType::Varint,
            Type::TYPE_SINT64 => WireType::Varint,
            Type::TYPE_BOOL => WireType::Varint,
            Type::TYPE_ENUM => WireType::Varint,
            Type::TYPE_FIXED32 => WireType::Fixed32,
            Type::TYPE_FIXED64 => WireType::Fixed64,
            Type::TYPE_SFIXED32 => WireType::Fixed32,
            Type::TYPE_SFIXED64 => WireType::Fixed64,
            Type::TYPE_FLOAT => WireType::Fixed32,
            Type::TYPE_DOUBLE => WireType::Fixed64,
            Type::TYPE_STRING => WireType::LengthDelimited,
            Type::TYPE_BYTES => WireType::LengthDelimited,
            Type::TYPE_MESSAGE => WireType::LengthDelimited,
            Type::TYPE_GROUP => WireType::LengthDelimited, // not true
        }
    }
}

/// Parsed field tag (a pair of field number and wire type)
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub(crate) struct Tag {
    field_number: u32,
    wire_type: WireType,
}

impl Tag {
    /// Fold tag to a number to be serialized.
    pub(crate) fn value(self) -> u32 {
        (self.field_number << TAG_TYPE_BITS) | (self.wire_type as u32)
    }

    /// Extract wire type and field number from integer tag
    pub(crate) fn new(value: u32) -> crate::Result<Tag> {
        let wire_type = WireType::new(value & TAG_TYPE_MASK);
        if wire_type.is_none() {
            return Err(WireError::IncorrectTag(value).into());
        }
        let field_number = value >> TAG_TYPE_BITS;
        if field_number == 0 {
            return Err(WireError::IncorrectTag(value).into());
        }
        Ok(Tag {
            field_number,
            wire_type: wire_type.unwrap(),
        })
    }

    /// Construct a tag from a field number and wire type.
    ///
    /// # Panics
    ///
    /// If field number is outside of valid range.
    pub(crate) fn make(field_number: u32, wire_type: WireType) -> Tag {
        assert!(field_number > 0 && field_number <= FIELD_NUMBER_MAX);
        Tag {
            field_number,
            wire_type,
        }
    }

    /// Get field number and wire type
    pub(crate) fn unpack(self) -> (u32, WireType) {
        (self.field_number(), self.wire_type())
    }

    /// Get wire type
    fn wire_type(self) -> WireType {
        self.wire_type
    }

    /// Get field number
    pub(crate) fn field_number(self) -> u32 {
        self.field_number
    }
}