diff options
Diffstat (limited to 'src/wire_format.rs')
-rw-r--r-- | src/wire_format.rs | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/src/wire_format.rs b/src/wire_format.rs new file mode 100644 index 0000000..9f54af3 --- /dev/null +++ b/src/wire_format.rs @@ -0,0 +1,105 @@ +//! Serialization constants. + +// TODO: temporary +pub use self::WireType::*; + +/// Tag occupies 3 bits +pub const TAG_TYPE_BITS: u32 = 3; +/// Tag mask +pub const TAG_TYPE_MASK: u32 = (1u32 << TAG_TYPE_BITS) - 1; +/// Max possible field number +pub const FIELD_NUMBER_MAX: u32 = 0x1fffffff; + +/// One of six defined protobuf wire types +#[derive(PartialEq, Eq, Clone, Debug)] +pub enum WireType { + /// Varint (e. g. `int32` or `sint64`) + WireTypeVarint = 0, + /// Fixed size 64 bit (e. g. `fixed64` or `double`) + WireTypeFixed64 = 1, + /// Length-delimited (e. g. `message` or `string`) + WireTypeLengthDelimited = 2, + /// Groups are not supported by rust-protobuf + WireTypeStartGroup = 3, + /// Groups are not supported by rust-protobuf + WireTypeEndGroup = 4, + /// Fixed size 64 bit (e. g. `fixed32` or `float`) + WireTypeFixed32 = 5, +} + +impl Copy for WireType {} + +impl WireType { + /// Parse wire type + pub fn new(n: u32) -> Option<WireType> { + match n { + 0 => Some(WireTypeVarint), + 1 => Some(WireTypeFixed64), + 2 => Some(WireTypeLengthDelimited), + 3 => Some(WireTypeStartGroup), + 4 => Some(WireTypeEndGroup), + 5 => Some(WireTypeFixed32), + _ => None, + } + } +} + +/// Parsed protobuf tag, which is a pair of field number and wire type +#[derive(Clone)] +pub struct Tag { + field_number: u32, + wire_type: WireType, +} + +impl Copy for Tag {} + +impl Tag { + /// Pack a tag to integer + pub fn value(self) -> u32 { + (self.field_number << TAG_TYPE_BITS) | (self.wire_type as u32) + } + + /// Parse integer into `Tag` object + // TODO: should return Result instead of Option + pub fn new(value: u32) -> Option<Tag> { + let wire_type = WireType::new(value & TAG_TYPE_MASK); + if wire_type.is_none() { + return None; + } + let field_number = value >> TAG_TYPE_BITS; + if field_number == 0 { + return None; + } + Some(Tag { + field_number: field_number, + wire_type: wire_type.unwrap(), + }) + } + + /// Create a tag from a field number and wire type. + /// + /// # Panics + /// + /// If field number is outside of allowed range. + pub fn make(field_number: u32, wire_type: WireType) -> Tag { + assert!(field_number > 0 && field_number <= FIELD_NUMBER_MAX); + Tag { + field_number: field_number, + wire_type: wire_type, + } + } + + /// Tag as pair of (field number, wire type) + pub fn unpack(self) -> (u32, WireType) { + (self.field_number(), self.wire_type()) + } + + fn wire_type(self) -> WireType { + self.wire_type + } + + /// Protobuf field number + pub fn field_number(self) -> u32 { + self.field_number + } +} |