summaryrefslogtreecommitdiffstats
path: root/src/jaegertracing/thrift/lib/rs/src/protocol/compact.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/jaegertracing/thrift/lib/rs/src/protocol/compact.rs2385
1 files changed, 2385 insertions, 0 deletions
diff --git a/src/jaegertracing/thrift/lib/rs/src/protocol/compact.rs b/src/jaegertracing/thrift/lib/rs/src/protocol/compact.rs
new file mode 100644
index 000000000..1750bc42e
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/rs/src/protocol/compact.rs
@@ -0,0 +1,2385 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
+use integer_encoding::{VarIntReader, VarIntWriter};
+use std::convert::{From, TryFrom};
+use std::io;
+
+use super::{
+ TFieldIdentifier, TInputProtocol, TInputProtocolFactory, TListIdentifier, TMapIdentifier,
+ TMessageIdentifier, TMessageType,
+};
+use super::{TOutputProtocol, TOutputProtocolFactory, TSetIdentifier, TStructIdentifier, TType};
+use transport::{TReadTransport, TWriteTransport};
+
+const COMPACT_PROTOCOL_ID: u8 = 0x82;
+const COMPACT_VERSION: u8 = 0x01;
+const COMPACT_VERSION_MASK: u8 = 0x1F;
+
+/// Read messages encoded in the Thrift compact protocol.
+///
+/// # Examples
+///
+/// Create and use a `TCompactInputProtocol`.
+///
+/// ```no_run
+/// use thrift::protocol::{TCompactInputProtocol, TInputProtocol};
+/// use thrift::transport::TTcpChannel;
+///
+/// let mut channel = TTcpChannel::new();
+/// channel.open("localhost:9090").unwrap();
+///
+/// let mut protocol = TCompactInputProtocol::new(channel);
+///
+/// let recvd_bool = protocol.read_bool().unwrap();
+/// let recvd_string = protocol.read_string().unwrap();
+/// ```
+#[derive(Debug)]
+pub struct TCompactInputProtocol<T>
+where
+ T: TReadTransport,
+{
+ // Identifier of the last field deserialized for a struct.
+ last_read_field_id: i16,
+ // Stack of the last read field ids (a new entry is added each time a nested struct is read).
+ read_field_id_stack: Vec<i16>,
+ // Boolean value for a field.
+ // Saved because boolean fields and their value are encoded in a single byte,
+ // and reading the field only occurs after the field id is read.
+ pending_read_bool_value: Option<bool>,
+ // Underlying transport used for byte-level operations.
+ transport: T,
+}
+
+impl<T> TCompactInputProtocol<T>
+where
+ T: TReadTransport,
+{
+ /// Create a `TCompactInputProtocol` that reads bytes from `transport`.
+ pub fn new(transport: T) -> TCompactInputProtocol<T> {
+ TCompactInputProtocol {
+ last_read_field_id: 0,
+ read_field_id_stack: Vec::new(),
+ pending_read_bool_value: None,
+ transport: transport,
+ }
+ }
+
+ fn read_list_set_begin(&mut self) -> ::Result<(TType, i32)> {
+ let header = self.read_byte()?;
+ let element_type = collection_u8_to_type(header & 0x0F)?;
+
+ let element_count;
+ let possible_element_count = (header & 0xF0) >> 4;
+ if possible_element_count != 15 {
+ // high bits set high if count and type encoded separately
+ element_count = possible_element_count as i32;
+ } else {
+ element_count = self.transport.read_varint::<u32>()? as i32;
+ }
+
+ Ok((element_type, element_count))
+ }
+}
+
+impl<T> TInputProtocol for TCompactInputProtocol<T>
+where
+ T: TReadTransport,
+{
+ fn read_message_begin(&mut self) -> ::Result<TMessageIdentifier> {
+ let compact_id = self.read_byte()?;
+ if compact_id != COMPACT_PROTOCOL_ID {
+ Err(::Error::Protocol(::ProtocolError {
+ kind: ::ProtocolErrorKind::BadVersion,
+ message: format!("invalid compact protocol header {:?}", compact_id),
+ }))
+ } else {
+ Ok(())
+ }?;
+
+ let type_and_byte = self.read_byte()?;
+ let received_version = type_and_byte & COMPACT_VERSION_MASK;
+ if received_version != COMPACT_VERSION {
+ Err(::Error::Protocol(::ProtocolError {
+ kind: ::ProtocolErrorKind::BadVersion,
+ message: format!(
+ "cannot process compact protocol version {:?}",
+ received_version
+ ),
+ }))
+ } else {
+ Ok(())
+ }?;
+
+ // NOTE: unsigned right shift will pad with 0s
+ let message_type: TMessageType = TMessageType::try_from(type_and_byte >> 5)?;
+ let sequence_number = self.read_i32()?;
+ let service_call_name = self.read_string()?;
+
+ self.last_read_field_id = 0;
+
+ Ok(TMessageIdentifier::new(
+ service_call_name,
+ message_type,
+ sequence_number,
+ ))
+ }
+
+ fn read_message_end(&mut self) -> ::Result<()> {
+ Ok(())
+ }
+
+ fn read_struct_begin(&mut self) -> ::Result<Option<TStructIdentifier>> {
+ self.read_field_id_stack.push(self.last_read_field_id);
+ self.last_read_field_id = 0;
+ Ok(None)
+ }
+
+ fn read_struct_end(&mut self) -> ::Result<()> {
+ self.last_read_field_id = self
+ .read_field_id_stack
+ .pop()
+ .expect("should have previous field ids");
+ Ok(())
+ }
+
+ fn read_field_begin(&mut self) -> ::Result<TFieldIdentifier> {
+ // we can read at least one byte, which is:
+ // - the type
+ // - the field delta and the type
+ let field_type = self.read_byte()?;
+ let field_delta = (field_type & 0xF0) >> 4;
+ let field_type = match field_type & 0x0F {
+ 0x01 => {
+ self.pending_read_bool_value = Some(true);
+ Ok(TType::Bool)
+ }
+ 0x02 => {
+ self.pending_read_bool_value = Some(false);
+ Ok(TType::Bool)
+ }
+ ttu8 => u8_to_type(ttu8),
+ }?;
+
+ match field_type {
+ TType::Stop => Ok(
+ TFieldIdentifier::new::<Option<String>, String, Option<i16>>(
+ None,
+ TType::Stop,
+ None,
+ ),
+ ),
+ _ => {
+ if field_delta != 0 {
+ self.last_read_field_id += field_delta as i16;
+ } else {
+ self.last_read_field_id = self.read_i16()?;
+ };
+
+ Ok(TFieldIdentifier {
+ name: None,
+ field_type: field_type,
+ id: Some(self.last_read_field_id),
+ })
+ }
+ }
+ }
+
+ fn read_field_end(&mut self) -> ::Result<()> {
+ Ok(())
+ }
+
+ fn read_bool(&mut self) -> ::Result<bool> {
+ match self.pending_read_bool_value.take() {
+ Some(b) => Ok(b),
+ None => {
+ let b = self.read_byte()?;
+ match b {
+ 0x01 => Ok(true),
+ 0x02 => Ok(false),
+ unkn => Err(::Error::Protocol(::ProtocolError {
+ kind: ::ProtocolErrorKind::InvalidData,
+ message: format!("cannot convert {} into bool", unkn),
+ })),
+ }
+ }
+ }
+ }
+
+ fn read_bytes(&mut self) -> ::Result<Vec<u8>> {
+ let len = self.transport.read_varint::<u32>()?;
+ let mut buf = vec![0u8; len as usize];
+ self.transport
+ .read_exact(&mut buf)
+ .map_err(From::from)
+ .map(|_| buf)
+ }
+
+ fn read_i8(&mut self) -> ::Result<i8> {
+ self.read_byte().map(|i| i as i8)
+ }
+
+ fn read_i16(&mut self) -> ::Result<i16> {
+ self.transport.read_varint::<i16>().map_err(From::from)
+ }
+
+ fn read_i32(&mut self) -> ::Result<i32> {
+ self.transport.read_varint::<i32>().map_err(From::from)
+ }
+
+ fn read_i64(&mut self) -> ::Result<i64> {
+ self.transport.read_varint::<i64>().map_err(From::from)
+ }
+
+ fn read_double(&mut self) -> ::Result<f64> {
+ self.transport.read_f64::<BigEndian>().map_err(From::from)
+ }
+
+ fn read_string(&mut self) -> ::Result<String> {
+ let bytes = self.read_bytes()?;
+ String::from_utf8(bytes).map_err(From::from)
+ }
+
+ fn read_list_begin(&mut self) -> ::Result<TListIdentifier> {
+ let (element_type, element_count) = self.read_list_set_begin()?;
+ Ok(TListIdentifier::new(element_type, element_count))
+ }
+
+ fn read_list_end(&mut self) -> ::Result<()> {
+ Ok(())
+ }
+
+ fn read_set_begin(&mut self) -> ::Result<TSetIdentifier> {
+ let (element_type, element_count) = self.read_list_set_begin()?;
+ Ok(TSetIdentifier::new(element_type, element_count))
+ }
+
+ fn read_set_end(&mut self) -> ::Result<()> {
+ Ok(())
+ }
+
+ fn read_map_begin(&mut self) -> ::Result<TMapIdentifier> {
+ let element_count = self.transport.read_varint::<u32>()? as i32;
+ if element_count == 0 {
+ Ok(TMapIdentifier::new(None, None, 0))
+ } else {
+ let type_header = self.read_byte()?;
+ let key_type = collection_u8_to_type((type_header & 0xF0) >> 4)?;
+ let val_type = collection_u8_to_type(type_header & 0x0F)?;
+ Ok(TMapIdentifier::new(key_type, val_type, element_count))
+ }
+ }
+
+ fn read_map_end(&mut self) -> ::Result<()> {
+ Ok(())
+ }
+
+ // utility
+ //
+
+ fn read_byte(&mut self) -> ::Result<u8> {
+ let mut buf = [0u8; 1];
+ self.transport
+ .read_exact(&mut buf)
+ .map_err(From::from)
+ .map(|_| buf[0])
+ }
+}
+
+impl<T> io::Seek for TCompactInputProtocol<T>
+where
+ T: io::Seek + TReadTransport,
+{
+ fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
+ self.transport.seek(pos)
+ }
+}
+
+/// Factory for creating instances of `TCompactInputProtocol`.
+#[derive(Default)]
+pub struct TCompactInputProtocolFactory;
+
+impl TCompactInputProtocolFactory {
+ /// Create a `TCompactInputProtocolFactory`.
+ pub fn new() -> TCompactInputProtocolFactory {
+ TCompactInputProtocolFactory {}
+ }
+}
+
+impl TInputProtocolFactory for TCompactInputProtocolFactory {
+ fn create(&self, transport: Box<dyn TReadTransport + Send>) -> Box<dyn TInputProtocol + Send> {
+ Box::new(TCompactInputProtocol::new(transport))
+ }
+}
+
+/// Write messages using the Thrift compact protocol.
+///
+/// # Examples
+///
+/// Create and use a `TCompactOutputProtocol`.
+///
+/// ```no_run
+/// use thrift::protocol::{TCompactOutputProtocol, TOutputProtocol};
+/// use thrift::transport::TTcpChannel;
+///
+/// let mut channel = TTcpChannel::new();
+/// channel.open("localhost:9090").unwrap();
+///
+/// let mut protocol = TCompactOutputProtocol::new(channel);
+///
+/// protocol.write_bool(true).unwrap();
+/// protocol.write_string("test_string").unwrap();
+/// ```
+#[derive(Debug)]
+pub struct TCompactOutputProtocol<T>
+where
+ T: TWriteTransport,
+{
+ // Identifier of the last field serialized for a struct.
+ last_write_field_id: i16,
+ // Stack of the last written field ids (new entry added each time a nested struct is written).
+ write_field_id_stack: Vec<i16>,
+ // Field identifier of the boolean field to be written.
+ // Saved because boolean fields and their value are encoded in a single byte
+ pending_write_bool_field_identifier: Option<TFieldIdentifier>,
+ // Underlying transport used for byte-level operations.
+ transport: T,
+}
+
+impl<T> TCompactOutputProtocol<T>
+where
+ T: TWriteTransport,
+{
+ /// Create a `TCompactOutputProtocol` that writes bytes to `transport`.
+ pub fn new(transport: T) -> TCompactOutputProtocol<T> {
+ TCompactOutputProtocol {
+ last_write_field_id: 0,
+ write_field_id_stack: Vec::new(),
+ pending_write_bool_field_identifier: None,
+ transport: transport,
+ }
+ }
+
+ // FIXME: field_type as unconstrained u8 is bad
+ fn write_field_header(&mut self, field_type: u8, field_id: i16) -> ::Result<()> {
+ let field_delta = field_id - self.last_write_field_id;
+ if field_delta > 0 && field_delta < 15 {
+ self.write_byte(((field_delta as u8) << 4) | field_type)?;
+ } else {
+ self.write_byte(field_type)?;
+ self.write_i16(field_id)?;
+ }
+ self.last_write_field_id = field_id;
+ Ok(())
+ }
+
+ fn write_list_set_begin(&mut self, element_type: TType, element_count: i32) -> ::Result<()> {
+ let elem_identifier = collection_type_to_u8(element_type);
+ if element_count <= 14 {
+ let header = (element_count as u8) << 4 | elem_identifier;
+ self.write_byte(header)
+ } else {
+ let header = 0xF0 | elem_identifier;
+ self.write_byte(header)?;
+ self.transport
+ .write_varint(element_count as u32)
+ .map_err(From::from)
+ .map(|_| ())
+ }
+ }
+
+ fn assert_no_pending_bool_write(&self) {
+ if let Some(ref f) = self.pending_write_bool_field_identifier {
+ panic!("pending bool field {:?} not written", f)
+ }
+ }
+}
+
+impl<T> TOutputProtocol for TCompactOutputProtocol<T>
+where
+ T: TWriteTransport,
+{
+ fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> ::Result<()> {
+ self.write_byte(COMPACT_PROTOCOL_ID)?;
+ self.write_byte((u8::from(identifier.message_type) << 5) | COMPACT_VERSION)?;
+ self.write_i32(identifier.sequence_number)?;
+ self.write_string(&identifier.name)?;
+ Ok(())
+ }
+
+ fn write_message_end(&mut self) -> ::Result<()> {
+ self.assert_no_pending_bool_write();
+ Ok(())
+ }
+
+ fn write_struct_begin(&mut self, _: &TStructIdentifier) -> ::Result<()> {
+ self.write_field_id_stack.push(self.last_write_field_id);
+ self.last_write_field_id = 0;
+ Ok(())
+ }
+
+ fn write_struct_end(&mut self) -> ::Result<()> {
+ self.assert_no_pending_bool_write();
+ self.last_write_field_id = self
+ .write_field_id_stack
+ .pop()
+ .expect("should have previous field ids");
+ Ok(())
+ }
+
+ fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> ::Result<()> {
+ match identifier.field_type {
+ TType::Bool => {
+ if self.pending_write_bool_field_identifier.is_some() {
+ panic!(
+ "should not have a pending bool while writing another bool with id: \
+ {:?}",
+ identifier
+ )
+ }
+ self.pending_write_bool_field_identifier = Some(identifier.clone());
+ Ok(())
+ }
+ _ => {
+ let field_type = type_to_u8(identifier.field_type);
+ let field_id = identifier.id.expect("non-stop field should have field id");
+ self.write_field_header(field_type, field_id)
+ }
+ }
+ }
+
+ fn write_field_end(&mut self) -> ::Result<()> {
+ self.assert_no_pending_bool_write();
+ Ok(())
+ }
+
+ fn write_field_stop(&mut self) -> ::Result<()> {
+ self.assert_no_pending_bool_write();
+ self.write_byte(type_to_u8(TType::Stop))
+ }
+
+ fn write_bool(&mut self, b: bool) -> ::Result<()> {
+ match self.pending_write_bool_field_identifier.take() {
+ Some(pending) => {
+ let field_id = pending.id.expect("bool field should have a field id");
+ let field_type_as_u8 = if b { 0x01 } else { 0x02 };
+ self.write_field_header(field_type_as_u8, field_id)
+ }
+ None => {
+ if b {
+ self.write_byte(0x01)
+ } else {
+ self.write_byte(0x02)
+ }
+ }
+ }
+ }
+
+ fn write_bytes(&mut self, b: &[u8]) -> ::Result<()> {
+ self.transport.write_varint(b.len() as u32)?;
+ self.transport.write_all(b).map_err(From::from)
+ }
+
+ fn write_i8(&mut self, i: i8) -> ::Result<()> {
+ self.write_byte(i as u8)
+ }
+
+ fn write_i16(&mut self, i: i16) -> ::Result<()> {
+ self.transport
+ .write_varint(i)
+ .map_err(From::from)
+ .map(|_| ())
+ }
+
+ fn write_i32(&mut self, i: i32) -> ::Result<()> {
+ self.transport
+ .write_varint(i)
+ .map_err(From::from)
+ .map(|_| ())
+ }
+
+ fn write_i64(&mut self, i: i64) -> ::Result<()> {
+ self.transport
+ .write_varint(i)
+ .map_err(From::from)
+ .map(|_| ())
+ }
+
+ fn write_double(&mut self, d: f64) -> ::Result<()> {
+ self.transport.write_f64::<BigEndian>(d).map_err(From::from)
+ }
+
+ fn write_string(&mut self, s: &str) -> ::Result<()> {
+ self.write_bytes(s.as_bytes())
+ }
+
+ fn write_list_begin(&mut self, identifier: &TListIdentifier) -> ::Result<()> {
+ self.write_list_set_begin(identifier.element_type, identifier.size)
+ }
+
+ fn write_list_end(&mut self) -> ::Result<()> {
+ Ok(())
+ }
+
+ fn write_set_begin(&mut self, identifier: &TSetIdentifier) -> ::Result<()> {
+ self.write_list_set_begin(identifier.element_type, identifier.size)
+ }
+
+ fn write_set_end(&mut self) -> ::Result<()> {
+ Ok(())
+ }
+
+ fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> ::Result<()> {
+ if identifier.size == 0 {
+ self.write_byte(0)
+ } else {
+ self.transport.write_varint(identifier.size as u32)?;
+
+ let key_type = identifier
+ .key_type
+ .expect("map identifier to write should contain key type");
+ let key_type_byte = collection_type_to_u8(key_type) << 4;
+
+ let val_type = identifier
+ .value_type
+ .expect("map identifier to write should contain value type");
+ let val_type_byte = collection_type_to_u8(val_type);
+
+ let map_type_header = key_type_byte | val_type_byte;
+ self.write_byte(map_type_header)
+ }
+ }
+
+ fn write_map_end(&mut self) -> ::Result<()> {
+ Ok(())
+ }
+
+ fn flush(&mut self) -> ::Result<()> {
+ self.transport.flush().map_err(From::from)
+ }
+
+ // utility
+ //
+
+ fn write_byte(&mut self, b: u8) -> ::Result<()> {
+ self.transport.write(&[b]).map_err(From::from).map(|_| ())
+ }
+}
+
+/// Factory for creating instances of `TCompactOutputProtocol`.
+#[derive(Default)]
+pub struct TCompactOutputProtocolFactory;
+
+impl TCompactOutputProtocolFactory {
+ /// Create a `TCompactOutputProtocolFactory`.
+ pub fn new() -> TCompactOutputProtocolFactory {
+ TCompactOutputProtocolFactory {}
+ }
+}
+
+impl TOutputProtocolFactory for TCompactOutputProtocolFactory {
+ fn create(&self, transport: Box<dyn TWriteTransport + Send>) -> Box<dyn TOutputProtocol + Send> {
+ Box::new(TCompactOutputProtocol::new(transport))
+ }
+}
+
+fn collection_type_to_u8(field_type: TType) -> u8 {
+ match field_type {
+ TType::Bool => 0x01,
+ f => type_to_u8(f),
+ }
+}
+
+fn type_to_u8(field_type: TType) -> u8 {
+ match field_type {
+ TType::Stop => 0x00,
+ TType::I08 => 0x03, // equivalent to TType::Byte
+ TType::I16 => 0x04,
+ TType::I32 => 0x05,
+ TType::I64 => 0x06,
+ TType::Double => 0x07,
+ TType::String => 0x08,
+ TType::List => 0x09,
+ TType::Set => 0x0A,
+ TType::Map => 0x0B,
+ TType::Struct => 0x0C,
+ _ => panic!(format!(
+ "should not have attempted to convert {} to u8",
+ field_type
+ )),
+ }
+}
+
+fn collection_u8_to_type(b: u8) -> ::Result<TType> {
+ match b {
+ 0x01 => Ok(TType::Bool),
+ o => u8_to_type(o),
+ }
+}
+
+fn u8_to_type(b: u8) -> ::Result<TType> {
+ match b {
+ 0x00 => Ok(TType::Stop),
+ 0x03 => Ok(TType::I08), // equivalent to TType::Byte
+ 0x04 => Ok(TType::I16),
+ 0x05 => Ok(TType::I32),
+ 0x06 => Ok(TType::I64),
+ 0x07 => Ok(TType::Double),
+ 0x08 => Ok(TType::String),
+ 0x09 => Ok(TType::List),
+ 0x0A => Ok(TType::Set),
+ 0x0B => Ok(TType::Map),
+ 0x0C => Ok(TType::Struct),
+ unkn => Err(::Error::Protocol(::ProtocolError {
+ kind: ::ProtocolErrorKind::InvalidData,
+ message: format!("cannot convert {} into TType", unkn),
+ })),
+ }
+}
+
+#[cfg(test)]
+mod tests {
+
+ use protocol::{
+ TFieldIdentifier, TInputProtocol, TListIdentifier, TMapIdentifier, TMessageIdentifier,
+ TMessageType, TOutputProtocol, TSetIdentifier, TStructIdentifier, TType,
+ };
+ use transport::{ReadHalf, TBufferChannel, TIoChannel, WriteHalf};
+
+ use super::*;
+
+ #[test]
+ fn must_write_message_begin_0() {
+ let (_, mut o_prot) = test_objects();
+
+ assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new(
+ "foo",
+ TMessageType::Call,
+ 431
+ )));
+
+ #[cfg_attr(rustfmt, rustfmt::skip)]
+ let expected: [u8; 8] = [
+ 0x82, /* protocol ID */
+ 0x21, /* message type | protocol version */
+ 0xDE,
+ 0x06, /* zig-zag varint sequence number */
+ 0x03, /* message-name length */
+ 0x66,
+ 0x6F,
+ 0x6F /* "foo" */,
+ ];
+
+ assert_eq_written_bytes!(o_prot, expected);
+ }
+
+ #[test]
+ fn must_write_message_begin_1() {
+ let (_, mut o_prot) = test_objects();
+
+ assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new(
+ "bar",
+ TMessageType::Reply,
+ 991828
+ )));
+
+ #[cfg_attr(rustfmt, rustfmt::skip)]
+ let expected: [u8; 9] = [
+ 0x82, /* protocol ID */
+ 0x41, /* message type | protocol version */
+ 0xA8,
+ 0x89,
+ 0x79, /* zig-zag varint sequence number */
+ 0x03, /* message-name length */
+ 0x62,
+ 0x61,
+ 0x72 /* "bar" */,
+ ];
+
+ assert_eq_written_bytes!(o_prot, expected);
+ }
+
+ #[test]
+ fn must_round_trip_message_begin() {
+ let (mut i_prot, mut o_prot) = test_objects();
+
+ let ident = TMessageIdentifier::new("service_call", TMessageType::Call, 1283948);
+
+ assert_success!(o_prot.write_message_begin(&ident));
+
+ copy_write_buffer_to_read_buffer!(o_prot);
+
+ let res = assert_success!(i_prot.read_message_begin());
+ assert_eq!(&res, &ident);
+ }
+
+ #[test]
+ fn must_write_message_end() {
+ assert_no_write(|o| o.write_message_end());
+ }
+
+ // NOTE: structs and fields are tested together
+ //
+
+ #[test]
+ fn must_write_struct_with_delta_fields() {
+ let (_, mut o_prot) = test_objects();
+
+ // no bytes should be written however
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // write three fields with tiny field ids
+ // since they're small the field ids will be encoded as deltas
+
+ // since this is the first field (and it's zero) it gets the full varint write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 0)));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta > 0 and < 15 it can be encoded as a delta
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I16, 4)));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta > 0 and < 15 it can be encoded as a delta
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::List, 9)));
+ assert_success!(o_prot.write_field_end());
+
+ // now, finish the struct off
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ #[cfg_attr(rustfmt, rustfmt::skip)]
+ let expected: [u8; 5] = [
+ 0x03, /* field type */
+ 0x00, /* first field id */
+ 0x44, /* field delta (4) | field type */
+ 0x59, /* field delta (5) | field type */
+ 0x00 /* field stop */,
+ ];
+
+ assert_eq_written_bytes!(o_prot, expected);
+ }
+
+ #[test]
+ fn must_round_trip_struct_with_delta_fields() {
+ let (mut i_prot, mut o_prot) = test_objects();
+
+ // no bytes should be written however
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // write three fields with tiny field ids
+ // since they're small the field ids will be encoded as deltas
+
+ // since this is the first field (and it's zero) it gets the full varint write
+ let field_ident_1 = TFieldIdentifier::new("foo", TType::I08, 0);
+ assert_success!(o_prot.write_field_begin(&field_ident_1));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta > 0 and < 15 it can be encoded as a delta
+ let field_ident_2 = TFieldIdentifier::new("foo", TType::I16, 4);
+ assert_success!(o_prot.write_field_begin(&field_ident_2));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta > 0 and < 15 it can be encoded as a delta
+ let field_ident_3 = TFieldIdentifier::new("foo", TType::List, 9);
+ assert_success!(o_prot.write_field_begin(&field_ident_3));
+ assert_success!(o_prot.write_field_end());
+
+ // now, finish the struct off
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ copy_write_buffer_to_read_buffer!(o_prot);
+
+ // read the struct back
+ assert_success!(i_prot.read_struct_begin());
+
+ let read_ident_1 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_1,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_1
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_2 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_2,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_2
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_3 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_3,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_3
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_4 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_4,
+ TFieldIdentifier {
+ name: None,
+ field_type: TType::Stop,
+ id: None,
+ }
+ );
+
+ assert_success!(i_prot.read_struct_end());
+ }
+
+ #[test]
+ fn must_write_struct_with_non_zero_initial_field_and_delta_fields() {
+ let (_, mut o_prot) = test_objects();
+
+ // no bytes should be written however
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // write three fields with tiny field ids
+ // since they're small the field ids will be encoded as deltas
+
+ // gets a delta write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 1)));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta > 0 and < 15 it can be encoded as a delta
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 2)));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta > 0 and < 15 it can be encoded as a delta
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::String, 6)));
+ assert_success!(o_prot.write_field_end());
+
+ // now, finish the struct off
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ #[cfg_attr(rustfmt, rustfmt::skip)]
+ let expected: [u8; 4] = [
+ 0x15, /* field delta (1) | field type */
+ 0x1A, /* field delta (1) | field type */
+ 0x48, /* field delta (4) | field type */
+ 0x00 /* field stop */,
+ ];
+
+ assert_eq_written_bytes!(o_prot, expected);
+ }
+
+ #[test]
+ fn must_round_trip_struct_with_non_zero_initial_field_and_delta_fields() {
+ let (mut i_prot, mut o_prot) = test_objects();
+
+ // no bytes should be written however
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // write three fields with tiny field ids
+ // since they're small the field ids will be encoded as deltas
+
+ // gets a delta write
+ let field_ident_1 = TFieldIdentifier::new("foo", TType::I32, 1);
+ assert_success!(o_prot.write_field_begin(&field_ident_1));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta > 0 and < 15 it can be encoded as a delta
+ let field_ident_2 = TFieldIdentifier::new("foo", TType::Set, 2);
+ assert_success!(o_prot.write_field_begin(&field_ident_2));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta > 0 and < 15 it can be encoded as a delta
+ let field_ident_3 = TFieldIdentifier::new("foo", TType::String, 6);
+ assert_success!(o_prot.write_field_begin(&field_ident_3));
+ assert_success!(o_prot.write_field_end());
+
+ // now, finish the struct off
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ copy_write_buffer_to_read_buffer!(o_prot);
+
+ // read the struct back
+ assert_success!(i_prot.read_struct_begin());
+
+ let read_ident_1 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_1,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_1
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_2 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_2,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_2
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_3 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_3,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_3
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_4 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_4,
+ TFieldIdentifier {
+ name: None,
+ field_type: TType::Stop,
+ id: None,
+ }
+ );
+
+ assert_success!(i_prot.read_struct_end());
+ }
+
+ #[test]
+ fn must_write_struct_with_long_fields() {
+ let (_, mut o_prot) = test_objects();
+
+ // no bytes should be written however
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // write three fields with field ids that cannot be encoded as deltas
+
+ // since this is the first field (and it's zero) it gets the full varint write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 0)));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta is > 15 it is encoded as a zig-zag varint
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 16)));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta is > 15 it is encoded as a zig-zag varint
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 99)));
+ assert_success!(o_prot.write_field_end());
+
+ // now, finish the struct off
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ #[cfg_attr(rustfmt, rustfmt::skip)]
+ let expected: [u8; 8] = [
+ 0x05, /* field type */
+ 0x00, /* first field id */
+ 0x06, /* field type */
+ 0x20, /* zig-zag varint field id */
+ 0x0A, /* field type */
+ 0xC6,
+ 0x01, /* zig-zag varint field id */
+ 0x00 /* field stop */,
+ ];
+
+ assert_eq_written_bytes!(o_prot, expected);
+ }
+
+ #[test]
+ fn must_round_trip_struct_with_long_fields() {
+ let (mut i_prot, mut o_prot) = test_objects();
+
+ // no bytes should be written however
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // write three fields with field ids that cannot be encoded as deltas
+
+ // since this is the first field (and it's zero) it gets the full varint write
+ let field_ident_1 = TFieldIdentifier::new("foo", TType::I32, 0);
+ assert_success!(o_prot.write_field_begin(&field_ident_1));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta is > 15 it is encoded as a zig-zag varint
+ let field_ident_2 = TFieldIdentifier::new("foo", TType::I64, 16);
+ assert_success!(o_prot.write_field_begin(&field_ident_2));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta is > 15 it is encoded as a zig-zag varint
+ let field_ident_3 = TFieldIdentifier::new("foo", TType::Set, 99);
+ assert_success!(o_prot.write_field_begin(&field_ident_3));
+ assert_success!(o_prot.write_field_end());
+
+ // now, finish the struct off
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ copy_write_buffer_to_read_buffer!(o_prot);
+
+ // read the struct back
+ assert_success!(i_prot.read_struct_begin());
+
+ let read_ident_1 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_1,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_1
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_2 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_2,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_2
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_3 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_3,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_3
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_4 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_4,
+ TFieldIdentifier {
+ name: None,
+ field_type: TType::Stop,
+ id: None,
+ }
+ );
+
+ assert_success!(i_prot.read_struct_end());
+ }
+
+ #[test]
+ fn must_write_struct_with_mix_of_long_and_delta_fields() {
+ let (_, mut o_prot) = test_objects();
+
+ // no bytes should be written however
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // write three fields with field ids that cannot be encoded as deltas
+
+ // since the delta is > 0 and < 15 it gets a delta write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1)));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta > 0 and < 15 it gets a delta write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 9)));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta is > 15 it is encoded as a zig-zag varint
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 1000)));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta is > 15 it is encoded as a zig-zag varint
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 2001)));
+ assert_success!(o_prot.write_field_end());
+
+ // since this is only 3 up from the previous it is recorded as a delta
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 2004)));
+ assert_success!(o_prot.write_field_end());
+
+ // now, finish the struct off
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ #[cfg_attr(rustfmt, rustfmt::skip)]
+ let expected: [u8; 10] = [
+ 0x16, /* field delta (1) | field type */
+ 0x85, /* field delta (8) | field type */
+ 0x0A, /* field type */
+ 0xD0,
+ 0x0F, /* zig-zag varint field id */
+ 0x0A, /* field type */
+ 0xA2,
+ 0x1F, /* zig-zag varint field id */
+ 0x3A, /* field delta (3) | field type */
+ 0x00 /* field stop */,
+ ];
+
+ assert_eq_written_bytes!(o_prot, expected);
+ }
+
+ #[test]
+ fn must_round_trip_struct_with_mix_of_long_and_delta_fields() {
+ let (mut i_prot, mut o_prot) = test_objects();
+
+ // no bytes should be written however
+ let struct_ident = TStructIdentifier::new("foo");
+ assert_success!(o_prot.write_struct_begin(&struct_ident));
+
+ // write three fields with field ids that cannot be encoded as deltas
+
+ // since the delta is > 0 and < 15 it gets a delta write
+ let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1);
+ assert_success!(o_prot.write_field_begin(&field_ident_1));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta > 0 and < 15 it gets a delta write
+ let field_ident_2 = TFieldIdentifier::new("foo", TType::I32, 9);
+ assert_success!(o_prot.write_field_begin(&field_ident_2));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta is > 15 it is encoded as a zig-zag varint
+ let field_ident_3 = TFieldIdentifier::new("foo", TType::Set, 1000);
+ assert_success!(o_prot.write_field_begin(&field_ident_3));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta is > 15 it is encoded as a zig-zag varint
+ let field_ident_4 = TFieldIdentifier::new("foo", TType::Set, 2001);
+ assert_success!(o_prot.write_field_begin(&field_ident_4));
+ assert_success!(o_prot.write_field_end());
+
+ // since this is only 3 up from the previous it is recorded as a delta
+ let field_ident_5 = TFieldIdentifier::new("foo", TType::Set, 2004);
+ assert_success!(o_prot.write_field_begin(&field_ident_5));
+ assert_success!(o_prot.write_field_end());
+
+ // now, finish the struct off
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ copy_write_buffer_to_read_buffer!(o_prot);
+
+ // read the struct back
+ assert_success!(i_prot.read_struct_begin());
+
+ let read_ident_1 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_1,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_1
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_2 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_2,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_2
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_3 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_3,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_3
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_4 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_4,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_4
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_5 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_5,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_5
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_6 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_6,
+ TFieldIdentifier {
+ name: None,
+ field_type: TType::Stop,
+ id: None,
+ }
+ );
+
+ assert_success!(i_prot.read_struct_end());
+ }
+
+ #[test]
+ fn must_write_nested_structs_0() {
+ // last field of the containing struct is a delta
+ // first field of the the contained struct is a delta
+
+ let (_, mut o_prot) = test_objects();
+
+ // start containing struct
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // containing struct
+ // since the delta is > 0 and < 15 it gets a delta write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1)));
+ assert_success!(o_prot.write_field_end());
+
+ // containing struct
+ // since this delta > 0 and < 15 it gets a delta write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 9)));
+ assert_success!(o_prot.write_field_end());
+
+ // start contained struct
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // contained struct
+ // since the delta is > 0 and < 15 it gets a delta write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 7)));
+ assert_success!(o_prot.write_field_end());
+
+ // contained struct
+ // since this delta > 15 it gets a full write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 24)));
+ assert_success!(o_prot.write_field_end());
+
+ // end contained struct
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ // end containing struct
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ #[cfg_attr(rustfmt, rustfmt::skip)]
+ let expected: [u8; 7] = [
+ 0x16, /* field delta (1) | field type */
+ 0x85, /* field delta (8) | field type */
+ 0x73, /* field delta (7) | field type */
+ 0x07, /* field type */
+ 0x30, /* zig-zag varint field id */
+ 0x00, /* field stop - contained */
+ 0x00 /* field stop - containing */,
+ ];
+
+ assert_eq_written_bytes!(o_prot, expected);
+ }
+
+ #[test]
+ fn must_round_trip_nested_structs_0() {
+ // last field of the containing struct is a delta
+ // first field of the the contained struct is a delta
+
+ let (mut i_prot, mut o_prot) = test_objects();
+
+ // start containing struct
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // containing struct
+ // since the delta is > 0 and < 15 it gets a delta write
+ let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1);
+ assert_success!(o_prot.write_field_begin(&field_ident_1));
+ assert_success!(o_prot.write_field_end());
+
+ // containing struct
+ // since this delta > 0 and < 15 it gets a delta write
+ let field_ident_2 = TFieldIdentifier::new("foo", TType::I32, 9);
+ assert_success!(o_prot.write_field_begin(&field_ident_2));
+ assert_success!(o_prot.write_field_end());
+
+ // start contained struct
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // contained struct
+ // since the delta is > 0 and < 15 it gets a delta write
+ let field_ident_3 = TFieldIdentifier::new("foo", TType::I08, 7);
+ assert_success!(o_prot.write_field_begin(&field_ident_3));
+ assert_success!(o_prot.write_field_end());
+
+ // contained struct
+ // since this delta > 15 it gets a full write
+ let field_ident_4 = TFieldIdentifier::new("foo", TType::Double, 24);
+ assert_success!(o_prot.write_field_begin(&field_ident_4));
+ assert_success!(o_prot.write_field_end());
+
+ // end contained struct
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ // end containing struct
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ copy_write_buffer_to_read_buffer!(o_prot);
+
+ // read containing struct back
+ assert_success!(i_prot.read_struct_begin());
+
+ let read_ident_1 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_1,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_1
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_2 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_2,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_2
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ // read contained struct back
+ assert_success!(i_prot.read_struct_begin());
+
+ let read_ident_3 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_3,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_3
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_4 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_4,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_4
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ // end contained struct
+ let read_ident_6 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_6,
+ TFieldIdentifier {
+ name: None,
+ field_type: TType::Stop,
+ id: None,
+ }
+ );
+ assert_success!(i_prot.read_struct_end());
+
+ // end containing struct
+ let read_ident_7 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_7,
+ TFieldIdentifier {
+ name: None,
+ field_type: TType::Stop,
+ id: None,
+ }
+ );
+ assert_success!(i_prot.read_struct_end());
+ }
+
+ #[test]
+ fn must_write_nested_structs_1() {
+ // last field of the containing struct is a delta
+ // first field of the the contained struct is a full write
+
+ let (_, mut o_prot) = test_objects();
+
+ // start containing struct
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // containing struct
+ // since the delta is > 0 and < 15 it gets a delta write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1)));
+ assert_success!(o_prot.write_field_end());
+
+ // containing struct
+ // since this delta > 0 and < 15 it gets a delta write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 9)));
+ assert_success!(o_prot.write_field_end());
+
+ // start contained struct
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // contained struct
+ // since this delta > 15 it gets a full write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 24)));
+ assert_success!(o_prot.write_field_end());
+
+ // contained struct
+ // since the delta is > 0 and < 15 it gets a delta write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 27)));
+ assert_success!(o_prot.write_field_end());
+
+ // end contained struct
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ // end containing struct
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ #[cfg_attr(rustfmt, rustfmt::skip)]
+ let expected: [u8; 7] = [
+ 0x16, /* field delta (1) | field type */
+ 0x85, /* field delta (8) | field type */
+ 0x07, /* field type */
+ 0x30, /* zig-zag varint field id */
+ 0x33, /* field delta (3) | field type */
+ 0x00, /* field stop - contained */
+ 0x00 /* field stop - containing */,
+ ];
+
+ assert_eq_written_bytes!(o_prot, expected);
+ }
+
+ #[test]
+ fn must_round_trip_nested_structs_1() {
+ // last field of the containing struct is a delta
+ // first field of the the contained struct is a full write
+
+ let (mut i_prot, mut o_prot) = test_objects();
+
+ // start containing struct
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // containing struct
+ // since the delta is > 0 and < 15 it gets a delta write
+ let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1);
+ assert_success!(o_prot.write_field_begin(&field_ident_1));
+ assert_success!(o_prot.write_field_end());
+
+ // containing struct
+ // since this delta > 0 and < 15 it gets a delta write
+ let field_ident_2 = TFieldIdentifier::new("foo", TType::I32, 9);
+ assert_success!(o_prot.write_field_begin(&field_ident_2));
+ assert_success!(o_prot.write_field_end());
+
+ // start contained struct
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // contained struct
+ // since this delta > 15 it gets a full write
+ let field_ident_3 = TFieldIdentifier::new("foo", TType::Double, 24);
+ assert_success!(o_prot.write_field_begin(&field_ident_3));
+ assert_success!(o_prot.write_field_end());
+
+ // contained struct
+ // since the delta is > 0 and < 15 it gets a delta write
+ let field_ident_4 = TFieldIdentifier::new("foo", TType::I08, 27);
+ assert_success!(o_prot.write_field_begin(&field_ident_4));
+ assert_success!(o_prot.write_field_end());
+
+ // end contained struct
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ // end containing struct
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ copy_write_buffer_to_read_buffer!(o_prot);
+
+ // read containing struct back
+ assert_success!(i_prot.read_struct_begin());
+
+ let read_ident_1 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_1,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_1
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_2 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_2,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_2
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ // read contained struct back
+ assert_success!(i_prot.read_struct_begin());
+
+ let read_ident_3 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_3,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_3
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_4 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_4,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_4
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ // end contained struct
+ let read_ident_6 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_6,
+ TFieldIdentifier {
+ name: None,
+ field_type: TType::Stop,
+ id: None,
+ }
+ );
+ assert_success!(i_prot.read_struct_end());
+
+ // end containing struct
+ let read_ident_7 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_7,
+ TFieldIdentifier {
+ name: None,
+ field_type: TType::Stop,
+ id: None,
+ }
+ );
+ assert_success!(i_prot.read_struct_end());
+ }
+
+ #[test]
+ fn must_write_nested_structs_2() {
+ // last field of the containing struct is a full write
+ // first field of the the contained struct is a delta write
+
+ let (_, mut o_prot) = test_objects();
+
+ // start containing struct
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // containing struct
+ // since the delta is > 0 and < 15 it gets a delta write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1)));
+ assert_success!(o_prot.write_field_end());
+
+ // containing struct
+ // since this delta > 15 it gets a full write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::String, 21)));
+ assert_success!(o_prot.write_field_end());
+
+ // start contained struct
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // contained struct
+ // since this delta > 0 and < 15 it gets a delta write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 7)));
+ assert_success!(o_prot.write_field_end());
+
+ // contained struct
+ // since the delta is > 0 and < 15 it gets a delta write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 10)));
+ assert_success!(o_prot.write_field_end());
+
+ // end contained struct
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ // end containing struct
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ #[cfg_attr(rustfmt, rustfmt::skip)]
+ let expected: [u8; 7] = [
+ 0x16, /* field delta (1) | field type */
+ 0x08, /* field type */
+ 0x2A, /* zig-zag varint field id */
+ 0x77, /* field delta(7) | field type */
+ 0x33, /* field delta (3) | field type */
+ 0x00, /* field stop - contained */
+ 0x00 /* field stop - containing */,
+ ];
+
+ assert_eq_written_bytes!(o_prot, expected);
+ }
+
+ #[test]
+ fn must_round_trip_nested_structs_2() {
+ let (mut i_prot, mut o_prot) = test_objects();
+
+ // start containing struct
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // containing struct
+ // since the delta is > 0 and < 15 it gets a delta write
+ let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1);
+ assert_success!(o_prot.write_field_begin(&field_ident_1));
+ assert_success!(o_prot.write_field_end());
+
+ // containing struct
+ // since this delta > 15 it gets a full write
+ let field_ident_2 = TFieldIdentifier::new("foo", TType::String, 21);
+ assert_success!(o_prot.write_field_begin(&field_ident_2));
+ assert_success!(o_prot.write_field_end());
+
+ // start contained struct
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // contained struct
+ // since this delta > 0 and < 15 it gets a delta write
+ let field_ident_3 = TFieldIdentifier::new("foo", TType::Double, 7);
+ assert_success!(o_prot.write_field_begin(&field_ident_3));
+ assert_success!(o_prot.write_field_end());
+
+ // contained struct
+ // since the delta is > 0 and < 15 it gets a delta write
+ let field_ident_4 = TFieldIdentifier::new("foo", TType::I08, 10);
+ assert_success!(o_prot.write_field_begin(&field_ident_4));
+ assert_success!(o_prot.write_field_end());
+
+ // end contained struct
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ // end containing struct
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ copy_write_buffer_to_read_buffer!(o_prot);
+
+ // read containing struct back
+ assert_success!(i_prot.read_struct_begin());
+
+ let read_ident_1 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_1,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_1
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_2 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_2,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_2
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ // read contained struct back
+ assert_success!(i_prot.read_struct_begin());
+
+ let read_ident_3 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_3,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_3
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_4 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_4,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_4
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ // end contained struct
+ let read_ident_6 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_6,
+ TFieldIdentifier {
+ name: None,
+ field_type: TType::Stop,
+ id: None,
+ }
+ );
+ assert_success!(i_prot.read_struct_end());
+
+ // end containing struct
+ let read_ident_7 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_7,
+ TFieldIdentifier {
+ name: None,
+ field_type: TType::Stop,
+ id: None,
+ }
+ );
+ assert_success!(i_prot.read_struct_end());
+ }
+
+ #[test]
+ fn must_write_nested_structs_3() {
+ // last field of the containing struct is a full write
+ // first field of the the contained struct is a full write
+
+ let (_, mut o_prot) = test_objects();
+
+ // start containing struct
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // containing struct
+ // since the delta is > 0 and < 15 it gets a delta write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1)));
+ assert_success!(o_prot.write_field_end());
+
+ // containing struct
+ // since this delta > 15 it gets a full write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::String, 21)));
+ assert_success!(o_prot.write_field_end());
+
+ // start contained struct
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // contained struct
+ // since this delta > 15 it gets a full write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 21)));
+ assert_success!(o_prot.write_field_end());
+
+ // contained struct
+ // since the delta is > 0 and < 15 it gets a delta write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 27)));
+ assert_success!(o_prot.write_field_end());
+
+ // end contained struct
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ // end containing struct
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ #[cfg_attr(rustfmt, rustfmt::skip)]
+ let expected: [u8; 8] = [
+ 0x16, /* field delta (1) | field type */
+ 0x08, /* field type */
+ 0x2A, /* zig-zag varint field id */
+ 0x07, /* field type */
+ 0x2A, /* zig-zag varint field id */
+ 0x63, /* field delta (6) | field type */
+ 0x00, /* field stop - contained */
+ 0x00 /* field stop - containing */,
+ ];
+
+ assert_eq_written_bytes!(o_prot, expected);
+ }
+
+ #[test]
+ fn must_round_trip_nested_structs_3() {
+ // last field of the containing struct is a full write
+ // first field of the the contained struct is a full write
+
+ let (mut i_prot, mut o_prot) = test_objects();
+
+ // start containing struct
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // containing struct
+ // since the delta is > 0 and < 15 it gets a delta write
+ let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1);
+ assert_success!(o_prot.write_field_begin(&field_ident_1));
+ assert_success!(o_prot.write_field_end());
+
+ // containing struct
+ // since this delta > 15 it gets a full write
+ let field_ident_2 = TFieldIdentifier::new("foo", TType::String, 21);
+ assert_success!(o_prot.write_field_begin(&field_ident_2));
+ assert_success!(o_prot.write_field_end());
+
+ // start contained struct
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // contained struct
+ // since this delta > 15 it gets a full write
+ let field_ident_3 = TFieldIdentifier::new("foo", TType::Double, 21);
+ assert_success!(o_prot.write_field_begin(&field_ident_3));
+ assert_success!(o_prot.write_field_end());
+
+ // contained struct
+ // since the delta is > 0 and < 15 it gets a delta write
+ let field_ident_4 = TFieldIdentifier::new("foo", TType::I08, 27);
+ assert_success!(o_prot.write_field_begin(&field_ident_4));
+ assert_success!(o_prot.write_field_end());
+
+ // end contained struct
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ // end containing struct
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ copy_write_buffer_to_read_buffer!(o_prot);
+
+ // read containing struct back
+ assert_success!(i_prot.read_struct_begin());
+
+ let read_ident_1 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_1,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_1
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_2 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_2,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_2
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ // read contained struct back
+ assert_success!(i_prot.read_struct_begin());
+
+ let read_ident_3 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_3,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_3
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_4 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_4,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_4
+ }
+ );
+ assert_success!(i_prot.read_field_end());
+
+ // end contained struct
+ let read_ident_6 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_6,
+ TFieldIdentifier {
+ name: None,
+ field_type: TType::Stop,
+ id: None,
+ }
+ );
+ assert_success!(i_prot.read_struct_end());
+
+ // end containing struct
+ let read_ident_7 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_7,
+ TFieldIdentifier {
+ name: None,
+ field_type: TType::Stop,
+ id: None,
+ }
+ );
+ assert_success!(i_prot.read_struct_end());
+ }
+
+ #[test]
+ fn must_write_bool_field() {
+ let (_, mut o_prot) = test_objects();
+
+ // no bytes should be written however
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+ // write three fields with field ids that cannot be encoded as deltas
+
+ // since the delta is > 0 and < 16 it gets a delta write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1)));
+ assert_success!(o_prot.write_bool(true));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta > 0 and < 15 it gets a delta write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 9)));
+ assert_success!(o_prot.write_bool(false));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta > 15 it gets a full write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 26)));
+ assert_success!(o_prot.write_bool(true));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta > 15 it gets a full write
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 45)));
+ assert_success!(o_prot.write_bool(false));
+ assert_success!(o_prot.write_field_end());
+
+ // now, finish the struct off
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ #[cfg_attr(rustfmt, rustfmt::skip)]
+ let expected: [u8; 7] = [
+ 0x11, /* field delta (1) | true */
+ 0x82, /* field delta (8) | false */
+ 0x01, /* true */
+ 0x34, /* field id */
+ 0x02, /* false */
+ 0x5A, /* field id */
+ 0x00 /* stop field */,
+ ];
+
+ assert_eq_written_bytes!(o_prot, expected);
+ }
+
+ #[test]
+ fn must_round_trip_bool_field() {
+ let (mut i_prot, mut o_prot) = test_objects();
+
+ // no bytes should be written however
+ let struct_ident = TStructIdentifier::new("foo");
+ assert_success!(o_prot.write_struct_begin(&struct_ident));
+
+ // write two fields
+
+ // since the delta is > 0 and < 16 it gets a delta write
+ let field_ident_1 = TFieldIdentifier::new("foo", TType::Bool, 1);
+ assert_success!(o_prot.write_field_begin(&field_ident_1));
+ assert_success!(o_prot.write_bool(true));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta > 0 and < 15 it gets a delta write
+ let field_ident_2 = TFieldIdentifier::new("foo", TType::Bool, 9);
+ assert_success!(o_prot.write_field_begin(&field_ident_2));
+ assert_success!(o_prot.write_bool(false));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta > 15 it gets a full write
+ let field_ident_3 = TFieldIdentifier::new("foo", TType::Bool, 26);
+ assert_success!(o_prot.write_field_begin(&field_ident_3));
+ assert_success!(o_prot.write_bool(true));
+ assert_success!(o_prot.write_field_end());
+
+ // since this delta > 15 it gets a full write
+ let field_ident_4 = TFieldIdentifier::new("foo", TType::Bool, 45);
+ assert_success!(o_prot.write_field_begin(&field_ident_4));
+ assert_success!(o_prot.write_bool(false));
+ assert_success!(o_prot.write_field_end());
+
+ // now, finish the struct off
+ assert_success!(o_prot.write_field_stop());
+ assert_success!(o_prot.write_struct_end());
+
+ copy_write_buffer_to_read_buffer!(o_prot);
+
+ // read the struct back
+ assert_success!(i_prot.read_struct_begin());
+
+ let read_ident_1 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_1,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_1
+ }
+ );
+ let read_value_1 = assert_success!(i_prot.read_bool());
+ assert_eq!(read_value_1, true);
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_2 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_2,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_2
+ }
+ );
+ let read_value_2 = assert_success!(i_prot.read_bool());
+ assert_eq!(read_value_2, false);
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_3 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_3,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_3
+ }
+ );
+ let read_value_3 = assert_success!(i_prot.read_bool());
+ assert_eq!(read_value_3, true);
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_4 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_4,
+ TFieldIdentifier {
+ name: None,
+ ..field_ident_4
+ }
+ );
+ let read_value_4 = assert_success!(i_prot.read_bool());
+ assert_eq!(read_value_4, false);
+ assert_success!(i_prot.read_field_end());
+
+ let read_ident_5 = assert_success!(i_prot.read_field_begin());
+ assert_eq!(
+ read_ident_5,
+ TFieldIdentifier {
+ name: None,
+ field_type: TType::Stop,
+ id: None,
+ }
+ );
+
+ assert_success!(i_prot.read_struct_end());
+ }
+
+ #[test]
+ #[should_panic]
+ fn must_fail_if_write_field_end_without_writing_bool_value() {
+ let (_, mut o_prot) = test_objects();
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1)));
+ o_prot.write_field_end().unwrap();
+ }
+
+ #[test]
+ #[should_panic]
+ fn must_fail_if_write_stop_field_without_writing_bool_value() {
+ let (_, mut o_prot) = test_objects();
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1)));
+ o_prot.write_field_stop().unwrap();
+ }
+
+ #[test]
+ #[should_panic]
+ fn must_fail_if_write_struct_end_without_writing_bool_value() {
+ let (_, mut o_prot) = test_objects();
+ assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+ assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1)));
+ o_prot.write_struct_end().unwrap();
+ }
+
+ #[test]
+ #[should_panic]
+ fn must_fail_if_write_struct_end_without_any_fields() {
+ let (_, mut o_prot) = test_objects();
+ o_prot.write_struct_end().unwrap();
+ }
+
+ #[test]
+ fn must_write_field_end() {
+ assert_no_write(|o| o.write_field_end());
+ }
+
+ #[test]
+ fn must_write_small_sized_list_begin() {
+ let (_, mut o_prot) = test_objects();
+
+ assert_success!(o_prot.write_list_begin(&TListIdentifier::new(TType::I64, 4)));
+
+ let expected: [u8; 1] = [0x46 /* size | elem_type */];
+
+ assert_eq_written_bytes!(o_prot, expected);
+ }
+
+ #[test]
+ fn must_round_trip_small_sized_list_begin() {
+ let (mut i_prot, mut o_prot) = test_objects();
+
+ let ident = TListIdentifier::new(TType::I08, 10);
+
+ assert_success!(o_prot.write_list_begin(&ident));
+
+ copy_write_buffer_to_read_buffer!(o_prot);
+
+ let res = assert_success!(i_prot.read_list_begin());
+ assert_eq!(&res, &ident);
+ }
+
+ #[test]
+ fn must_write_large_sized_list_begin() {
+ let (_, mut o_prot) = test_objects();
+
+ let res = o_prot.write_list_begin(&TListIdentifier::new(TType::List, 9999));
+ assert!(res.is_ok());
+
+ let expected: [u8; 3] = [
+ 0xF9, /* 0xF0 | elem_type */
+ 0x8F, 0x4E, /* size as varint */
+ ];
+
+ assert_eq_written_bytes!(o_prot, expected);
+ }
+
+ #[test]
+ fn must_round_trip_large_sized_list_begin() {
+ let (mut i_prot, mut o_prot) = test_objects();
+
+ let ident = TListIdentifier::new(TType::Set, 47381);
+
+ assert_success!(o_prot.write_list_begin(&ident));
+
+ copy_write_buffer_to_read_buffer!(o_prot);
+
+ let res = assert_success!(i_prot.read_list_begin());
+ assert_eq!(&res, &ident);
+ }
+
+ #[test]
+ fn must_write_list_end() {
+ assert_no_write(|o| o.write_list_end());
+ }
+
+ #[test]
+ fn must_write_small_sized_set_begin() {
+ let (_, mut o_prot) = test_objects();
+
+ assert_success!(o_prot.write_set_begin(&TSetIdentifier::new(TType::Struct, 2)));
+
+ let expected: [u8; 1] = [0x2C /* size | elem_type */];
+
+ assert_eq_written_bytes!(o_prot, expected);
+ }
+
+ #[test]
+ fn must_round_trip_small_sized_set_begin() {
+ let (mut i_prot, mut o_prot) = test_objects();
+
+ let ident = TSetIdentifier::new(TType::I16, 7);
+
+ assert_success!(o_prot.write_set_begin(&ident));
+
+ copy_write_buffer_to_read_buffer!(o_prot);
+
+ let res = assert_success!(i_prot.read_set_begin());
+ assert_eq!(&res, &ident);
+ }
+
+ #[test]
+ fn must_write_large_sized_set_begin() {
+ let (_, mut o_prot) = test_objects();
+
+ assert_success!(o_prot.write_set_begin(&TSetIdentifier::new(TType::Double, 23891)));
+
+ let expected: [u8; 4] = [
+ 0xF7, /* 0xF0 | elem_type */
+ 0xD3, 0xBA, 0x01, /* size as varint */
+ ];
+
+ assert_eq_written_bytes!(o_prot, expected);
+ }
+
+ #[test]
+ fn must_round_trip_large_sized_set_begin() {
+ let (mut i_prot, mut o_prot) = test_objects();
+
+ let ident = TSetIdentifier::new(TType::Map, 3928429);
+
+ assert_success!(o_prot.write_set_begin(&ident));
+
+ copy_write_buffer_to_read_buffer!(o_prot);
+
+ let res = assert_success!(i_prot.read_set_begin());
+ assert_eq!(&res, &ident);
+ }
+
+ #[test]
+ fn must_write_set_end() {
+ assert_no_write(|o| o.write_set_end());
+ }
+
+ #[test]
+ fn must_write_zero_sized_map_begin() {
+ let (_, mut o_prot) = test_objects();
+
+ assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::String, TType::I32, 0)));
+
+ let expected: [u8; 1] = [0x00]; // since size is zero we don't write anything
+
+ assert_eq_written_bytes!(o_prot, expected);
+ }
+
+ #[test]
+ fn must_read_zero_sized_map_begin() {
+ let (mut i_prot, mut o_prot) = test_objects();
+
+ assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::Double, TType::I32, 0)));
+
+ copy_write_buffer_to_read_buffer!(o_prot);
+
+ let res = assert_success!(i_prot.read_map_begin());
+ assert_eq!(
+ &res,
+ &TMapIdentifier {
+ key_type: None,
+ value_type: None,
+ size: 0,
+ }
+ );
+ }
+
+ #[test]
+ fn must_write_map_begin() {
+ let (_, mut o_prot) = test_objects();
+
+ assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(
+ TType::Double,
+ TType::String,
+ 238
+ )));
+
+ let expected: [u8; 3] = [
+ 0xEE, 0x01, /* size as varint */
+ 0x78, /* key type | val type */
+ ];
+
+ assert_eq_written_bytes!(o_prot, expected);
+ }
+
+ #[test]
+ fn must_round_trip_map_begin() {
+ let (mut i_prot, mut o_prot) = test_objects();
+
+ let ident = TMapIdentifier::new(TType::Map, TType::List, 1928349);
+
+ assert_success!(o_prot.write_map_begin(&ident));
+
+ copy_write_buffer_to_read_buffer!(o_prot);
+
+ let res = assert_success!(i_prot.read_map_begin());
+ assert_eq!(&res, &ident);
+ }
+
+ #[test]
+ fn must_write_map_end() {
+ assert_no_write(|o| o.write_map_end());
+ }
+
+ #[test]
+ fn must_write_map_with_bool_key_and_value() {
+ let (_, mut o_prot) = test_objects();
+
+ assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::Bool, TType::Bool, 1)));
+ assert_success!(o_prot.write_bool(true));
+ assert_success!(o_prot.write_bool(false));
+ assert_success!(o_prot.write_map_end());
+
+ let expected: [u8; 4] = [
+ 0x01, /* size as varint */
+ 0x11, /* key type | val type */
+ 0x01, /* key: true */
+ 0x02, /* val: false */
+ ];
+
+ assert_eq_written_bytes!(o_prot, expected);
+ }
+
+ #[test]
+ fn must_round_trip_map_with_bool_value() {
+ let (mut i_prot, mut o_prot) = test_objects();
+
+ let map_ident = TMapIdentifier::new(TType::Bool, TType::Bool, 2);
+ assert_success!(o_prot.write_map_begin(&map_ident));
+ assert_success!(o_prot.write_bool(true));
+ assert_success!(o_prot.write_bool(false));
+ assert_success!(o_prot.write_bool(false));
+ assert_success!(o_prot.write_bool(true));
+ assert_success!(o_prot.write_map_end());
+
+ copy_write_buffer_to_read_buffer!(o_prot);
+
+ // map header
+ let rcvd_ident = assert_success!(i_prot.read_map_begin());
+ assert_eq!(&rcvd_ident, &map_ident);
+ // key 1
+ let b = assert_success!(i_prot.read_bool());
+ assert_eq!(b, true);
+ // val 1
+ let b = assert_success!(i_prot.read_bool());
+ assert_eq!(b, false);
+ // key 2
+ let b = assert_success!(i_prot.read_bool());
+ assert_eq!(b, false);
+ // val 2
+ let b = assert_success!(i_prot.read_bool());
+ assert_eq!(b, true);
+ // map end
+ assert_success!(i_prot.read_map_end());
+ }
+
+ #[test]
+ fn must_read_map_end() {
+ let (mut i_prot, _) = test_objects();
+ assert!(i_prot.read_map_end().is_ok()); // will blow up if we try to read from empty buffer
+ }
+
+ fn test_objects() -> (
+ TCompactInputProtocol<ReadHalf<TBufferChannel>>,
+ TCompactOutputProtocol<WriteHalf<TBufferChannel>>,
+ ) {
+ let mem = TBufferChannel::with_capacity(80, 80);
+
+ let (r_mem, w_mem) = mem.split().unwrap();
+
+ let i_prot = TCompactInputProtocol::new(r_mem);
+ let o_prot = TCompactOutputProtocol::new(w_mem);
+
+ (i_prot, o_prot)
+ }
+
+ fn assert_no_write<F>(mut write_fn: F)
+ where
+ F: FnMut(&mut TCompactOutputProtocol<WriteHalf<TBufferChannel>>) -> ::Result<()>,
+ {
+ let (_, mut o_prot) = test_objects();
+ assert!(write_fn(&mut o_prot).is_ok());
+ assert_eq!(o_prot.transport.write_bytes().len(), 0);
+ }
+}