Skip to main content

veriform/field/
length.rs

1//! Field length calculations for various types
2
3use super::{Header, Tag, WireType};
4use crate::message::Message;
5
6/// Compute length of a `uint64` field
7pub fn uint64(tag: Tag, value: u64) -> usize {
8    header(tag, WireType::UInt64) + vint64::encoded_len(value)
9}
10
11/// Compute length of an `sint64` field
12pub fn sint64(tag: Tag, value: i64) -> usize {
13    header(tag, WireType::SInt64) + vint64::signed::encoded_len(value)
14}
15
16/// Compute length of a `bytes` field
17pub fn bytes(tag: Tag, bytes: &[u8]) -> usize {
18    dynamically_sized(tag, WireType::Bytes, bytes.len())
19}
20
21/// Compute length of a `string` field
22pub fn string(tag: Tag, string: &str) -> usize {
23    dynamically_sized(tag, WireType::String, string.len())
24}
25
26/// Compute length of a `message` field including the tag and delimiter
27pub fn message(tag: Tag, message: &dyn Message) -> usize {
28    dynamically_sized(tag, WireType::Message, message.encoded_len())
29}
30
31/// Compute length of a `sequence` of `message` values including the tag and delimiter
32pub fn message_seq<'a>(tag: Tag, messages: impl Iterator<Item = &'a dyn Message>) -> usize {
33    let body_len: usize = messages
34        .map(|msg| {
35            let encoded_len = msg.encoded_len();
36            vint64::encoded_len(encoded_len as u64) + encoded_len
37        })
38        .sum();
39
40    header(tag, WireType::Sequence)
41        + vint64::encoded_len((body_len as u64) << 4 | WireType::Message as u64)
42        + body_len
43}
44
45/// Compute length of a field header
46fn header(tag: Tag, wire_type: WireType) -> usize {
47    // Note: there shouldn't be any cases where the critical bit affects length
48    Header::new(tag, false, wire_type).encoded_len()
49}
50
51/// Compute length of a dynamically sized field
52fn dynamically_sized(tag: Tag, wire_type: WireType, length: usize) -> usize {
53    header(tag, wire_type) + vint64::encoded_len(length as u64) + length
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn uint64_length() {
62        assert_eq!(uint64(1, 42), 2);
63    }
64
65    #[test]
66    fn sint64_length() {
67        assert_eq!(sint64(2, -42), 2);
68    }
69
70    #[test]
71    fn bytes_length() {
72        assert_eq!(bytes(3, b"foobar"), 8)
73    }
74
75    #[test]
76    fn string_length() {
77        assert_eq!(string(4, "baz"), 5);
78    }
79}