protobuf_core/
field_number.rs1use crate::ProtobufError;
16use ::std::convert::TryFrom;
17#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
21pub struct FieldNumber(u32);
22
23impl FieldNumber {
24 pub const MIN: Self = Self(1);
26
27 pub const MAX: Self = Self(536_870_911);
29
30 pub const MAX_SINGLE_BYTE_TAG: u32 = 15;
33
34 pub const RESERVED_RANGE_START: u32 = 19000;
37
38 pub const RESERVED_RANGE_END: u32 = 19999;
41
42 pub fn try_new(value: u32) -> Result<Self, ProtobufError> {
44 if !(Self::MIN.0..=Self::MAX.0).contains(&value) {
45 return Err(ProtobufError::FieldNumberOutOfRange {
46 value: value.to_string(),
47 });
48 }
49 Ok(Self(value))
50 }
51
52 pub fn is_tag_single_byte(&self) -> bool {
55 self.0 <= Self::MAX_SINGLE_BYTE_TAG
56 }
57
58 pub fn is_reserved(&self) -> bool {
61 self.0 >= Self::RESERVED_RANGE_START && self.0 <= Self::RESERVED_RANGE_END
62 }
63
64 pub fn is_in_range(&self, min: u32, max: u32) -> bool {
66 self.0 >= min && self.0 <= max
67 }
68
69 pub fn encoded_size(&self) -> usize {
74 let max_tag_value = (self.0 << 3) | 7; match max_tag_value {
77 0..=0x7F => 1,
78 0x80..=0x3FFF => 2,
79 0x4000..=0x1FFFFF => 3,
80 0x200000..=0xFFFFFFF => 4,
81 _ => 5,
82 }
83 }
84
85 pub fn as_u32(&self) -> u32 {
87 self.0
88 }
89
90 pub fn as_i32(&self) -> i32 {
92 self.0 as i32
93 }
94
95 pub fn as_usize(&self) -> usize {
97 self.0 as usize
98 }
99}
100
101impl TryFrom<u32> for FieldNumber {
102 type Error = ProtobufError;
103
104 fn try_from(value: u32) -> Result<Self, Self::Error> {
105 Self::try_new(value)
106 }
107}
108
109impl From<FieldNumber> for u32 {
110 fn from(field_number: FieldNumber) -> Self {
111 field_number.as_u32()
112 }
113}
114
115impl TryFrom<i32> for FieldNumber {
116 type Error = ProtobufError;
117
118 fn try_from(value: i32) -> Result<Self, Self::Error> {
119 Self::try_new(
120 value
121 .try_into()
122 .map_err(|_| ProtobufError::FieldNumberOutOfRange {
123 value: value.to_string(),
124 })?,
125 )
126 }
127}
128
129impl From<FieldNumber> for i32 {
130 fn from(field_number: FieldNumber) -> Self {
131 field_number.as_i32()
132 }
133}
134
135impl From<FieldNumber> for usize {
136 fn from(field_number: FieldNumber) -> Self {
137 field_number.as_usize()
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144
145 #[test]
146 fn test_field_number_creation() {
147 assert!(FieldNumber::try_new(1).is_ok());
148 assert!(FieldNumber::try_new(16).is_ok());
149 assert!(FieldNumber::try_new(536_870_911).is_ok());
150
151 assert!(FieldNumber::try_new(0).is_err());
152 assert!(FieldNumber::try_new(536_870_912).is_err());
153 }
154
155 #[test]
156 fn test_field_number_conversion() {
157 let field = FieldNumber::try_new(42).unwrap();
158 assert_eq!(u32::from(field), 42);
159 assert_eq!(usize::from(field), 42);
160 assert_eq!(field.as_u32(), 42);
161 assert_eq!(field.as_usize(), 42);
162 }
163
164 #[test]
165 fn test_field_number_try_from() {
166 let result = FieldNumber::try_from(1);
167 assert!(result.is_ok());
168 let field_number = result.unwrap();
169 assert_eq!(field_number.as_u32(), 1);
170
171 let result = FieldNumber::try_from(0);
172 assert!(result.is_err());
173 if let Err(ProtobufError::FieldNumberOutOfRange { value }) = result {
174 assert_eq!(value, "0");
175 } else {
176 panic!("Expected FieldNumberOutOfRange error");
177 }
178 }
179
180 #[test]
181 fn test_helper_methods() {
182 let single_byte_field = FieldNumber::try_new(15).unwrap();
183 let multi_byte_field = FieldNumber::try_new(16).unwrap();
184 let large_field = FieldNumber::try_new(1000).unwrap();
185 let reserved_field = FieldNumber::try_new(19500).unwrap();
186
187 assert!(single_byte_field.is_tag_single_byte());
188 assert!(!multi_byte_field.is_tag_single_byte());
189 assert!(!large_field.is_tag_single_byte());
190
191 assert!(reserved_field.is_reserved());
192 assert!(!single_byte_field.is_reserved());
193
194 assert!(single_byte_field.is_in_range(1, 20));
195 assert!(!single_byte_field.is_in_range(20, 30));
196 }
197
198 #[test]
199 fn test_encoded_size() {
200 assert_eq!(FieldNumber::try_new(1).unwrap().encoded_size(), 1);
202
203 assert_eq!(FieldNumber::try_new(16).unwrap().encoded_size(), 2);
205
206 assert_eq!(FieldNumber::try_new(100).unwrap().encoded_size(), 2);
208
209 assert_eq!(FieldNumber::try_new(10000).unwrap().encoded_size(), 3);
211
212 assert_eq!(FieldNumber::try_new(1000000).unwrap().encoded_size(), 4);
214
215 assert_eq!(FieldNumber::try_new(100000000).unwrap().encoded_size(), 5);
217 }
218
219 #[test]
220 fn test_as_u32_and_as_usize() {
221 let min_field = FieldNumber::MIN;
222 let max_field = FieldNumber::MAX;
223 let mid_field = FieldNumber::try_new(1000).unwrap();
224
225 assert_eq!(min_field.as_u32(), 1);
227 assert_eq!(max_field.as_u32(), 536_870_911);
228 assert_eq!(mid_field.as_u32(), 1000);
229
230 assert_eq!(min_field.as_usize(), 1);
232 assert_eq!(max_field.as_usize(), 536_870_911);
233 assert_eq!(mid_field.as_usize(), 1000);
234 }
235}