const VARINT: u32 = 0;
const FIXED64: u32 = 1;
const LENGTH_DELIMITED: u32 = 2;
#[derive(Debug, Default, Clone)]
pub struct Encoder {
bytes: Vec<u8>,
}
impl Encoder {
pub fn new() -> Self {
Encoder::default()
}
pub fn into_bytes(self) -> Vec<u8> {
self.bytes
}
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
pub fn len(&self) -> usize {
self.bytes.len()
}
pub fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
fn tag(&mut self, field: u32, wire: u32) {
self.raw_varint(u64::from(field) << 3 | u64::from(wire));
}
fn raw_varint(&mut self, mut value: u64) {
while value >= 0x80 {
self.bytes.push((value as u8) | 0x80);
value >>= 7;
}
self.bytes.push(value as u8);
}
pub fn uint64(&mut self, field: u32, value: u64) {
if value != 0 {
self.tag(field, VARINT);
self.raw_varint(value);
}
}
pub fn uint32(&mut self, field: u32, value: u32) {
self.uint64(field, u64::from(value));
}
pub fn int64(&mut self, field: u32, value: i64) {
if value != 0 {
self.tag(field, VARINT);
self.raw_varint(value as u64);
}
}
pub fn bool(&mut self, field: u32, value: bool) {
if value {
self.bool_present(field, value);
}
}
pub fn bool_present(&mut self, field: u32, value: bool) {
self.tag(field, VARINT);
self.raw_varint(u64::from(value));
}
pub fn int64_present(&mut self, field: u32, value: i64) {
self.tag(field, VARINT);
self.raw_varint(value as u64);
}
pub fn string_present(&mut self, field: u32, value: &str) {
self.tag(field, LENGTH_DELIMITED);
self.raw_varint(value.len() as u64);
self.bytes.extend_from_slice(value.as_bytes());
}
pub fn sfixed64_present(&mut self, field: u32, value: i64) {
self.tag(field, FIXED64);
self.bytes.extend_from_slice(&value.to_le_bytes());
}
pub fn enumeration(&mut self, field: u32, value: i32) {
if value != 0 {
self.tag(field, VARINT);
self.raw_varint(value as u32 as u64);
}
}
pub fn fixed64(&mut self, field: u32, value: u64) {
if value != 0 {
self.tag(field, FIXED64);
self.bytes.extend_from_slice(&value.to_le_bytes());
}
}
pub fn sfixed64(&mut self, field: u32, value: i64) {
if value != 0 {
self.tag(field, FIXED64);
self.bytes.extend_from_slice(&value.to_le_bytes());
}
}
pub fn double(&mut self, field: u32, value: f64) {
if value != 0.0 {
self.present_double(field, value);
}
}
pub fn present_double(&mut self, field: u32, value: f64) {
self.tag(field, FIXED64);
self.bytes.extend_from_slice(&value.to_le_bytes());
}
pub fn string(&mut self, field: u32, value: &str) {
if !value.is_empty() {
self.bytes_field(field, value.as_bytes());
}
}
pub fn bytes_field(&mut self, field: u32, value: &[u8]) {
if value.is_empty() {
return;
}
self.tag(field, LENGTH_DELIMITED);
self.raw_varint(value.len() as u64);
self.bytes.extend_from_slice(value);
}
pub fn message(&mut self, field: u32, message: &Encoder) {
self.tag(field, LENGTH_DELIMITED);
self.raw_varint(message.bytes.len() as u64);
self.bytes.extend_from_slice(&message.bytes);
}
pub fn packed_fixed64(&mut self, field: u32, values: &[u64]) {
if values.is_empty() {
return;
}
self.tag(field, LENGTH_DELIMITED);
self.raw_varint((values.len() * 8) as u64);
for value in values {
self.bytes.extend_from_slice(&value.to_le_bytes());
}
}
pub fn packed_double(&mut self, field: u32, values: &[f64]) {
if values.is_empty() {
return;
}
self.tag(field, LENGTH_DELIMITED);
self.raw_varint((values.len() * 8) as u64);
for value in values {
self.bytes.extend_from_slice(&value.to_le_bytes());
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn varint_of(value: u64) -> Vec<u8> {
let mut encoder = Encoder::new();
encoder.raw_varint(value);
encoder.into_bytes()
}
#[test]
fn varints_match_the_specifications_worked_example() {
assert_eq!(varint_of(0), [0x00]);
assert_eq!(varint_of(1), [0x01]);
assert_eq!(varint_of(127), [0x7f]);
assert_eq!(varint_of(128), [0x80, 0x01]);
assert_eq!(varint_of(300), [0xac, 0x02]);
assert_eq!(varint_of(u64::MAX), [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01]);
}
#[test]
fn a_tagged_varint_field_is_the_canonical_three_bytes() {
let mut encoder = Encoder::new();
encoder.uint64(1, 150);
assert_eq!(encoder.as_bytes(), [0x08, 0x96, 0x01]);
}
#[test]
fn a_string_field_is_tag_length_then_utf8() {
let mut encoder = Encoder::new();
encoder.string(2, "testing");
assert_eq!(encoder.as_bytes(), b"\x12\x07testing");
}
#[test]
fn a_nested_message_is_length_delimited_around_its_own_bytes() {
let mut inner = Encoder::new();
inner.uint64(1, 150);
let mut outer = Encoder::new();
outer.message(3, &inner);
assert_eq!(outer.as_bytes(), [0x1a, 0x03, 0x08, 0x96, 0x01]);
}
#[test]
fn an_empty_nested_message_still_writes_its_header() {
let mut outer = Encoder::new();
outer.message(15, &Encoder::new());
assert_eq!(outer.as_bytes(), [0x7a, 0x00]);
}
#[test]
fn fixed64_is_eight_little_endian_bytes() {
let mut encoder = Encoder::new();
encoder.fixed64(7, 1);
assert_eq!(encoder.as_bytes(), [0x39, 0x01, 0, 0, 0, 0, 0, 0, 0]);
}
#[test]
fn a_double_is_its_ieee_754_bits_little_endian() {
let mut encoder = Encoder::new();
encoder.double(4, 1.0);
assert_eq!(encoder.as_bytes(), [0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f]);
}
#[test]
fn zero_is_skipped_by_double_and_kept_by_present_double() {
let mut skipped = Encoder::new();
skipped.double(5, 0.0);
assert!(skipped.is_empty());
let mut kept = Encoder::new();
kept.present_double(5, 0.0);
assert_eq!(kept.as_bytes(), [0x29, 0, 0, 0, 0, 0, 0, 0, 0]);
}
#[test]
fn oneof_members_are_written_even_when_they_hold_the_default() {
let mut boolean = Encoder::new();
boolean.bool(2, false);
assert!(boolean.is_empty());
boolean.bool_present(2, false);
assert_eq!(boolean.as_bytes(), [0x10, 0x00]);
let mut integer = Encoder::new();
integer.int64_present(3, 0);
assert_eq!(integer.as_bytes(), [0x18, 0x00]);
let mut text = Encoder::new();
text.string_present(1, "");
assert_eq!(text.as_bytes(), [0x0a, 0x00]);
let mut number = Encoder::new();
number.sfixed64_present(6, 0);
assert_eq!(number.as_bytes(), [0x31, 0, 0, 0, 0, 0, 0, 0, 0]);
}
#[test]
fn a_negative_int64_sign_extends_to_ten_bytes() {
let mut encoder = Encoder::new();
encoder.int64(1, -1);
assert_eq!(encoder.as_bytes(), [0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01]);
}
#[test]
fn packed_repeated_scalars_share_one_tag_and_one_length() {
let mut encoder = Encoder::new();
encoder.packed_fixed64(6, &[1, 2]);
let mut expected = vec![0x32, 0x10];
expected.extend_from_slice(&1u64.to_le_bytes());
expected.extend_from_slice(&2u64.to_le_bytes());
assert_eq!(encoder.as_bytes(), expected.as_slice());
}
#[test]
fn packed_doubles_are_bounds_as_the_collector_expects_them() {
let mut encoder = Encoder::new();
encoder.packed_double(7, &[0.005, 0.01]);
let mut expected = vec![0x3a, 0x10];
expected.extend_from_slice(&0.005f64.to_le_bytes());
expected.extend_from_slice(&0.01f64.to_le_bytes());
assert_eq!(encoder.as_bytes(), expected.as_slice());
}
#[test]
fn default_values_are_omitted_entirely() {
let mut encoder = Encoder::new();
encoder.uint64(1, 0);
encoder.int64(2, 0);
encoder.bool(3, false);
encoder.enumeration(4, 0);
encoder.fixed64(5, 0);
encoder.string(6, "");
encoder.bytes_field(7, &[]);
encoder.packed_fixed64(8, &[]);
assert!(encoder.is_empty());
}
#[test]
fn field_numbers_past_fifteen_use_a_two_byte_tag() {
let mut encoder = Encoder::new();
encoder.uint64(16, 1);
assert_eq!(encoder.as_bytes(), [0x80, 0x01, 0x01]);
}
}