thrift/protocol/
compact.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
19use integer_encoding::{VarIntReader, VarIntWriter};
20use std::convert::{From, TryFrom};
21use std::io;
22
23use super::{
24    TFieldIdentifier, TInputProtocol, TInputProtocolFactory, TListIdentifier, TMapIdentifier,
25    TMessageIdentifier, TMessageType,
26};
27use super::{TOutputProtocol, TOutputProtocolFactory, TSetIdentifier, TStructIdentifier, TType};
28use crate::transport::{TReadTransport, TWriteTransport};
29
30const COMPACT_PROTOCOL_ID: u8 = 0x82;
31const COMPACT_VERSION: u8 = 0x01;
32const COMPACT_VERSION_MASK: u8 = 0x1F;
33
34/// Read messages encoded in the Thrift compact protocol.
35///
36/// # Examples
37///
38/// Create and use a `TCompactInputProtocol`.
39///
40/// ```no_run
41/// use thrift::protocol::{TCompactInputProtocol, TInputProtocol};
42/// use thrift::transport::TTcpChannel;
43///
44/// let mut channel = TTcpChannel::new();
45/// channel.open("localhost:9090").unwrap();
46///
47/// let mut protocol = TCompactInputProtocol::new(channel);
48///
49/// let recvd_bool = protocol.read_bool().unwrap();
50/// let recvd_string = protocol.read_string().unwrap();
51/// ```
52#[derive(Debug)]
53pub struct TCompactInputProtocol<T>
54where
55    T: TReadTransport,
56{
57    // Identifier of the last field deserialized for a struct.
58    last_read_field_id: i16,
59    // Stack of the last read field ids (a new entry is added each time a nested struct is read).
60    read_field_id_stack: Vec<i16>,
61    // Boolean value for a field.
62    // Saved because boolean fields and their value are encoded in a single byte,
63    // and reading the field only occurs after the field id is read.
64    pending_read_bool_value: Option<bool>,
65    // Underlying transport used for byte-level operations.
66    transport: T,
67}
68
69impl<T> TCompactInputProtocol<T>
70where
71    T: TReadTransport,
72{
73    /// Create a `TCompactInputProtocol` that reads bytes from `transport`.
74    pub fn new(transport: T) -> TCompactInputProtocol<T> {
75        TCompactInputProtocol {
76            last_read_field_id: 0,
77            read_field_id_stack: Vec::new(),
78            pending_read_bool_value: None,
79            transport,
80        }
81    }
82
83    fn read_list_set_begin(&mut self) -> crate::Result<(TType, i32)> {
84        let header = self.read_byte()?;
85        let element_type = collection_u8_to_type(header & 0x0F)?;
86
87        let element_count;
88        let possible_element_count = (header & 0xF0) >> 4;
89        if possible_element_count != 15 {
90            // high bits set high if count and type encoded separately
91            element_count = possible_element_count as i32;
92        } else {
93            element_count = self.transport.read_varint::<u32>()? as i32;
94        }
95
96        Ok((element_type, element_count))
97    }
98}
99
100impl<T> TInputProtocol for TCompactInputProtocol<T>
101where
102    T: TReadTransport,
103{
104    fn read_message_begin(&mut self) -> crate::Result<TMessageIdentifier> {
105        let compact_id = self.read_byte()?;
106        if compact_id != COMPACT_PROTOCOL_ID {
107            Err(crate::Error::Protocol(crate::ProtocolError {
108                kind: crate::ProtocolErrorKind::BadVersion,
109                message: format!("invalid compact protocol header {:?}", compact_id),
110            }))
111        } else {
112            Ok(())
113        }?;
114
115        let type_and_byte = self.read_byte()?;
116        let received_version = type_and_byte & COMPACT_VERSION_MASK;
117        if received_version != COMPACT_VERSION {
118            Err(crate::Error::Protocol(crate::ProtocolError {
119                kind: crate::ProtocolErrorKind::BadVersion,
120                message: format!(
121                    "cannot process compact protocol version {:?}",
122                    received_version
123                ),
124            }))
125        } else {
126            Ok(())
127        }?;
128
129        // NOTE: unsigned right shift will pad with 0s
130        let message_type: TMessageType = TMessageType::try_from(type_and_byte >> 5)?;
131        // writing side wrote signed sequence number as u32 to avoid zigzag encoding
132        let sequence_number = self.transport.read_varint::<u32>()? as i32;
133        let service_call_name = self.read_string()?;
134
135        self.last_read_field_id = 0;
136
137        Ok(TMessageIdentifier::new(
138            service_call_name,
139            message_type,
140            sequence_number,
141        ))
142    }
143
144    fn read_message_end(&mut self) -> crate::Result<()> {
145        Ok(())
146    }
147
148    fn read_struct_begin(&mut self) -> crate::Result<Option<TStructIdentifier>> {
149        self.read_field_id_stack.push(self.last_read_field_id);
150        self.last_read_field_id = 0;
151        Ok(None)
152    }
153
154    fn read_struct_end(&mut self) -> crate::Result<()> {
155        self.last_read_field_id = self
156            .read_field_id_stack
157            .pop()
158            .expect("should have previous field ids");
159        Ok(())
160    }
161
162    fn read_field_begin(&mut self) -> crate::Result<TFieldIdentifier> {
163        // we can read at least one byte, which is:
164        // - the type
165        // - the field delta and the type
166        let field_type = self.read_byte()?;
167        let field_delta = (field_type & 0xF0) >> 4;
168        let field_type = match field_type & 0x0F {
169            0x01 => {
170                self.pending_read_bool_value = Some(true);
171                Ok(TType::Bool)
172            }
173            0x02 => {
174                self.pending_read_bool_value = Some(false);
175                Ok(TType::Bool)
176            }
177            ttu8 => u8_to_type(ttu8),
178        }?;
179
180        match field_type {
181            TType::Stop => Ok(
182                TFieldIdentifier::new::<Option<String>, String, Option<i16>>(
183                    None,
184                    TType::Stop,
185                    None,
186                ),
187            ),
188            _ => {
189                if field_delta != 0 {
190                    self.last_read_field_id += field_delta as i16;
191                } else {
192                    self.last_read_field_id = self.read_i16()?;
193                };
194
195                Ok(TFieldIdentifier {
196                    name: None,
197                    field_type,
198                    id: Some(self.last_read_field_id),
199                })
200            }
201        }
202    }
203
204    fn read_field_end(&mut self) -> crate::Result<()> {
205        Ok(())
206    }
207
208    fn read_bool(&mut self) -> crate::Result<bool> {
209        match self.pending_read_bool_value.take() {
210            Some(b) => Ok(b),
211            None => {
212                let b = self.read_byte()?;
213                match b {
214                    0x01 => Ok(true),
215                    0x02 => Ok(false),
216                    unkn => Err(crate::Error::Protocol(crate::ProtocolError {
217                        kind: crate::ProtocolErrorKind::InvalidData,
218                        message: format!("cannot convert {} into bool", unkn),
219                    })),
220                }
221            }
222        }
223    }
224
225    fn read_bytes(&mut self) -> crate::Result<Vec<u8>> {
226        let len = self.transport.read_varint::<u32>()?;
227        let mut buf = vec![0u8; len as usize];
228        self.transport
229            .read_exact(&mut buf)
230            .map_err(From::from)
231            .map(|_| buf)
232    }
233
234    fn read_i8(&mut self) -> crate::Result<i8> {
235        self.read_byte().map(|i| i as i8)
236    }
237
238    fn read_i16(&mut self) -> crate::Result<i16> {
239        self.transport.read_varint::<i16>().map_err(From::from)
240    }
241
242    fn read_i32(&mut self) -> crate::Result<i32> {
243        self.transport.read_varint::<i32>().map_err(From::from)
244    }
245
246    fn read_i64(&mut self) -> crate::Result<i64> {
247        self.transport.read_varint::<i64>().map_err(From::from)
248    }
249
250    fn read_double(&mut self) -> crate::Result<f64> {
251        self.transport
252            .read_f64::<LittleEndian>()
253            .map_err(From::from)
254    }
255
256    fn read_string(&mut self) -> crate::Result<String> {
257        let bytes = self.read_bytes()?;
258        String::from_utf8(bytes).map_err(From::from)
259    }
260
261    fn read_list_begin(&mut self) -> crate::Result<TListIdentifier> {
262        let (element_type, element_count) = self.read_list_set_begin()?;
263        Ok(TListIdentifier::new(element_type, element_count))
264    }
265
266    fn read_list_end(&mut self) -> crate::Result<()> {
267        Ok(())
268    }
269
270    fn read_set_begin(&mut self) -> crate::Result<TSetIdentifier> {
271        let (element_type, element_count) = self.read_list_set_begin()?;
272        Ok(TSetIdentifier::new(element_type, element_count))
273    }
274
275    fn read_set_end(&mut self) -> crate::Result<()> {
276        Ok(())
277    }
278
279    fn read_map_begin(&mut self) -> crate::Result<TMapIdentifier> {
280        let element_count = self.transport.read_varint::<u32>()? as i32;
281        if element_count == 0 {
282            Ok(TMapIdentifier::new(None, None, 0))
283        } else {
284            let type_header = self.read_byte()?;
285            let key_type = collection_u8_to_type((type_header & 0xF0) >> 4)?;
286            let val_type = collection_u8_to_type(type_header & 0x0F)?;
287            Ok(TMapIdentifier::new(key_type, val_type, element_count))
288        }
289    }
290
291    fn read_map_end(&mut self) -> crate::Result<()> {
292        Ok(())
293    }
294
295    // utility
296    //
297
298    fn read_byte(&mut self) -> crate::Result<u8> {
299        let mut buf = [0u8; 1];
300        self.transport
301            .read_exact(&mut buf)
302            .map_err(From::from)
303            .map(|_| buf[0])
304    }
305}
306
307impl<T> io::Seek for TCompactInputProtocol<T>
308where
309    T: io::Seek + TReadTransport,
310{
311    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
312        self.transport.seek(pos)
313    }
314}
315
316/// Factory for creating instances of `TCompactInputProtocol`.
317#[derive(Default)]
318pub struct TCompactInputProtocolFactory;
319
320impl TCompactInputProtocolFactory {
321    /// Create a `TCompactInputProtocolFactory`.
322    pub fn new() -> TCompactInputProtocolFactory {
323        TCompactInputProtocolFactory {}
324    }
325}
326
327impl TInputProtocolFactory for TCompactInputProtocolFactory {
328    fn create(&self, transport: Box<dyn TReadTransport + Send>) -> Box<dyn TInputProtocol + Send> {
329        Box::new(TCompactInputProtocol::new(transport))
330    }
331}
332
333/// Write messages using the Thrift compact protocol.
334///
335/// # Examples
336///
337/// Create and use a `TCompactOutputProtocol`.
338///
339/// ```no_run
340/// use thrift::protocol::{TCompactOutputProtocol, TOutputProtocol};
341/// use thrift::transport::TTcpChannel;
342///
343/// let mut channel = TTcpChannel::new();
344/// channel.open("localhost:9090").unwrap();
345///
346/// let mut protocol = TCompactOutputProtocol::new(channel);
347///
348/// protocol.write_bool(true).unwrap();
349/// protocol.write_string("test_string").unwrap();
350/// ```
351#[derive(Debug)]
352pub struct TCompactOutputProtocol<T>
353where
354    T: TWriteTransport,
355{
356    // Identifier of the last field serialized for a struct.
357    last_write_field_id: i16,
358    // Stack of the last written field ids (new entry added each time a nested struct is written).
359    write_field_id_stack: Vec<i16>,
360    // Field identifier of the boolean field to be written.
361    // Saved because boolean fields and their value are encoded in a single byte
362    pending_write_bool_field_identifier: Option<TFieldIdentifier>,
363    // Underlying transport used for byte-level operations.
364    transport: T,
365}
366
367impl<T> TCompactOutputProtocol<T>
368where
369    T: TWriteTransport,
370{
371    /// Create a `TCompactOutputProtocol` that writes bytes to `transport`.
372    pub fn new(transport: T) -> TCompactOutputProtocol<T> {
373        TCompactOutputProtocol {
374            last_write_field_id: 0,
375            write_field_id_stack: Vec::new(),
376            pending_write_bool_field_identifier: None,
377            transport,
378        }
379    }
380
381    // FIXME: field_type as unconstrained u8 is bad
382    fn write_field_header(&mut self, field_type: u8, field_id: i16) -> crate::Result<()> {
383        let field_delta = field_id - self.last_write_field_id;
384        if field_delta > 0 && field_delta < 15 {
385            self.write_byte(((field_delta as u8) << 4) | field_type)?;
386        } else {
387            self.write_byte(field_type)?;
388            self.write_i16(field_id)?;
389        }
390        self.last_write_field_id = field_id;
391        Ok(())
392    }
393
394    fn write_list_set_begin(
395        &mut self,
396        element_type: TType,
397        element_count: i32,
398    ) -> crate::Result<()> {
399        let elem_identifier = collection_type_to_u8(element_type);
400        if element_count <= 14 {
401            let header = (element_count as u8) << 4 | elem_identifier;
402            self.write_byte(header)
403        } else {
404            let header = 0xF0 | elem_identifier;
405            self.write_byte(header)?;
406            // element count is strictly positive as per the spec, so
407            // cast i32 as u32 so that varint writing won't use zigzag encoding
408            self.transport
409                .write_varint(element_count as u32)
410                .map_err(From::from)
411                .map(|_| ())
412        }
413    }
414
415    fn assert_no_pending_bool_write(&self) {
416        if let Some(ref f) = self.pending_write_bool_field_identifier {
417            panic!("pending bool field {:?} not written", f)
418        }
419    }
420}
421
422impl<T> TOutputProtocol for TCompactOutputProtocol<T>
423where
424    T: TWriteTransport,
425{
426    fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> crate::Result<()> {
427        self.write_byte(COMPACT_PROTOCOL_ID)?;
428        self.write_byte((u8::from(identifier.message_type) << 5) | COMPACT_VERSION)?;
429        // cast i32 as u32 so that varint writing won't use zigzag encoding
430        self.transport
431            .write_varint(identifier.sequence_number as u32)?;
432        self.write_string(&identifier.name)?;
433        Ok(())
434    }
435
436    fn write_message_end(&mut self) -> crate::Result<()> {
437        self.assert_no_pending_bool_write();
438        Ok(())
439    }
440
441    fn write_struct_begin(&mut self, _: &TStructIdentifier) -> crate::Result<()> {
442        self.write_field_id_stack.push(self.last_write_field_id);
443        self.last_write_field_id = 0;
444        Ok(())
445    }
446
447    fn write_struct_end(&mut self) -> crate::Result<()> {
448        self.assert_no_pending_bool_write();
449        self.last_write_field_id = self
450            .write_field_id_stack
451            .pop()
452            .expect("should have previous field ids");
453        Ok(())
454    }
455
456    fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> crate::Result<()> {
457        match identifier.field_type {
458            TType::Bool => {
459                if self.pending_write_bool_field_identifier.is_some() {
460                    panic!(
461                        "should not have a pending bool while writing another bool with id: \
462                         {:?}",
463                        identifier
464                    )
465                }
466                self.pending_write_bool_field_identifier = Some(identifier.clone());
467                Ok(())
468            }
469            _ => {
470                let field_type = type_to_u8(identifier.field_type);
471                let field_id = identifier.id.expect("non-stop field should have field id");
472                self.write_field_header(field_type, field_id)
473            }
474        }
475    }
476
477    fn write_field_end(&mut self) -> crate::Result<()> {
478        self.assert_no_pending_bool_write();
479        Ok(())
480    }
481
482    fn write_field_stop(&mut self) -> crate::Result<()> {
483        self.assert_no_pending_bool_write();
484        self.write_byte(type_to_u8(TType::Stop))
485    }
486
487    fn write_bool(&mut self, b: bool) -> crate::Result<()> {
488        match self.pending_write_bool_field_identifier.take() {
489            Some(pending) => {
490                let field_id = pending.id.expect("bool field should have a field id");
491                let field_type_as_u8 = if b { 0x01 } else { 0x02 };
492                self.write_field_header(field_type_as_u8, field_id)
493            }
494            None => {
495                if b {
496                    self.write_byte(0x01)
497                } else {
498                    self.write_byte(0x02)
499                }
500            }
501        }
502    }
503
504    fn write_bytes(&mut self, b: &[u8]) -> crate::Result<()> {
505        // length is strictly positive as per the spec, so
506        // cast i32 as u32 so that varint writing won't use zigzag encoding
507        self.transport.write_varint(b.len() as u32)?;
508        self.transport.write_all(b).map_err(From::from)
509    }
510
511    fn write_i8(&mut self, i: i8) -> crate::Result<()> {
512        self.write_byte(i as u8)
513    }
514
515    fn write_i16(&mut self, i: i16) -> crate::Result<()> {
516        self.transport
517            .write_varint(i)
518            .map_err(From::from)
519            .map(|_| ())
520    }
521
522    fn write_i32(&mut self, i: i32) -> crate::Result<()> {
523        self.transport
524            .write_varint(i)
525            .map_err(From::from)
526            .map(|_| ())
527    }
528
529    fn write_i64(&mut self, i: i64) -> crate::Result<()> {
530        self.transport
531            .write_varint(i)
532            .map_err(From::from)
533            .map(|_| ())
534    }
535
536    fn write_double(&mut self, d: f64) -> crate::Result<()> {
537        self.transport
538            .write_f64::<LittleEndian>(d)
539            .map_err(From::from)
540    }
541
542    fn write_string(&mut self, s: &str) -> crate::Result<()> {
543        self.write_bytes(s.as_bytes())
544    }
545
546    fn write_list_begin(&mut self, identifier: &TListIdentifier) -> crate::Result<()> {
547        self.write_list_set_begin(identifier.element_type, identifier.size)
548    }
549
550    fn write_list_end(&mut self) -> crate::Result<()> {
551        Ok(())
552    }
553
554    fn write_set_begin(&mut self, identifier: &TSetIdentifier) -> crate::Result<()> {
555        self.write_list_set_begin(identifier.element_type, identifier.size)
556    }
557
558    fn write_set_end(&mut self) -> crate::Result<()> {
559        Ok(())
560    }
561
562    fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> crate::Result<()> {
563        if identifier.size == 0 {
564            self.write_byte(0)
565        } else {
566            // element count is strictly positive as per the spec, so
567            // cast i32 as u32 so that varint writing won't use zigzag encoding
568            self.transport.write_varint(identifier.size as u32)?;
569
570            let key_type = identifier
571                .key_type
572                .expect("map identifier to write should contain key type");
573            let key_type_byte = collection_type_to_u8(key_type) << 4;
574
575            let val_type = identifier
576                .value_type
577                .expect("map identifier to write should contain value type");
578            let val_type_byte = collection_type_to_u8(val_type);
579
580            let map_type_header = key_type_byte | val_type_byte;
581            self.write_byte(map_type_header)
582        }
583    }
584
585    fn write_map_end(&mut self) -> crate::Result<()> {
586        Ok(())
587    }
588
589    fn flush(&mut self) -> crate::Result<()> {
590        self.transport.flush().map_err(From::from)
591    }
592
593    // utility
594    //
595
596    fn write_byte(&mut self, b: u8) -> crate::Result<()> {
597        self.transport.write(&[b]).map_err(From::from).map(|_| ())
598    }
599}
600
601/// Factory for creating instances of `TCompactOutputProtocol`.
602#[derive(Default)]
603pub struct TCompactOutputProtocolFactory;
604
605impl TCompactOutputProtocolFactory {
606    /// Create a `TCompactOutputProtocolFactory`.
607    pub fn new() -> TCompactOutputProtocolFactory {
608        TCompactOutputProtocolFactory {}
609    }
610}
611
612impl TOutputProtocolFactory for TCompactOutputProtocolFactory {
613    fn create(
614        &self,
615        transport: Box<dyn TWriteTransport + Send>,
616    ) -> Box<dyn TOutputProtocol + Send> {
617        Box::new(TCompactOutputProtocol::new(transport))
618    }
619}
620
621fn collection_type_to_u8(field_type: TType) -> u8 {
622    match field_type {
623        TType::Bool => 0x01,
624        f => type_to_u8(f),
625    }
626}
627
628fn type_to_u8(field_type: TType) -> u8 {
629    match field_type {
630        TType::Stop => 0x00,
631        TType::I08 => 0x03, // equivalent to TType::Byte
632        TType::I16 => 0x04,
633        TType::I32 => 0x05,
634        TType::I64 => 0x06,
635        TType::Double => 0x07,
636        TType::String => 0x08,
637        TType::List => 0x09,
638        TType::Set => 0x0A,
639        TType::Map => 0x0B,
640        TType::Struct => 0x0C,
641        _ => panic!("should not have attempted to convert {} to u8", field_type),
642    }
643}
644
645fn collection_u8_to_type(b: u8) -> crate::Result<TType> {
646    match b {
647        0x01 => Ok(TType::Bool),
648        o => u8_to_type(o),
649    }
650}
651
652fn u8_to_type(b: u8) -> crate::Result<TType> {
653    match b {
654        0x00 => Ok(TType::Stop),
655        0x03 => Ok(TType::I08), // equivalent to TType::Byte
656        0x04 => Ok(TType::I16),
657        0x05 => Ok(TType::I32),
658        0x06 => Ok(TType::I64),
659        0x07 => Ok(TType::Double),
660        0x08 => Ok(TType::String),
661        0x09 => Ok(TType::List),
662        0x0A => Ok(TType::Set),
663        0x0B => Ok(TType::Map),
664        0x0C => Ok(TType::Struct),
665        unkn => Err(crate::Error::Protocol(crate::ProtocolError {
666            kind: crate::ProtocolErrorKind::InvalidData,
667            message: format!("cannot convert {} into TType", unkn),
668        })),
669    }
670}
671
672#[cfg(test)]
673mod tests {
674
675    use std::i32;
676
677    use crate::protocol::{
678        TFieldIdentifier, TInputProtocol, TListIdentifier, TMapIdentifier, TMessageIdentifier,
679        TMessageType, TOutputProtocol, TSetIdentifier, TStructIdentifier, TType,
680    };
681    use crate::transport::{ReadHalf, TBufferChannel, TIoChannel, WriteHalf};
682
683    use super::*;
684
685    #[test]
686    fn must_write_message_begin_largest_maximum_positive_sequence_number() {
687        let (_, mut o_prot) = test_objects();
688
689        assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new(
690            "bar",
691            TMessageType::Reply,
692            i32::MAX
693        )));
694
695        #[rustfmt::skip]
696        let expected: [u8; 11] = [
697            0x82, /* protocol ID */
698            0x41, /* message type | protocol version */
699            0xFF,
700            0xFF,
701            0xFF,
702            0xFF,
703            0x07, /* non-zig-zag varint sequence number */
704            0x03, /* message-name length */
705            0x62,
706            0x61,
707            0x72 /* "bar" */,
708        ];
709
710        assert_eq_written_bytes!(o_prot, expected);
711    }
712
713    #[test]
714    fn must_read_message_begin_largest_maximum_positive_sequence_number() {
715        let (mut i_prot, _) = test_objects();
716
717        #[rustfmt::skip]
718        let source_bytes: [u8; 11] = [
719            0x82, /* protocol ID */
720            0x41, /* message type | protocol version */
721            0xFF,
722            0xFF,
723            0xFF,
724            0xFF,
725            0x07, /* non-zig-zag varint sequence number */
726            0x03, /* message-name length */
727            0x62,
728            0x61,
729            0x72 /* "bar" */,
730        ];
731
732        i_prot.transport.set_readable_bytes(&source_bytes);
733
734        let expected = TMessageIdentifier::new("bar", TMessageType::Reply, i32::MAX);
735        let res = assert_success!(i_prot.read_message_begin());
736
737        assert_eq!(&expected, &res);
738    }
739
740    #[test]
741    fn must_write_message_begin_positive_sequence_number_0() {
742        let (_, mut o_prot) = test_objects();
743
744        assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new(
745            "foo",
746            TMessageType::Call,
747            431
748        )));
749
750        #[rustfmt::skip]
751        let expected: [u8; 8] = [
752            0x82, /* protocol ID */
753            0x21, /* message type | protocol version */
754            0xAF,
755            0x03, /* non-zig-zag varint sequence number */
756            0x03, /* message-name length */
757            0x66,
758            0x6F,
759            0x6F /* "foo" */,
760        ];
761
762        assert_eq_written_bytes!(o_prot, expected);
763    }
764
765    #[test]
766    fn must_read_message_begin_positive_sequence_number_0() {
767        let (mut i_prot, _) = test_objects();
768
769        #[rustfmt::skip]
770        let source_bytes: [u8; 8] = [
771            0x82, /* protocol ID */
772            0x21, /* message type | protocol version */
773            0xAF,
774            0x03, /* non-zig-zag varint sequence number */
775            0x03, /* message-name length */
776            0x66,
777            0x6F,
778            0x6F /* "foo" */,
779        ];
780
781        i_prot.transport.set_readable_bytes(&source_bytes);
782
783        let expected = TMessageIdentifier::new("foo", TMessageType::Call, 431);
784        let res = assert_success!(i_prot.read_message_begin());
785
786        assert_eq!(&expected, &res);
787    }
788
789    #[test]
790    fn must_write_message_begin_positive_sequence_number_1() {
791        let (_, mut o_prot) = test_objects();
792
793        assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new(
794            "bar",
795            TMessageType::Reply,
796            991_828
797        )));
798
799        #[rustfmt::skip]
800        let expected: [u8; 9] = [
801            0x82, /* protocol ID */
802            0x41, /* message type | protocol version */
803            0xD4,
804            0xC4,
805            0x3C, /* non-zig-zag varint sequence number */
806            0x03, /* message-name length */
807            0x62,
808            0x61,
809            0x72 /* "bar" */,
810        ];
811
812        assert_eq_written_bytes!(o_prot, expected);
813    }
814
815    #[test]
816    fn must_read_message_begin_positive_sequence_number_1() {
817        let (mut i_prot, _) = test_objects();
818
819        #[rustfmt::skip]
820        let source_bytes: [u8; 9] = [
821            0x82, /* protocol ID */
822            0x41, /* message type | protocol version */
823            0xD4,
824            0xC4,
825            0x3C, /* non-zig-zag varint sequence number */
826            0x03, /* message-name length */
827            0x62,
828            0x61,
829            0x72 /* "bar" */,
830        ];
831
832        i_prot.transport.set_readable_bytes(&source_bytes);
833
834        let expected = TMessageIdentifier::new("bar", TMessageType::Reply, 991_828);
835        let res = assert_success!(i_prot.read_message_begin());
836
837        assert_eq!(&expected, &res);
838    }
839
840    #[test]
841    fn must_write_message_begin_zero_sequence_number() {
842        let (_, mut o_prot) = test_objects();
843
844        assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new(
845            "bar",
846            TMessageType::Reply,
847            0
848        )));
849
850        #[rustfmt::skip]
851        let expected: [u8; 7] = [
852            0x82, /* protocol ID */
853            0x41, /* message type | protocol version */
854            0x00, /* non-zig-zag varint sequence number */
855            0x03, /* message-name length */
856            0x62,
857            0x61,
858            0x72 /* "bar" */,
859        ];
860
861        assert_eq_written_bytes!(o_prot, expected);
862    }
863
864    #[test]
865    fn must_read_message_begin_zero_sequence_number() {
866        let (mut i_prot, _) = test_objects();
867
868        #[rustfmt::skip]
869        let source_bytes: [u8; 7] = [
870            0x82, /* protocol ID */
871            0x41, /* message type | protocol version */
872            0x00, /* non-zig-zag varint sequence number */
873            0x03, /* message-name length */
874            0x62,
875            0x61,
876            0x72 /* "bar" */,
877        ];
878
879        i_prot.transport.set_readable_bytes(&source_bytes);
880
881        let expected = TMessageIdentifier::new("bar", TMessageType::Reply, 0);
882        let res = assert_success!(i_prot.read_message_begin());
883
884        assert_eq!(&expected, &res);
885    }
886
887    #[test]
888    fn must_write_message_begin_largest_minimum_negative_sequence_number() {
889        let (_, mut o_prot) = test_objects();
890
891        assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new(
892            "bar",
893            TMessageType::Reply,
894            i32::MIN
895        )));
896
897        // two's complement notation of i32::MIN = 1000_0000_0000_0000_0000_0000_0000_0000
898        #[rustfmt::skip]
899        let expected: [u8; 11] = [
900            0x82, /* protocol ID */
901            0x41, /* message type | protocol version */
902            0x80,
903            0x80,
904            0x80,
905            0x80,
906            0x08, /* non-zig-zag varint sequence number */
907            0x03, /* message-name length */
908            0x62,
909            0x61,
910            0x72 /* "bar" */,
911        ];
912
913        assert_eq_written_bytes!(o_prot, expected);
914    }
915
916    #[test]
917    fn must_read_message_begin_largest_minimum_negative_sequence_number() {
918        let (mut i_prot, _) = test_objects();
919
920        // two's complement notation of i32::MIN = 1000_0000_0000_0000_0000_0000_0000_0000
921        #[rustfmt::skip]
922        let source_bytes: [u8; 11] = [
923            0x82, /* protocol ID */
924            0x41, /* message type | protocol version */
925            0x80,
926            0x80,
927            0x80,
928            0x80,
929            0x08, /* non-zig-zag varint sequence number */
930            0x03, /* message-name length */
931            0x62,
932            0x61,
933            0x72 /* "bar" */,
934        ];
935
936        i_prot.transport.set_readable_bytes(&source_bytes);
937
938        let expected = TMessageIdentifier::new("bar", TMessageType::Reply, i32::MIN);
939        let res = assert_success!(i_prot.read_message_begin());
940
941        assert_eq!(&expected, &res);
942    }
943
944    #[test]
945    fn must_write_message_begin_negative_sequence_number_0() {
946        let (_, mut o_prot) = test_objects();
947
948        assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new(
949            "foo",
950            TMessageType::Call,
951            -431
952        )));
953
954        // signed two's complement of -431 = 1111_1111_1111_1111_1111_1110_0101_0001
955        #[rustfmt::skip]
956        let expected: [u8; 11] = [
957            0x82, /* protocol ID */
958            0x21, /* message type | protocol version */
959            0xD1,
960            0xFC,
961            0xFF,
962            0xFF,
963            0x0F, /* non-zig-zag varint sequence number */
964            0x03, /* message-name length */
965            0x66,
966            0x6F,
967            0x6F /* "foo" */,
968        ];
969
970        assert_eq_written_bytes!(o_prot, expected);
971    }
972
973    #[test]
974    fn must_read_message_begin_negative_sequence_number_0() {
975        let (mut i_prot, _) = test_objects();
976
977        // signed two's complement of -431 = 1111_1111_1111_1111_1111_1110_0101_0001
978        #[rustfmt::skip]
979        let source_bytes: [u8; 11] = [
980            0x82, /* protocol ID */
981            0x21, /* message type | protocol version */
982            0xD1,
983            0xFC,
984            0xFF,
985            0xFF,
986            0x0F, /* non-zig-zag varint sequence number */
987            0x03, /* message-name length */
988            0x66,
989            0x6F,
990            0x6F /* "foo" */,
991        ];
992
993        i_prot.transport.set_readable_bytes(&source_bytes);
994
995        let expected = TMessageIdentifier::new("foo", TMessageType::Call, -431);
996        let res = assert_success!(i_prot.read_message_begin());
997
998        assert_eq!(&expected, &res);
999    }
1000
1001    #[test]
1002    fn must_write_message_begin_negative_sequence_number_1() {
1003        let (_, mut o_prot) = test_objects();
1004
1005        assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new(
1006            "foo",
1007            TMessageType::Call,
1008            -73_184_125
1009        )));
1010
1011        // signed two's complement of -73184125 = 1111_1011_1010_0011_0100_1100_1000_0011
1012        #[rustfmt::skip]
1013        let expected: [u8; 11] = [
1014            0x82, /* protocol ID */
1015            0x21, /* message type | protocol version */
1016            0x83,
1017            0x99,
1018            0x8D,
1019            0xDD,
1020            0x0F, /* non-zig-zag varint sequence number */
1021            0x03, /* message-name length */
1022            0x66,
1023            0x6F,
1024            0x6F /* "foo" */,
1025        ];
1026
1027        assert_eq_written_bytes!(o_prot, expected);
1028    }
1029
1030    #[test]
1031    fn must_read_message_begin_negative_sequence_number_1() {
1032        let (mut i_prot, _) = test_objects();
1033
1034        // signed two's complement of -73184125 = 1111_1011_1010_0011_0100_1100_1000_0011
1035        #[rustfmt::skip]
1036        let source_bytes: [u8; 11] = [
1037            0x82, /* protocol ID */
1038            0x21, /* message type | protocol version */
1039            0x83,
1040            0x99,
1041            0x8D,
1042            0xDD,
1043            0x0F, /* non-zig-zag varint sequence number */
1044            0x03, /* message-name length */
1045            0x66,
1046            0x6F,
1047            0x6F /* "foo" */,
1048        ];
1049
1050        i_prot.transport.set_readable_bytes(&source_bytes);
1051
1052        let expected = TMessageIdentifier::new("foo", TMessageType::Call, -73_184_125);
1053        let res = assert_success!(i_prot.read_message_begin());
1054
1055        assert_eq!(&expected, &res);
1056    }
1057
1058    #[test]
1059    fn must_write_message_begin_negative_sequence_number_2() {
1060        let (_, mut o_prot) = test_objects();
1061
1062        assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new(
1063            "foo",
1064            TMessageType::Call,
1065            -1_073_741_823
1066        )));
1067
1068        // signed two's complement of -1073741823 = 1100_0000_0000_0000_0000_0000_0000_0001
1069        #[rustfmt::skip]
1070        let expected: [u8; 11] = [
1071            0x82, /* protocol ID */
1072            0x21, /* message type | protocol version */
1073            0x81,
1074            0x80,
1075            0x80,
1076            0x80,
1077            0x0C, /* non-zig-zag varint sequence number */
1078            0x03, /* message-name length */
1079            0x66,
1080            0x6F,
1081            0x6F /* "foo" */,
1082        ];
1083
1084        assert_eq_written_bytes!(o_prot, expected);
1085    }
1086
1087    #[test]
1088    fn must_read_message_begin_negative_sequence_number_2() {
1089        let (mut i_prot, _) = test_objects();
1090
1091        // signed two's complement of -1073741823 = 1100_0000_0000_0000_0000_0000_0000_0001
1092        #[rustfmt::skip]
1093        let source_bytes: [u8; 11] = [
1094            0x82, /* protocol ID */
1095            0x21, /* message type | protocol version */
1096            0x81,
1097            0x80,
1098            0x80,
1099            0x80,
1100            0x0C, /* non-zig-zag varint sequence number */
1101            0x03, /* message-name length */
1102            0x66,
1103            0x6F,
1104            0x6F, /* "foo" */
1105        ];
1106
1107        i_prot.transport.set_readable_bytes(&source_bytes);
1108
1109        let expected = TMessageIdentifier::new("foo", TMessageType::Call, -1_073_741_823);
1110        let res = assert_success!(i_prot.read_message_begin());
1111
1112        assert_eq!(&expected, &res);
1113    }
1114
1115    #[test]
1116    fn must_round_trip_upto_i64_maxvalue() {
1117        // See https://issues.apache.org/jira/browse/THRIFT-5131
1118        for i in 0..64 {
1119            let (mut i_prot, mut o_prot) = test_objects();
1120            let val: i64 = ((1u64 << i) - 1) as i64;
1121
1122            o_prot
1123                .write_field_begin(&TFieldIdentifier::new("val", TType::I64, 1))
1124                .unwrap();
1125            o_prot.write_i64(val).unwrap();
1126            o_prot.write_field_end().unwrap();
1127            o_prot.flush().unwrap();
1128
1129            copy_write_buffer_to_read_buffer!(o_prot);
1130
1131            i_prot.read_field_begin().unwrap();
1132            assert_eq!(val, i_prot.read_i64().unwrap());
1133        }
1134    }
1135
1136    #[test]
1137    fn must_round_trip_message_begin() {
1138        let (mut i_prot, mut o_prot) = test_objects();
1139
1140        let ident = TMessageIdentifier::new("service_call", TMessageType::Call, 1_283_948);
1141
1142        assert_success!(o_prot.write_message_begin(&ident));
1143
1144        copy_write_buffer_to_read_buffer!(o_prot);
1145
1146        let res = assert_success!(i_prot.read_message_begin());
1147        assert_eq!(&res, &ident);
1148    }
1149
1150    #[test]
1151    fn must_write_message_end() {
1152        assert_no_write(|o| o.write_message_end());
1153    }
1154
1155    // NOTE: structs and fields are tested together
1156    //
1157
1158    #[test]
1159    fn must_write_struct_with_delta_fields() {
1160        let (_, mut o_prot) = test_objects();
1161
1162        // no bytes should be written however
1163        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
1164
1165        // write three fields with tiny field ids
1166        // since they're small the field ids will be encoded as deltas
1167
1168        // since this is the first field (and it's zero) it gets the full varint write
1169        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 0)));
1170        assert_success!(o_prot.write_field_end());
1171
1172        // since this delta > 0 and < 15 it can be encoded as a delta
1173        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I16, 4)));
1174        assert_success!(o_prot.write_field_end());
1175
1176        // since this delta > 0 and < 15 it can be encoded as a delta
1177        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::List, 9)));
1178        assert_success!(o_prot.write_field_end());
1179
1180        // now, finish the struct off
1181        assert_success!(o_prot.write_field_stop());
1182        assert_success!(o_prot.write_struct_end());
1183
1184        #[rustfmt::skip]
1185        let expected: [u8; 5] = [
1186            0x03, /* field type */
1187            0x00, /* first field id */
1188            0x44, /* field delta (4) | field type */
1189            0x59, /* field delta (5) | field type */
1190            0x00 /* field stop */,
1191        ];
1192
1193        assert_eq_written_bytes!(o_prot, expected);
1194    }
1195
1196    #[test]
1197    fn must_round_trip_struct_with_delta_fields() {
1198        let (mut i_prot, mut o_prot) = test_objects();
1199
1200        // no bytes should be written however
1201        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
1202
1203        // write three fields with tiny field ids
1204        // since they're small the field ids will be encoded as deltas
1205
1206        // since this is the first field (and it's zero) it gets the full varint write
1207        let field_ident_1 = TFieldIdentifier::new("foo", TType::I08, 0);
1208        assert_success!(o_prot.write_field_begin(&field_ident_1));
1209        assert_success!(o_prot.write_field_end());
1210
1211        // since this delta > 0 and < 15 it can be encoded as a delta
1212        let field_ident_2 = TFieldIdentifier::new("foo", TType::I16, 4);
1213        assert_success!(o_prot.write_field_begin(&field_ident_2));
1214        assert_success!(o_prot.write_field_end());
1215
1216        // since this delta > 0 and < 15 it can be encoded as a delta
1217        let field_ident_3 = TFieldIdentifier::new("foo", TType::List, 9);
1218        assert_success!(o_prot.write_field_begin(&field_ident_3));
1219        assert_success!(o_prot.write_field_end());
1220
1221        // now, finish the struct off
1222        assert_success!(o_prot.write_field_stop());
1223        assert_success!(o_prot.write_struct_end());
1224
1225        copy_write_buffer_to_read_buffer!(o_prot);
1226
1227        // read the struct back
1228        assert_success!(i_prot.read_struct_begin());
1229
1230        let read_ident_1 = assert_success!(i_prot.read_field_begin());
1231        assert_eq!(
1232            read_ident_1,
1233            TFieldIdentifier {
1234                name: None,
1235                ..field_ident_1
1236            }
1237        );
1238        assert_success!(i_prot.read_field_end());
1239
1240        let read_ident_2 = assert_success!(i_prot.read_field_begin());
1241        assert_eq!(
1242            read_ident_2,
1243            TFieldIdentifier {
1244                name: None,
1245                ..field_ident_2
1246            }
1247        );
1248        assert_success!(i_prot.read_field_end());
1249
1250        let read_ident_3 = assert_success!(i_prot.read_field_begin());
1251        assert_eq!(
1252            read_ident_3,
1253            TFieldIdentifier {
1254                name: None,
1255                ..field_ident_3
1256            }
1257        );
1258        assert_success!(i_prot.read_field_end());
1259
1260        let read_ident_4 = assert_success!(i_prot.read_field_begin());
1261        assert_eq!(
1262            read_ident_4,
1263            TFieldIdentifier {
1264                name: None,
1265                field_type: TType::Stop,
1266                id: None,
1267            }
1268        );
1269
1270        assert_success!(i_prot.read_struct_end());
1271    }
1272
1273    #[test]
1274    fn must_write_struct_with_non_zero_initial_field_and_delta_fields() {
1275        let (_, mut o_prot) = test_objects();
1276
1277        // no bytes should be written however
1278        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
1279
1280        // write three fields with tiny field ids
1281        // since they're small the field ids will be encoded as deltas
1282
1283        // gets a delta write
1284        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 1)));
1285        assert_success!(o_prot.write_field_end());
1286
1287        // since this delta > 0 and < 15 it can be encoded as a delta
1288        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 2)));
1289        assert_success!(o_prot.write_field_end());
1290
1291        // since this delta > 0 and < 15 it can be encoded as a delta
1292        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::String, 6)));
1293        assert_success!(o_prot.write_field_end());
1294
1295        // now, finish the struct off
1296        assert_success!(o_prot.write_field_stop());
1297        assert_success!(o_prot.write_struct_end());
1298
1299        #[rustfmt::skip]
1300        let expected: [u8; 4] = [
1301            0x15, /* field delta (1) | field type */
1302            0x1A, /* field delta (1) | field type */
1303            0x48, /* field delta (4) | field type */
1304            0x00 /* field stop */,
1305        ];
1306
1307        assert_eq_written_bytes!(o_prot, expected);
1308    }
1309
1310    #[test]
1311    fn must_round_trip_struct_with_non_zero_initial_field_and_delta_fields() {
1312        let (mut i_prot, mut o_prot) = test_objects();
1313
1314        // no bytes should be written however
1315        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
1316
1317        // write three fields with tiny field ids
1318        // since they're small the field ids will be encoded as deltas
1319
1320        // gets a delta write
1321        let field_ident_1 = TFieldIdentifier::new("foo", TType::I32, 1);
1322        assert_success!(o_prot.write_field_begin(&field_ident_1));
1323        assert_success!(o_prot.write_field_end());
1324
1325        // since this delta > 0 and < 15 it can be encoded as a delta
1326        let field_ident_2 = TFieldIdentifier::new("foo", TType::Set, 2);
1327        assert_success!(o_prot.write_field_begin(&field_ident_2));
1328        assert_success!(o_prot.write_field_end());
1329
1330        // since this delta > 0 and < 15 it can be encoded as a delta
1331        let field_ident_3 = TFieldIdentifier::new("foo", TType::String, 6);
1332        assert_success!(o_prot.write_field_begin(&field_ident_3));
1333        assert_success!(o_prot.write_field_end());
1334
1335        // now, finish the struct off
1336        assert_success!(o_prot.write_field_stop());
1337        assert_success!(o_prot.write_struct_end());
1338
1339        copy_write_buffer_to_read_buffer!(o_prot);
1340
1341        // read the struct back
1342        assert_success!(i_prot.read_struct_begin());
1343
1344        let read_ident_1 = assert_success!(i_prot.read_field_begin());
1345        assert_eq!(
1346            read_ident_1,
1347            TFieldIdentifier {
1348                name: None,
1349                ..field_ident_1
1350            }
1351        );
1352        assert_success!(i_prot.read_field_end());
1353
1354        let read_ident_2 = assert_success!(i_prot.read_field_begin());
1355        assert_eq!(
1356            read_ident_2,
1357            TFieldIdentifier {
1358                name: None,
1359                ..field_ident_2
1360            }
1361        );
1362        assert_success!(i_prot.read_field_end());
1363
1364        let read_ident_3 = assert_success!(i_prot.read_field_begin());
1365        assert_eq!(
1366            read_ident_3,
1367            TFieldIdentifier {
1368                name: None,
1369                ..field_ident_3
1370            }
1371        );
1372        assert_success!(i_prot.read_field_end());
1373
1374        let read_ident_4 = assert_success!(i_prot.read_field_begin());
1375        assert_eq!(
1376            read_ident_4,
1377            TFieldIdentifier {
1378                name: None,
1379                field_type: TType::Stop,
1380                id: None,
1381            }
1382        );
1383
1384        assert_success!(i_prot.read_struct_end());
1385    }
1386
1387    #[test]
1388    fn must_write_struct_with_long_fields() {
1389        let (_, mut o_prot) = test_objects();
1390
1391        // no bytes should be written however
1392        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
1393
1394        // write three fields with field ids that cannot be encoded as deltas
1395
1396        // since this is the first field (and it's zero) it gets the full varint write
1397        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 0)));
1398        assert_success!(o_prot.write_field_end());
1399
1400        // since this delta is > 15 it is encoded as a zig-zag varint
1401        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 16)));
1402        assert_success!(o_prot.write_field_end());
1403
1404        // since this delta is > 15 it is encoded as a zig-zag varint
1405        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 99)));
1406        assert_success!(o_prot.write_field_end());
1407
1408        // now, finish the struct off
1409        assert_success!(o_prot.write_field_stop());
1410        assert_success!(o_prot.write_struct_end());
1411
1412        #[rustfmt::skip]
1413        let expected: [u8; 8] = [
1414            0x05, /* field type */
1415            0x00, /* first field id */
1416            0x06, /* field type */
1417            0x20, /* zig-zag varint field id */
1418            0x0A, /* field type */
1419            0xC6,
1420            0x01, /* zig-zag varint field id */
1421            0x00 /* field stop */,
1422        ];
1423
1424        assert_eq_written_bytes!(o_prot, expected);
1425    }
1426
1427    #[test]
1428    fn must_round_trip_struct_with_long_fields() {
1429        let (mut i_prot, mut o_prot) = test_objects();
1430
1431        // no bytes should be written however
1432        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
1433
1434        // write three fields with field ids that cannot be encoded as deltas
1435
1436        // since this is the first field (and it's zero) it gets the full varint write
1437        let field_ident_1 = TFieldIdentifier::new("foo", TType::I32, 0);
1438        assert_success!(o_prot.write_field_begin(&field_ident_1));
1439        assert_success!(o_prot.write_field_end());
1440
1441        // since this delta is > 15 it is encoded as a zig-zag varint
1442        let field_ident_2 = TFieldIdentifier::new("foo", TType::I64, 16);
1443        assert_success!(o_prot.write_field_begin(&field_ident_2));
1444        assert_success!(o_prot.write_field_end());
1445
1446        // since this delta is > 15 it is encoded as a zig-zag varint
1447        let field_ident_3 = TFieldIdentifier::new("foo", TType::Set, 99);
1448        assert_success!(o_prot.write_field_begin(&field_ident_3));
1449        assert_success!(o_prot.write_field_end());
1450
1451        // now, finish the struct off
1452        assert_success!(o_prot.write_field_stop());
1453        assert_success!(o_prot.write_struct_end());
1454
1455        copy_write_buffer_to_read_buffer!(o_prot);
1456
1457        // read the struct back
1458        assert_success!(i_prot.read_struct_begin());
1459
1460        let read_ident_1 = assert_success!(i_prot.read_field_begin());
1461        assert_eq!(
1462            read_ident_1,
1463            TFieldIdentifier {
1464                name: None,
1465                ..field_ident_1
1466            }
1467        );
1468        assert_success!(i_prot.read_field_end());
1469
1470        let read_ident_2 = assert_success!(i_prot.read_field_begin());
1471        assert_eq!(
1472            read_ident_2,
1473            TFieldIdentifier {
1474                name: None,
1475                ..field_ident_2
1476            }
1477        );
1478        assert_success!(i_prot.read_field_end());
1479
1480        let read_ident_3 = assert_success!(i_prot.read_field_begin());
1481        assert_eq!(
1482            read_ident_3,
1483            TFieldIdentifier {
1484                name: None,
1485                ..field_ident_3
1486            }
1487        );
1488        assert_success!(i_prot.read_field_end());
1489
1490        let read_ident_4 = assert_success!(i_prot.read_field_begin());
1491        assert_eq!(
1492            read_ident_4,
1493            TFieldIdentifier {
1494                name: None,
1495                field_type: TType::Stop,
1496                id: None,
1497            }
1498        );
1499
1500        assert_success!(i_prot.read_struct_end());
1501    }
1502
1503    #[test]
1504    fn must_write_struct_with_mix_of_long_and_delta_fields() {
1505        let (_, mut o_prot) = test_objects();
1506
1507        // no bytes should be written however
1508        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
1509
1510        // write three fields with field ids that cannot be encoded as deltas
1511
1512        // since the delta is > 0 and < 15 it gets a delta write
1513        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1)));
1514        assert_success!(o_prot.write_field_end());
1515
1516        // since this delta > 0 and < 15 it gets a delta write
1517        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 9)));
1518        assert_success!(o_prot.write_field_end());
1519
1520        // since this delta is > 15 it is encoded as a zig-zag varint
1521        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 1000)));
1522        assert_success!(o_prot.write_field_end());
1523
1524        // since this delta is > 15 it is encoded as a zig-zag varint
1525        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 2001)));
1526        assert_success!(o_prot.write_field_end());
1527
1528        // since this is only 3 up from the previous it is recorded as a delta
1529        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 2004)));
1530        assert_success!(o_prot.write_field_end());
1531
1532        // now, finish the struct off
1533        assert_success!(o_prot.write_field_stop());
1534        assert_success!(o_prot.write_struct_end());
1535
1536        #[rustfmt::skip]
1537        let expected: [u8; 10] = [
1538            0x16, /* field delta (1) | field type */
1539            0x85, /* field delta (8) | field type */
1540            0x0A, /* field type */
1541            0xD0,
1542            0x0F, /* zig-zag varint field id */
1543            0x0A, /* field type */
1544            0xA2,
1545            0x1F, /* zig-zag varint field id */
1546            0x3A, /* field delta (3) | field type */
1547            0x00 /* field stop */,
1548        ];
1549
1550        assert_eq_written_bytes!(o_prot, expected);
1551    }
1552
1553    #[allow(clippy::cognitive_complexity)]
1554    #[test]
1555    fn must_round_trip_struct_with_mix_of_long_and_delta_fields() {
1556        let (mut i_prot, mut o_prot) = test_objects();
1557
1558        // no bytes should be written however
1559        let struct_ident = TStructIdentifier::new("foo");
1560        assert_success!(o_prot.write_struct_begin(&struct_ident));
1561
1562        // write three fields with field ids that cannot be encoded as deltas
1563
1564        // since the delta is > 0 and < 15 it gets a delta write
1565        let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1);
1566        assert_success!(o_prot.write_field_begin(&field_ident_1));
1567        assert_success!(o_prot.write_field_end());
1568
1569        // since this delta > 0 and < 15 it gets a delta write
1570        let field_ident_2 = TFieldIdentifier::new("foo", TType::I32, 9);
1571        assert_success!(o_prot.write_field_begin(&field_ident_2));
1572        assert_success!(o_prot.write_field_end());
1573
1574        // since this delta is > 15 it is encoded as a zig-zag varint
1575        let field_ident_3 = TFieldIdentifier::new("foo", TType::Set, 1000);
1576        assert_success!(o_prot.write_field_begin(&field_ident_3));
1577        assert_success!(o_prot.write_field_end());
1578
1579        // since this delta is > 15 it is encoded as a zig-zag varint
1580        let field_ident_4 = TFieldIdentifier::new("foo", TType::Set, 2001);
1581        assert_success!(o_prot.write_field_begin(&field_ident_4));
1582        assert_success!(o_prot.write_field_end());
1583
1584        // since this is only 3 up from the previous it is recorded as a delta
1585        let field_ident_5 = TFieldIdentifier::new("foo", TType::Set, 2004);
1586        assert_success!(o_prot.write_field_begin(&field_ident_5));
1587        assert_success!(o_prot.write_field_end());
1588
1589        // now, finish the struct off
1590        assert_success!(o_prot.write_field_stop());
1591        assert_success!(o_prot.write_struct_end());
1592
1593        copy_write_buffer_to_read_buffer!(o_prot);
1594
1595        // read the struct back
1596        assert_success!(i_prot.read_struct_begin());
1597
1598        let read_ident_1 = assert_success!(i_prot.read_field_begin());
1599        assert_eq!(
1600            read_ident_1,
1601            TFieldIdentifier {
1602                name: None,
1603                ..field_ident_1
1604            }
1605        );
1606        assert_success!(i_prot.read_field_end());
1607
1608        let read_ident_2 = assert_success!(i_prot.read_field_begin());
1609        assert_eq!(
1610            read_ident_2,
1611            TFieldIdentifier {
1612                name: None,
1613                ..field_ident_2
1614            }
1615        );
1616        assert_success!(i_prot.read_field_end());
1617
1618        let read_ident_3 = assert_success!(i_prot.read_field_begin());
1619        assert_eq!(
1620            read_ident_3,
1621            TFieldIdentifier {
1622                name: None,
1623                ..field_ident_3
1624            }
1625        );
1626        assert_success!(i_prot.read_field_end());
1627
1628        let read_ident_4 = assert_success!(i_prot.read_field_begin());
1629        assert_eq!(
1630            read_ident_4,
1631            TFieldIdentifier {
1632                name: None,
1633                ..field_ident_4
1634            }
1635        );
1636        assert_success!(i_prot.read_field_end());
1637
1638        let read_ident_5 = assert_success!(i_prot.read_field_begin());
1639        assert_eq!(
1640            read_ident_5,
1641            TFieldIdentifier {
1642                name: None,
1643                ..field_ident_5
1644            }
1645        );
1646        assert_success!(i_prot.read_field_end());
1647
1648        let read_ident_6 = assert_success!(i_prot.read_field_begin());
1649        assert_eq!(
1650            read_ident_6,
1651            TFieldIdentifier {
1652                name: None,
1653                field_type: TType::Stop,
1654                id: None,
1655            }
1656        );
1657
1658        assert_success!(i_prot.read_struct_end());
1659    }
1660
1661    #[test]
1662    fn must_write_nested_structs_0() {
1663        // last field of the containing struct is a delta
1664        // first field of the the contained struct is a delta
1665
1666        let (_, mut o_prot) = test_objects();
1667
1668        // start containing struct
1669        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
1670
1671        // containing struct
1672        // since the delta is > 0 and < 15 it gets a delta write
1673        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1)));
1674        assert_success!(o_prot.write_field_end());
1675
1676        // containing struct
1677        // since this delta > 0 and < 15 it gets a delta write
1678        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 9)));
1679        assert_success!(o_prot.write_field_end());
1680
1681        // start contained struct
1682        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
1683
1684        // contained struct
1685        // since the delta is > 0 and < 15 it gets a delta write
1686        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 7)));
1687        assert_success!(o_prot.write_field_end());
1688
1689        // contained struct
1690        // since this delta > 15 it gets a full write
1691        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 24)));
1692        assert_success!(o_prot.write_field_end());
1693
1694        // end contained struct
1695        assert_success!(o_prot.write_field_stop());
1696        assert_success!(o_prot.write_struct_end());
1697
1698        // end containing struct
1699        assert_success!(o_prot.write_field_stop());
1700        assert_success!(o_prot.write_struct_end());
1701
1702        #[rustfmt::skip]
1703        let expected: [u8; 7] = [
1704            0x16, /* field delta (1) | field type */
1705            0x85, /* field delta (8) | field type */
1706            0x73, /* field delta (7) | field type */
1707            0x07, /* field type */
1708            0x30, /* zig-zag varint field id */
1709            0x00, /* field stop - contained */
1710            0x00 /* field stop - containing */,
1711        ];
1712
1713        assert_eq_written_bytes!(o_prot, expected);
1714    }
1715
1716    #[allow(clippy::cognitive_complexity)]
1717    #[test]
1718    fn must_round_trip_nested_structs_0() {
1719        // last field of the containing struct is a delta
1720        // first field of the the contained struct is a delta
1721
1722        let (mut i_prot, mut o_prot) = test_objects();
1723
1724        // start containing struct
1725        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
1726
1727        // containing struct
1728        // since the delta is > 0 and < 15 it gets a delta write
1729        let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1);
1730        assert_success!(o_prot.write_field_begin(&field_ident_1));
1731        assert_success!(o_prot.write_field_end());
1732
1733        // containing struct
1734        // since this delta > 0 and < 15 it gets a delta write
1735        let field_ident_2 = TFieldIdentifier::new("foo", TType::I32, 9);
1736        assert_success!(o_prot.write_field_begin(&field_ident_2));
1737        assert_success!(o_prot.write_field_end());
1738
1739        // start contained struct
1740        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
1741
1742        // contained struct
1743        // since the delta is > 0 and < 15 it gets a delta write
1744        let field_ident_3 = TFieldIdentifier::new("foo", TType::I08, 7);
1745        assert_success!(o_prot.write_field_begin(&field_ident_3));
1746        assert_success!(o_prot.write_field_end());
1747
1748        // contained struct
1749        // since this delta > 15 it gets a full write
1750        let field_ident_4 = TFieldIdentifier::new("foo", TType::Double, 24);
1751        assert_success!(o_prot.write_field_begin(&field_ident_4));
1752        assert_success!(o_prot.write_field_end());
1753
1754        // end contained struct
1755        assert_success!(o_prot.write_field_stop());
1756        assert_success!(o_prot.write_struct_end());
1757
1758        // end containing struct
1759        assert_success!(o_prot.write_field_stop());
1760        assert_success!(o_prot.write_struct_end());
1761
1762        copy_write_buffer_to_read_buffer!(o_prot);
1763
1764        // read containing struct back
1765        assert_success!(i_prot.read_struct_begin());
1766
1767        let read_ident_1 = assert_success!(i_prot.read_field_begin());
1768        assert_eq!(
1769            read_ident_1,
1770            TFieldIdentifier {
1771                name: None,
1772                ..field_ident_1
1773            }
1774        );
1775        assert_success!(i_prot.read_field_end());
1776
1777        let read_ident_2 = assert_success!(i_prot.read_field_begin());
1778        assert_eq!(
1779            read_ident_2,
1780            TFieldIdentifier {
1781                name: None,
1782                ..field_ident_2
1783            }
1784        );
1785        assert_success!(i_prot.read_field_end());
1786
1787        // read contained struct back
1788        assert_success!(i_prot.read_struct_begin());
1789
1790        let read_ident_3 = assert_success!(i_prot.read_field_begin());
1791        assert_eq!(
1792            read_ident_3,
1793            TFieldIdentifier {
1794                name: None,
1795                ..field_ident_3
1796            }
1797        );
1798        assert_success!(i_prot.read_field_end());
1799
1800        let read_ident_4 = assert_success!(i_prot.read_field_begin());
1801        assert_eq!(
1802            read_ident_4,
1803            TFieldIdentifier {
1804                name: None,
1805                ..field_ident_4
1806            }
1807        );
1808        assert_success!(i_prot.read_field_end());
1809
1810        // end contained struct
1811        let read_ident_6 = assert_success!(i_prot.read_field_begin());
1812        assert_eq!(
1813            read_ident_6,
1814            TFieldIdentifier {
1815                name: None,
1816                field_type: TType::Stop,
1817                id: None,
1818            }
1819        );
1820        assert_success!(i_prot.read_struct_end());
1821
1822        // end containing struct
1823        let read_ident_7 = assert_success!(i_prot.read_field_begin());
1824        assert_eq!(
1825            read_ident_7,
1826            TFieldIdentifier {
1827                name: None,
1828                field_type: TType::Stop,
1829                id: None,
1830            }
1831        );
1832        assert_success!(i_prot.read_struct_end());
1833    }
1834
1835    #[test]
1836    fn must_write_nested_structs_1() {
1837        // last field of the containing struct is a delta
1838        // first field of the the contained struct is a full write
1839
1840        let (_, mut o_prot) = test_objects();
1841
1842        // start containing struct
1843        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
1844
1845        // containing struct
1846        // since the delta is > 0 and < 15 it gets a delta write
1847        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1)));
1848        assert_success!(o_prot.write_field_end());
1849
1850        // containing struct
1851        // since this delta > 0 and < 15 it gets a delta write
1852        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 9)));
1853        assert_success!(o_prot.write_field_end());
1854
1855        // start contained struct
1856        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
1857
1858        // contained struct
1859        // since this delta > 15 it gets a full write
1860        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 24)));
1861        assert_success!(o_prot.write_field_end());
1862
1863        // contained struct
1864        // since the delta is > 0 and < 15 it gets a delta write
1865        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 27)));
1866        assert_success!(o_prot.write_field_end());
1867
1868        // end contained struct
1869        assert_success!(o_prot.write_field_stop());
1870        assert_success!(o_prot.write_struct_end());
1871
1872        // end containing struct
1873        assert_success!(o_prot.write_field_stop());
1874        assert_success!(o_prot.write_struct_end());
1875
1876        #[rustfmt::skip]
1877        let expected: [u8; 7] = [
1878            0x16, /* field delta (1) | field type */
1879            0x85, /* field delta (8) | field type */
1880            0x07, /* field type */
1881            0x30, /* zig-zag varint field id */
1882            0x33, /* field delta (3) | field type */
1883            0x00, /* field stop - contained */
1884            0x00 /* field stop - containing */,
1885        ];
1886
1887        assert_eq_written_bytes!(o_prot, expected);
1888    }
1889
1890    #[allow(clippy::cognitive_complexity)]
1891    #[test]
1892    fn must_round_trip_nested_structs_1() {
1893        // last field of the containing struct is a delta
1894        // first field of the the contained struct is a full write
1895
1896        let (mut i_prot, mut o_prot) = test_objects();
1897
1898        // start containing struct
1899        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
1900
1901        // containing struct
1902        // since the delta is > 0 and < 15 it gets a delta write
1903        let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1);
1904        assert_success!(o_prot.write_field_begin(&field_ident_1));
1905        assert_success!(o_prot.write_field_end());
1906
1907        // containing struct
1908        // since this delta > 0 and < 15 it gets a delta write
1909        let field_ident_2 = TFieldIdentifier::new("foo", TType::I32, 9);
1910        assert_success!(o_prot.write_field_begin(&field_ident_2));
1911        assert_success!(o_prot.write_field_end());
1912
1913        // start contained struct
1914        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
1915
1916        // contained struct
1917        // since this delta > 15 it gets a full write
1918        let field_ident_3 = TFieldIdentifier::new("foo", TType::Double, 24);
1919        assert_success!(o_prot.write_field_begin(&field_ident_3));
1920        assert_success!(o_prot.write_field_end());
1921
1922        // contained struct
1923        // since the delta is > 0 and < 15 it gets a delta write
1924        let field_ident_4 = TFieldIdentifier::new("foo", TType::I08, 27);
1925        assert_success!(o_prot.write_field_begin(&field_ident_4));
1926        assert_success!(o_prot.write_field_end());
1927
1928        // end contained struct
1929        assert_success!(o_prot.write_field_stop());
1930        assert_success!(o_prot.write_struct_end());
1931
1932        // end containing struct
1933        assert_success!(o_prot.write_field_stop());
1934        assert_success!(o_prot.write_struct_end());
1935
1936        copy_write_buffer_to_read_buffer!(o_prot);
1937
1938        // read containing struct back
1939        assert_success!(i_prot.read_struct_begin());
1940
1941        let read_ident_1 = assert_success!(i_prot.read_field_begin());
1942        assert_eq!(
1943            read_ident_1,
1944            TFieldIdentifier {
1945                name: None,
1946                ..field_ident_1
1947            }
1948        );
1949        assert_success!(i_prot.read_field_end());
1950
1951        let read_ident_2 = assert_success!(i_prot.read_field_begin());
1952        assert_eq!(
1953            read_ident_2,
1954            TFieldIdentifier {
1955                name: None,
1956                ..field_ident_2
1957            }
1958        );
1959        assert_success!(i_prot.read_field_end());
1960
1961        // read contained struct back
1962        assert_success!(i_prot.read_struct_begin());
1963
1964        let read_ident_3 = assert_success!(i_prot.read_field_begin());
1965        assert_eq!(
1966            read_ident_3,
1967            TFieldIdentifier {
1968                name: None,
1969                ..field_ident_3
1970            }
1971        );
1972        assert_success!(i_prot.read_field_end());
1973
1974        let read_ident_4 = assert_success!(i_prot.read_field_begin());
1975        assert_eq!(
1976            read_ident_4,
1977            TFieldIdentifier {
1978                name: None,
1979                ..field_ident_4
1980            }
1981        );
1982        assert_success!(i_prot.read_field_end());
1983
1984        // end contained struct
1985        let read_ident_6 = assert_success!(i_prot.read_field_begin());
1986        assert_eq!(
1987            read_ident_6,
1988            TFieldIdentifier {
1989                name: None,
1990                field_type: TType::Stop,
1991                id: None,
1992            }
1993        );
1994        assert_success!(i_prot.read_struct_end());
1995
1996        // end containing struct
1997        let read_ident_7 = assert_success!(i_prot.read_field_begin());
1998        assert_eq!(
1999            read_ident_7,
2000            TFieldIdentifier {
2001                name: None,
2002                field_type: TType::Stop,
2003                id: None,
2004            }
2005        );
2006        assert_success!(i_prot.read_struct_end());
2007    }
2008
2009    #[test]
2010    fn must_write_nested_structs_2() {
2011        // last field of the containing struct is a full write
2012        // first field of the the contained struct is a delta write
2013
2014        let (_, mut o_prot) = test_objects();
2015
2016        // start containing struct
2017        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
2018
2019        // containing struct
2020        // since the delta is > 0 and < 15 it gets a delta write
2021        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1)));
2022        assert_success!(o_prot.write_field_end());
2023
2024        // containing struct
2025        // since this delta > 15 it gets a full write
2026        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::String, 21)));
2027        assert_success!(o_prot.write_field_end());
2028
2029        // start contained struct
2030        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
2031
2032        // contained struct
2033        // since this delta > 0 and < 15 it gets a delta write
2034        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 7)));
2035        assert_success!(o_prot.write_field_end());
2036
2037        // contained struct
2038        // since the delta is > 0 and < 15 it gets a delta write
2039        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 10)));
2040        assert_success!(o_prot.write_field_end());
2041
2042        // end contained struct
2043        assert_success!(o_prot.write_field_stop());
2044        assert_success!(o_prot.write_struct_end());
2045
2046        // end containing struct
2047        assert_success!(o_prot.write_field_stop());
2048        assert_success!(o_prot.write_struct_end());
2049
2050        #[rustfmt::skip]
2051        let expected: [u8; 7] = [
2052            0x16, /* field delta (1) | field type */
2053            0x08, /* field type */
2054            0x2A, /* zig-zag varint field id */
2055            0x77, /* field delta(7) | field type */
2056            0x33, /* field delta (3) | field type */
2057            0x00, /* field stop - contained */
2058            0x00 /* field stop - containing */,
2059        ];
2060
2061        assert_eq_written_bytes!(o_prot, expected);
2062    }
2063
2064    #[allow(clippy::cognitive_complexity)]
2065    #[test]
2066    fn must_round_trip_nested_structs_2() {
2067        let (mut i_prot, mut o_prot) = test_objects();
2068
2069        // start containing struct
2070        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
2071
2072        // containing struct
2073        // since the delta is > 0 and < 15 it gets a delta write
2074        let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1);
2075        assert_success!(o_prot.write_field_begin(&field_ident_1));
2076        assert_success!(o_prot.write_field_end());
2077
2078        // containing struct
2079        // since this delta > 15 it gets a full write
2080        let field_ident_2 = TFieldIdentifier::new("foo", TType::String, 21);
2081        assert_success!(o_prot.write_field_begin(&field_ident_2));
2082        assert_success!(o_prot.write_field_end());
2083
2084        // start contained struct
2085        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
2086
2087        // contained struct
2088        // since this delta > 0 and < 15 it gets a delta write
2089        let field_ident_3 = TFieldIdentifier::new("foo", TType::Double, 7);
2090        assert_success!(o_prot.write_field_begin(&field_ident_3));
2091        assert_success!(o_prot.write_field_end());
2092
2093        // contained struct
2094        // since the delta is > 0 and < 15 it gets a delta write
2095        let field_ident_4 = TFieldIdentifier::new("foo", TType::I08, 10);
2096        assert_success!(o_prot.write_field_begin(&field_ident_4));
2097        assert_success!(o_prot.write_field_end());
2098
2099        // end contained struct
2100        assert_success!(o_prot.write_field_stop());
2101        assert_success!(o_prot.write_struct_end());
2102
2103        // end containing struct
2104        assert_success!(o_prot.write_field_stop());
2105        assert_success!(o_prot.write_struct_end());
2106
2107        copy_write_buffer_to_read_buffer!(o_prot);
2108
2109        // read containing struct back
2110        assert_success!(i_prot.read_struct_begin());
2111
2112        let read_ident_1 = assert_success!(i_prot.read_field_begin());
2113        assert_eq!(
2114            read_ident_1,
2115            TFieldIdentifier {
2116                name: None,
2117                ..field_ident_1
2118            }
2119        );
2120        assert_success!(i_prot.read_field_end());
2121
2122        let read_ident_2 = assert_success!(i_prot.read_field_begin());
2123        assert_eq!(
2124            read_ident_2,
2125            TFieldIdentifier {
2126                name: None,
2127                ..field_ident_2
2128            }
2129        );
2130        assert_success!(i_prot.read_field_end());
2131
2132        // read contained struct back
2133        assert_success!(i_prot.read_struct_begin());
2134
2135        let read_ident_3 = assert_success!(i_prot.read_field_begin());
2136        assert_eq!(
2137            read_ident_3,
2138            TFieldIdentifier {
2139                name: None,
2140                ..field_ident_3
2141            }
2142        );
2143        assert_success!(i_prot.read_field_end());
2144
2145        let read_ident_4 = assert_success!(i_prot.read_field_begin());
2146        assert_eq!(
2147            read_ident_4,
2148            TFieldIdentifier {
2149                name: None,
2150                ..field_ident_4
2151            }
2152        );
2153        assert_success!(i_prot.read_field_end());
2154
2155        // end contained struct
2156        let read_ident_6 = assert_success!(i_prot.read_field_begin());
2157        assert_eq!(
2158            read_ident_6,
2159            TFieldIdentifier {
2160                name: None,
2161                field_type: TType::Stop,
2162                id: None,
2163            }
2164        );
2165        assert_success!(i_prot.read_struct_end());
2166
2167        // end containing struct
2168        let read_ident_7 = assert_success!(i_prot.read_field_begin());
2169        assert_eq!(
2170            read_ident_7,
2171            TFieldIdentifier {
2172                name: None,
2173                field_type: TType::Stop,
2174                id: None,
2175            }
2176        );
2177        assert_success!(i_prot.read_struct_end());
2178    }
2179
2180    #[test]
2181    fn must_write_nested_structs_3() {
2182        // last field of the containing struct is a full write
2183        // first field of the the contained struct is a full write
2184
2185        let (_, mut o_prot) = test_objects();
2186
2187        // start containing struct
2188        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
2189
2190        // containing struct
2191        // since the delta is > 0 and < 15 it gets a delta write
2192        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1)));
2193        assert_success!(o_prot.write_field_end());
2194
2195        // containing struct
2196        // since this delta > 15 it gets a full write
2197        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::String, 21)));
2198        assert_success!(o_prot.write_field_end());
2199
2200        // start contained struct
2201        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
2202
2203        // contained struct
2204        // since this delta > 15 it gets a full write
2205        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 21)));
2206        assert_success!(o_prot.write_field_end());
2207
2208        // contained struct
2209        // since the delta is > 0 and < 15 it gets a delta write
2210        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 27)));
2211        assert_success!(o_prot.write_field_end());
2212
2213        // end contained struct
2214        assert_success!(o_prot.write_field_stop());
2215        assert_success!(o_prot.write_struct_end());
2216
2217        // end containing struct
2218        assert_success!(o_prot.write_field_stop());
2219        assert_success!(o_prot.write_struct_end());
2220
2221        #[rustfmt::skip]
2222        let expected: [u8; 8] = [
2223            0x16, /* field delta (1) | field type */
2224            0x08, /* field type */
2225            0x2A, /* zig-zag varint field id */
2226            0x07, /* field type */
2227            0x2A, /* zig-zag varint field id */
2228            0x63, /* field delta (6) | field type */
2229            0x00, /* field stop - contained */
2230            0x00 /* field stop - containing */,
2231        ];
2232
2233        assert_eq_written_bytes!(o_prot, expected);
2234    }
2235
2236    #[allow(clippy::cognitive_complexity)]
2237    #[test]
2238    fn must_round_trip_nested_structs_3() {
2239        // last field of the containing struct is a full write
2240        // first field of the the contained struct is a full write
2241
2242        let (mut i_prot, mut o_prot) = test_objects();
2243
2244        // start containing struct
2245        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
2246
2247        // containing struct
2248        // since the delta is > 0 and < 15 it gets a delta write
2249        let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1);
2250        assert_success!(o_prot.write_field_begin(&field_ident_1));
2251        assert_success!(o_prot.write_field_end());
2252
2253        // containing struct
2254        // since this delta > 15 it gets a full write
2255        let field_ident_2 = TFieldIdentifier::new("foo", TType::String, 21);
2256        assert_success!(o_prot.write_field_begin(&field_ident_2));
2257        assert_success!(o_prot.write_field_end());
2258
2259        // start contained struct
2260        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
2261
2262        // contained struct
2263        // since this delta > 15 it gets a full write
2264        let field_ident_3 = TFieldIdentifier::new("foo", TType::Double, 21);
2265        assert_success!(o_prot.write_field_begin(&field_ident_3));
2266        assert_success!(o_prot.write_field_end());
2267
2268        // contained struct
2269        // since the delta is > 0 and < 15 it gets a delta write
2270        let field_ident_4 = TFieldIdentifier::new("foo", TType::I08, 27);
2271        assert_success!(o_prot.write_field_begin(&field_ident_4));
2272        assert_success!(o_prot.write_field_end());
2273
2274        // end contained struct
2275        assert_success!(o_prot.write_field_stop());
2276        assert_success!(o_prot.write_struct_end());
2277
2278        // end containing struct
2279        assert_success!(o_prot.write_field_stop());
2280        assert_success!(o_prot.write_struct_end());
2281
2282        copy_write_buffer_to_read_buffer!(o_prot);
2283
2284        // read containing struct back
2285        assert_success!(i_prot.read_struct_begin());
2286
2287        let read_ident_1 = assert_success!(i_prot.read_field_begin());
2288        assert_eq!(
2289            read_ident_1,
2290            TFieldIdentifier {
2291                name: None,
2292                ..field_ident_1
2293            }
2294        );
2295        assert_success!(i_prot.read_field_end());
2296
2297        let read_ident_2 = assert_success!(i_prot.read_field_begin());
2298        assert_eq!(
2299            read_ident_2,
2300            TFieldIdentifier {
2301                name: None,
2302                ..field_ident_2
2303            }
2304        );
2305        assert_success!(i_prot.read_field_end());
2306
2307        // read contained struct back
2308        assert_success!(i_prot.read_struct_begin());
2309
2310        let read_ident_3 = assert_success!(i_prot.read_field_begin());
2311        assert_eq!(
2312            read_ident_3,
2313            TFieldIdentifier {
2314                name: None,
2315                ..field_ident_3
2316            }
2317        );
2318        assert_success!(i_prot.read_field_end());
2319
2320        let read_ident_4 = assert_success!(i_prot.read_field_begin());
2321        assert_eq!(
2322            read_ident_4,
2323            TFieldIdentifier {
2324                name: None,
2325                ..field_ident_4
2326            }
2327        );
2328        assert_success!(i_prot.read_field_end());
2329
2330        // end contained struct
2331        let read_ident_6 = assert_success!(i_prot.read_field_begin());
2332        assert_eq!(
2333            read_ident_6,
2334            TFieldIdentifier {
2335                name: None,
2336                field_type: TType::Stop,
2337                id: None,
2338            }
2339        );
2340        assert_success!(i_prot.read_struct_end());
2341
2342        // end containing struct
2343        let read_ident_7 = assert_success!(i_prot.read_field_begin());
2344        assert_eq!(
2345            read_ident_7,
2346            TFieldIdentifier {
2347                name: None,
2348                field_type: TType::Stop,
2349                id: None,
2350            }
2351        );
2352        assert_success!(i_prot.read_struct_end());
2353    }
2354
2355    #[test]
2356    fn must_write_bool_field() {
2357        let (_, mut o_prot) = test_objects();
2358
2359        // no bytes should be written however
2360        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
2361
2362        // write three fields with field ids that cannot be encoded as deltas
2363
2364        // since the delta is > 0 and < 16 it gets a delta write
2365        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1)));
2366        assert_success!(o_prot.write_bool(true));
2367        assert_success!(o_prot.write_field_end());
2368
2369        // since this delta > 0 and < 15 it gets a delta write
2370        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 9)));
2371        assert_success!(o_prot.write_bool(false));
2372        assert_success!(o_prot.write_field_end());
2373
2374        // since this delta > 15 it gets a full write
2375        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 26)));
2376        assert_success!(o_prot.write_bool(true));
2377        assert_success!(o_prot.write_field_end());
2378
2379        // since this delta > 15 it gets a full write
2380        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 45)));
2381        assert_success!(o_prot.write_bool(false));
2382        assert_success!(o_prot.write_field_end());
2383
2384        // now, finish the struct off
2385        assert_success!(o_prot.write_field_stop());
2386        assert_success!(o_prot.write_struct_end());
2387
2388        #[rustfmt::skip]
2389        let expected: [u8; 7] = [
2390            0x11, /* field delta (1) | true */
2391            0x82, /* field delta (8) | false */
2392            0x01, /* true */
2393            0x34, /* field id */
2394            0x02, /* false */
2395            0x5A, /* field id */
2396            0x00 /* stop field */,
2397        ];
2398
2399        assert_eq_written_bytes!(o_prot, expected);
2400    }
2401
2402    #[allow(clippy::cognitive_complexity)]
2403    #[test]
2404    fn must_round_trip_bool_field() {
2405        let (mut i_prot, mut o_prot) = test_objects();
2406
2407        // no bytes should be written however
2408        let struct_ident = TStructIdentifier::new("foo");
2409        assert_success!(o_prot.write_struct_begin(&struct_ident));
2410
2411        // write two fields
2412
2413        // since the delta is > 0 and < 16 it gets a delta write
2414        let field_ident_1 = TFieldIdentifier::new("foo", TType::Bool, 1);
2415        assert_success!(o_prot.write_field_begin(&field_ident_1));
2416        assert_success!(o_prot.write_bool(true));
2417        assert_success!(o_prot.write_field_end());
2418
2419        // since this delta > 0 and < 15 it gets a delta write
2420        let field_ident_2 = TFieldIdentifier::new("foo", TType::Bool, 9);
2421        assert_success!(o_prot.write_field_begin(&field_ident_2));
2422        assert_success!(o_prot.write_bool(false));
2423        assert_success!(o_prot.write_field_end());
2424
2425        // since this delta > 15 it gets a full write
2426        let field_ident_3 = TFieldIdentifier::new("foo", TType::Bool, 26);
2427        assert_success!(o_prot.write_field_begin(&field_ident_3));
2428        assert_success!(o_prot.write_bool(true));
2429        assert_success!(o_prot.write_field_end());
2430
2431        // since this delta > 15 it gets a full write
2432        let field_ident_4 = TFieldIdentifier::new("foo", TType::Bool, 45);
2433        assert_success!(o_prot.write_field_begin(&field_ident_4));
2434        assert_success!(o_prot.write_bool(false));
2435        assert_success!(o_prot.write_field_end());
2436
2437        // now, finish the struct off
2438        assert_success!(o_prot.write_field_stop());
2439        assert_success!(o_prot.write_struct_end());
2440
2441        copy_write_buffer_to_read_buffer!(o_prot);
2442
2443        // read the struct back
2444        assert_success!(i_prot.read_struct_begin());
2445
2446        let read_ident_1 = assert_success!(i_prot.read_field_begin());
2447        assert_eq!(
2448            read_ident_1,
2449            TFieldIdentifier {
2450                name: None,
2451                ..field_ident_1
2452            }
2453        );
2454        let read_value_1 = assert_success!(i_prot.read_bool());
2455        assert_eq!(read_value_1, true);
2456        assert_success!(i_prot.read_field_end());
2457
2458        let read_ident_2 = assert_success!(i_prot.read_field_begin());
2459        assert_eq!(
2460            read_ident_2,
2461            TFieldIdentifier {
2462                name: None,
2463                ..field_ident_2
2464            }
2465        );
2466        let read_value_2 = assert_success!(i_prot.read_bool());
2467        assert_eq!(read_value_2, false);
2468        assert_success!(i_prot.read_field_end());
2469
2470        let read_ident_3 = assert_success!(i_prot.read_field_begin());
2471        assert_eq!(
2472            read_ident_3,
2473            TFieldIdentifier {
2474                name: None,
2475                ..field_ident_3
2476            }
2477        );
2478        let read_value_3 = assert_success!(i_prot.read_bool());
2479        assert_eq!(read_value_3, true);
2480        assert_success!(i_prot.read_field_end());
2481
2482        let read_ident_4 = assert_success!(i_prot.read_field_begin());
2483        assert_eq!(
2484            read_ident_4,
2485            TFieldIdentifier {
2486                name: None,
2487                ..field_ident_4
2488            }
2489        );
2490        let read_value_4 = assert_success!(i_prot.read_bool());
2491        assert_eq!(read_value_4, false);
2492        assert_success!(i_prot.read_field_end());
2493
2494        let read_ident_5 = assert_success!(i_prot.read_field_begin());
2495        assert_eq!(
2496            read_ident_5,
2497            TFieldIdentifier {
2498                name: None,
2499                field_type: TType::Stop,
2500                id: None,
2501            }
2502        );
2503
2504        assert_success!(i_prot.read_struct_end());
2505    }
2506
2507    #[test]
2508    #[should_panic]
2509    fn must_fail_if_write_field_end_without_writing_bool_value() {
2510        let (_, mut o_prot) = test_objects();
2511        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
2512        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1)));
2513        o_prot.write_field_end().unwrap();
2514    }
2515
2516    #[test]
2517    #[should_panic]
2518    fn must_fail_if_write_stop_field_without_writing_bool_value() {
2519        let (_, mut o_prot) = test_objects();
2520        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
2521        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1)));
2522        o_prot.write_field_stop().unwrap();
2523    }
2524
2525    #[test]
2526    #[should_panic]
2527    fn must_fail_if_write_struct_end_without_writing_bool_value() {
2528        let (_, mut o_prot) = test_objects();
2529        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
2530        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1)));
2531        o_prot.write_struct_end().unwrap();
2532    }
2533
2534    #[test]
2535    #[should_panic]
2536    fn must_fail_if_write_struct_end_without_any_fields() {
2537        let (_, mut o_prot) = test_objects();
2538        o_prot.write_struct_end().unwrap();
2539    }
2540
2541    #[test]
2542    fn must_write_field_end() {
2543        assert_no_write(|o| o.write_field_end());
2544    }
2545
2546    #[test]
2547    fn must_write_small_sized_list_begin() {
2548        let (_, mut o_prot) = test_objects();
2549
2550        assert_success!(o_prot.write_list_begin(&TListIdentifier::new(TType::I64, 4)));
2551
2552        let expected: [u8; 1] = [0x46 /* size | elem_type */];
2553
2554        assert_eq_written_bytes!(o_prot, expected);
2555    }
2556
2557    #[test]
2558    fn must_round_trip_small_sized_list_begin() {
2559        let (mut i_prot, mut o_prot) = test_objects();
2560
2561        let ident = TListIdentifier::new(TType::I08, 10);
2562
2563        assert_success!(o_prot.write_list_begin(&ident));
2564
2565        copy_write_buffer_to_read_buffer!(o_prot);
2566
2567        let res = assert_success!(i_prot.read_list_begin());
2568        assert_eq!(&res, &ident);
2569    }
2570
2571    #[test]
2572    fn must_write_large_sized_list_begin() {
2573        let (_, mut o_prot) = test_objects();
2574
2575        let res = o_prot.write_list_begin(&TListIdentifier::new(TType::List, 9999));
2576        assert!(res.is_ok());
2577
2578        let expected: [u8; 3] = [
2579            0xF9, /* 0xF0 | elem_type */
2580            0x8F, 0x4E, /* size as varint */
2581        ];
2582
2583        assert_eq_written_bytes!(o_prot, expected);
2584    }
2585
2586    #[test]
2587    fn must_round_trip_large_sized_list_begin() {
2588        let (mut i_prot, mut o_prot) = test_objects();
2589
2590        let ident = TListIdentifier::new(TType::Set, 47381);
2591
2592        assert_success!(o_prot.write_list_begin(&ident));
2593
2594        copy_write_buffer_to_read_buffer!(o_prot);
2595
2596        let res = assert_success!(i_prot.read_list_begin());
2597        assert_eq!(&res, &ident);
2598    }
2599
2600    #[test]
2601    fn must_write_list_end() {
2602        assert_no_write(|o| o.write_list_end());
2603    }
2604
2605    #[test]
2606    fn must_write_small_sized_set_begin() {
2607        let (_, mut o_prot) = test_objects();
2608
2609        assert_success!(o_prot.write_set_begin(&TSetIdentifier::new(TType::Struct, 2)));
2610
2611        let expected: [u8; 1] = [0x2C /* size | elem_type */];
2612
2613        assert_eq_written_bytes!(o_prot, expected);
2614    }
2615
2616    #[test]
2617    fn must_round_trip_small_sized_set_begin() {
2618        let (mut i_prot, mut o_prot) = test_objects();
2619
2620        let ident = TSetIdentifier::new(TType::I16, 7);
2621
2622        assert_success!(o_prot.write_set_begin(&ident));
2623
2624        copy_write_buffer_to_read_buffer!(o_prot);
2625
2626        let res = assert_success!(i_prot.read_set_begin());
2627        assert_eq!(&res, &ident);
2628    }
2629
2630    #[test]
2631    fn must_write_large_sized_set_begin() {
2632        let (_, mut o_prot) = test_objects();
2633
2634        assert_success!(o_prot.write_set_begin(&TSetIdentifier::new(TType::Double, 23891)));
2635
2636        let expected: [u8; 4] = [
2637            0xF7, /* 0xF0 | elem_type */
2638            0xD3, 0xBA, 0x01, /* size as varint */
2639        ];
2640
2641        assert_eq_written_bytes!(o_prot, expected);
2642    }
2643
2644    #[test]
2645    fn must_round_trip_large_sized_set_begin() {
2646        let (mut i_prot, mut o_prot) = test_objects();
2647
2648        let ident = TSetIdentifier::new(TType::Map, 3_928_429);
2649
2650        assert_success!(o_prot.write_set_begin(&ident));
2651
2652        copy_write_buffer_to_read_buffer!(o_prot);
2653
2654        let res = assert_success!(i_prot.read_set_begin());
2655        assert_eq!(&res, &ident);
2656    }
2657
2658    #[test]
2659    fn must_write_set_end() {
2660        assert_no_write(|o| o.write_set_end());
2661    }
2662
2663    #[test]
2664    fn must_write_zero_sized_map_begin() {
2665        let (_, mut o_prot) = test_objects();
2666
2667        assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::String, TType::I32, 0)));
2668
2669        let expected: [u8; 1] = [0x00]; // since size is zero we don't write anything
2670
2671        assert_eq_written_bytes!(o_prot, expected);
2672    }
2673
2674    #[test]
2675    fn must_read_zero_sized_map_begin() {
2676        let (mut i_prot, mut o_prot) = test_objects();
2677
2678        assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::Double, TType::I32, 0)));
2679
2680        copy_write_buffer_to_read_buffer!(o_prot);
2681
2682        let res = assert_success!(i_prot.read_map_begin());
2683        assert_eq!(
2684            &res,
2685            &TMapIdentifier {
2686                key_type: None,
2687                value_type: None,
2688                size: 0,
2689            }
2690        );
2691    }
2692
2693    #[test]
2694    fn must_write_map_begin() {
2695        let (_, mut o_prot) = test_objects();
2696
2697        assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(
2698            TType::Double,
2699            TType::String,
2700            238
2701        )));
2702
2703        let expected: [u8; 3] = [
2704            0xEE, 0x01, /* size as varint */
2705            0x78, /* key type | val type */
2706        ];
2707
2708        assert_eq_written_bytes!(o_prot, expected);
2709    }
2710
2711    #[test]
2712    fn must_round_trip_map_begin() {
2713        let (mut i_prot, mut o_prot) = test_objects();
2714
2715        let ident = TMapIdentifier::new(TType::Map, TType::List, 1_928_349);
2716
2717        assert_success!(o_prot.write_map_begin(&ident));
2718
2719        copy_write_buffer_to_read_buffer!(o_prot);
2720
2721        let res = assert_success!(i_prot.read_map_begin());
2722        assert_eq!(&res, &ident);
2723    }
2724
2725    #[test]
2726    fn must_write_map_end() {
2727        assert_no_write(|o| o.write_map_end());
2728    }
2729
2730    #[test]
2731    fn must_write_map_with_bool_key_and_value() {
2732        let (_, mut o_prot) = test_objects();
2733
2734        assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::Bool, TType::Bool, 1)));
2735        assert_success!(o_prot.write_bool(true));
2736        assert_success!(o_prot.write_bool(false));
2737        assert_success!(o_prot.write_map_end());
2738
2739        let expected: [u8; 4] = [
2740            0x01, /* size as varint */
2741            0x11, /* key type | val type */
2742            0x01, /* key: true */
2743            0x02, /* val: false */
2744        ];
2745
2746        assert_eq_written_bytes!(o_prot, expected);
2747    }
2748
2749    #[test]
2750    fn must_round_trip_map_with_bool_value() {
2751        let (mut i_prot, mut o_prot) = test_objects();
2752
2753        let map_ident = TMapIdentifier::new(TType::Bool, TType::Bool, 2);
2754        assert_success!(o_prot.write_map_begin(&map_ident));
2755        assert_success!(o_prot.write_bool(true));
2756        assert_success!(o_prot.write_bool(false));
2757        assert_success!(o_prot.write_bool(false));
2758        assert_success!(o_prot.write_bool(true));
2759        assert_success!(o_prot.write_map_end());
2760
2761        copy_write_buffer_to_read_buffer!(o_prot);
2762
2763        // map header
2764        let rcvd_ident = assert_success!(i_prot.read_map_begin());
2765        assert_eq!(&rcvd_ident, &map_ident);
2766        // key 1
2767        let b = assert_success!(i_prot.read_bool());
2768        assert_eq!(b, true);
2769        // val 1
2770        let b = assert_success!(i_prot.read_bool());
2771        assert_eq!(b, false);
2772        // key 2
2773        let b = assert_success!(i_prot.read_bool());
2774        assert_eq!(b, false);
2775        // val 2
2776        let b = assert_success!(i_prot.read_bool());
2777        assert_eq!(b, true);
2778        // map end
2779        assert_success!(i_prot.read_map_end());
2780    }
2781
2782    #[test]
2783    fn must_read_map_end() {
2784        let (mut i_prot, _) = test_objects();
2785        assert!(i_prot.read_map_end().is_ok()); // will blow up if we try to read from empty buffer
2786    }
2787
2788    fn test_objects() -> (
2789        TCompactInputProtocol<ReadHalf<TBufferChannel>>,
2790        TCompactOutputProtocol<WriteHalf<TBufferChannel>>,
2791    ) {
2792        let mem = TBufferChannel::with_capacity(80, 80);
2793
2794        let (r_mem, w_mem) = mem.split().unwrap();
2795
2796        let i_prot = TCompactInputProtocol::new(r_mem);
2797        let o_prot = TCompactOutputProtocol::new(w_mem);
2798
2799        (i_prot, o_prot)
2800    }
2801
2802    #[test]
2803    fn must_read_write_double() {
2804        let (mut i_prot, mut o_prot) = test_objects();
2805
2806        #[allow(clippy::approx_constant)]
2807        let double = 3.141_592_653_589_793;
2808        o_prot.write_double(double).unwrap();
2809        copy_write_buffer_to_read_buffer!(o_prot);
2810
2811        let read_double = i_prot.read_double().unwrap();
2812        assert!(read_double - double < std::f64::EPSILON);
2813    }
2814
2815    #[test]
2816    fn must_encode_double_as_other_langs() {
2817        let (_, mut o_prot) = test_objects();
2818        let expected = [24, 45, 68, 84, 251, 33, 9, 64];
2819
2820        #[allow(clippy::approx_constant)]
2821        let double = 3.141_592_653_589_793;
2822        o_prot.write_double(double).unwrap();
2823
2824        assert_eq_written_bytes!(o_prot, expected);
2825    }
2826
2827    fn assert_no_write<F>(mut write_fn: F)
2828    where
2829        F: FnMut(&mut TCompactOutputProtocol<WriteHalf<TBufferChannel>>) -> crate::Result<()>,
2830    {
2831        let (_, mut o_prot) = test_objects();
2832        assert!(write_fn(&mut o_prot).is_ok());
2833        assert_eq!(o_prot.transport.write_bytes().len(), 0);
2834    }
2835}