use crate::proto_wire::{WireType, tag_wire_type};
pub mod message_id {
pub const NO_OP: u32 = 0;
pub const NON_PROTO: u32 = 1;
pub const START_OF_SUBMESSAGE: u32 = 2;
pub const START_OF_MESSAGE: u32 = 3;
pub const ROOT: u32 = 4;
}
pub mod subtype {
pub const TRIVIAL: u8 = 0;
pub const VARINT_1: u8 = 0;
pub const VARINT_10: u8 = 9;
pub const VARINT_MAX: u8 = VARINT_10;
pub const VARINT_INLINE_0: u8 = VARINT_MAX + 1;
pub const VARINT_INLINE_MAX: u8 = VARINT_INLINE_0 + 0x7F;
pub const LENGTH_DELIMITED_STRING: u8 = 0;
pub const LENGTH_DELIMITED_START_OF_SUBMESSAGE: u8 = 1;
pub const LENGTH_DELIMITED_END_OF_SUBMESSAGE: u8 = 2;
}
pub const SUBMESSAGE_WIRE_TYPE: u32 = 6;
pub fn has_subtype(tag: u32) -> bool {
matches!(tag_wire_type(tag), Some(WireType::Varint))
}
pub fn has_data_buffer(tag: u32, subtype: u8) -> bool {
match tag_wire_type(tag) {
Some(WireType::Varint) => {
subtype < subtype::VARINT_INLINE_0
}
Some(WireType::Fixed32) | Some(WireType::Fixed64) => true,
Some(WireType::LengthDelimited) => {
subtype == subtype::LENGTH_DELIMITED_STRING
}
Some(WireType::StartGroup) | Some(WireType::EndGroup) => false,
None => false,
}
}
pub const MAX_RECURSION_DEPTH: usize = 100;
pub const MAX_VARINT_INLINE: u8 = 3;
#[cfg(test)]
mod tests {
use super::*;
use crate::proto_wire::make_tag;
#[test]
fn test_has_subtype_varint() {
assert!(has_subtype(make_tag(1, WireType::Varint)));
assert!(has_subtype(make_tag(100, WireType::Varint)));
}
#[test]
fn test_has_subtype_non_varint() {
assert!(!has_subtype(make_tag(1, WireType::Fixed32)));
assert!(!has_subtype(make_tag(1, WireType::Fixed64)));
assert!(!has_subtype(make_tag(1, WireType::LengthDelimited)));
assert!(!has_subtype(make_tag(1, WireType::StartGroup)));
assert!(!has_subtype(make_tag(1, WireType::EndGroup)));
}
#[test]
fn test_has_data_buffer_varint_buffered() {
assert!(has_data_buffer(
make_tag(1, WireType::Varint),
subtype::VARINT_1
));
assert!(has_data_buffer(
make_tag(1, WireType::Varint),
subtype::VARINT_10
));
}
#[test]
fn test_has_data_buffer_varint_inline() {
assert!(!has_data_buffer(
make_tag(1, WireType::Varint),
subtype::VARINT_INLINE_0
));
assert!(!has_data_buffer(
make_tag(1, WireType::Varint),
subtype::VARINT_INLINE_MAX
));
}
#[test]
fn test_has_data_buffer_fixed() {
assert!(has_data_buffer(
make_tag(1, WireType::Fixed32),
subtype::TRIVIAL
));
assert!(has_data_buffer(
make_tag(1, WireType::Fixed64),
subtype::TRIVIAL
));
}
#[test]
fn test_has_data_buffer_length_delimited_string() {
assert!(has_data_buffer(
make_tag(1, WireType::LengthDelimited),
subtype::LENGTH_DELIMITED_STRING
));
}
#[test]
fn test_has_data_buffer_length_delimited_submessage() {
assert!(!has_data_buffer(
make_tag(1, WireType::LengthDelimited),
subtype::LENGTH_DELIMITED_END_OF_SUBMESSAGE
));
assert!(!has_data_buffer(
make_tag(1, WireType::LengthDelimited),
subtype::LENGTH_DELIMITED_START_OF_SUBMESSAGE
));
}
#[test]
fn test_has_data_buffer_groups() {
assert!(!has_data_buffer(
make_tag(1, WireType::StartGroup),
subtype::TRIVIAL
));
assert!(!has_data_buffer(
make_tag(1, WireType::EndGroup),
subtype::TRIVIAL
));
}
#[test]
fn test_message_id_values() {
assert_eq!(message_id::NO_OP, 0);
assert_eq!(message_id::NON_PROTO, 1);
assert_eq!(message_id::START_OF_SUBMESSAGE, 2);
assert_eq!(message_id::START_OF_MESSAGE, 3);
assert_eq!(message_id::ROOT, 4);
assert!(message_id::ROOT < 8);
}
#[test]
fn test_subtype_values() {
assert_eq!(subtype::VARINT_1, 0);
assert_eq!(subtype::VARINT_10, 9);
assert_eq!(subtype::VARINT_INLINE_0, 10);
assert_eq!(subtype::VARINT_INLINE_MAX, 137);
assert_eq!(subtype::LENGTH_DELIMITED_STRING, 0);
assert_eq!(subtype::LENGTH_DELIMITED_START_OF_SUBMESSAGE, 1);
assert_eq!(subtype::LENGTH_DELIMITED_END_OF_SUBMESSAGE, 2);
}
#[test]
fn test_submessage_wire_type() {
assert_eq!(SUBMESSAGE_WIRE_TYPE, 6);
}
#[test]
fn test_has_subtype_high_field_number() {
assert!(has_subtype(make_tag(0x1FFFFFFF, WireType::Varint)));
assert!(!has_subtype(make_tag(0x1FFFFFFF, WireType::Fixed64)));
}
#[test]
fn test_has_subtype_invalid_wire_type_tag() {
let tag_wt6 = (1u32 << 3) | 6;
assert!(!has_subtype(tag_wt6));
}
#[test]
fn test_has_data_buffer_varint_all_buffered_subtypes() {
let tag = make_tag(1, WireType::Varint);
for s in 0..=subtype::VARINT_MAX {
assert!(
has_data_buffer(tag, s),
"subtype {s} should have data buffer"
);
}
for s in subtype::VARINT_INLINE_0..=subtype::VARINT_INLINE_MAX {
assert!(
!has_data_buffer(tag, s),
"subtype {s} should NOT have data buffer"
);
}
}
#[test]
fn test_has_data_buffer_invalid_wire_type_returns_false() {
let tag_wt6 = (1u32 << 3) | 6;
assert!(!has_data_buffer(tag_wt6, 0));
let tag_wt7 = (1u32 << 3) | 7;
assert!(!has_data_buffer(tag_wt7, 0));
}
}