1use std::{
30 cmp::Ordering,
31 io::{Read, Write},
32};
33
34use crate::{
35 errors::{ParquetError, Result},
36 write_thrift_field,
37};
38use std::io::Error;
39use std::num::TryFromIntError;
40use std::str::Utf8Error;
41
42#[derive(Debug)]
43pub(crate) enum ThriftProtocolError {
44 Eof,
45 IO(Error),
46 InvalidFieldType(u8),
47 InvalidElementType(u8),
48 FieldDeltaOverflow { field_delta: u8, last_field_id: i16 },
49 InvalidBoolean(u8),
50 IntegerOverflow,
51 Utf8Error,
52 SkipDepth(FieldType),
53 SkipUnsupportedType(FieldType),
54}
55
56impl From<ThriftProtocolError> for ParquetError {
57 #[inline(never)]
58 fn from(e: ThriftProtocolError) -> Self {
59 match e {
60 ThriftProtocolError::Eof => eof_err!("Unexpected EOF"),
61 ThriftProtocolError::IO(e) => e.into(),
62 ThriftProtocolError::InvalidFieldType(value) => match FieldType::try_from(value) {
63 Ok(fld_type) => general_err!("Unexpected struct field type {:?}", fld_type),
64 Err(_) => general_err!("Unexpected struct field type {}", value),
65 },
66 ThriftProtocolError::InvalidElementType(value) => {
67 general_err!("Unexpected list/set element type {}", value)
68 }
69 ThriftProtocolError::FieldDeltaOverflow {
70 field_delta,
71 last_field_id,
72 } => general_err!("cannot add {} to {}", field_delta, last_field_id),
73 ThriftProtocolError::InvalidBoolean(value) => {
74 general_err!("cannot convert {} into bool", value)
75 }
76 ThriftProtocolError::IntegerOverflow => {
77 general_err!("integer overflow decoding thrift value")
78 }
79 ThriftProtocolError::Utf8Error => general_err!("invalid utf8"),
80 ThriftProtocolError::SkipDepth(field_type) => {
81 general_err!("cannot parse past {:?}", field_type)
82 }
83 ThriftProtocolError::SkipUnsupportedType(field_type) => {
84 general_err!("cannot skip field type {:?}", field_type)
85 }
86 }
87 }
88}
89
90impl From<Utf8Error> for ThriftProtocolError {
91 fn from(_: Utf8Error) -> Self {
92 Self::Utf8Error
94 }
95}
96
97impl From<Error> for ThriftProtocolError {
98 fn from(e: Error) -> Self {
99 Self::IO(e)
100 }
101}
102
103impl From<TryFromIntError> for ThriftProtocolError {
104 fn from(_: TryFromIntError) -> Self {
105 Self::IntegerOverflow
107 }
108}
109
110pub type ThriftProtocolResult<T> = Result<T, ThriftProtocolError>;
111
112#[derive(Debug, Clone, Copy, PartialEq)]
116pub struct OrderedF64(f64);
117
118impl From<f64> for OrderedF64 {
119 fn from(value: f64) -> Self {
120 Self(value)
121 }
122}
123
124impl From<OrderedF64> for f64 {
125 fn from(value: OrderedF64) -> Self {
126 value.0
127 }
128}
129
130impl Eq for OrderedF64 {} impl Ord for OrderedF64 {
133 fn cmp(&self, other: &Self) -> Ordering {
134 self.0.total_cmp(&other.0)
135 }
136}
137
138impl PartialOrd for OrderedF64 {
139 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
140 Some(self.cmp(other))
141 }
142}
143
144#[derive(Clone, Copy, Debug, Eq, PartialEq)]
146pub(crate) enum FieldType {
147 Stop = 0,
148 BooleanTrue = 1,
149 BooleanFalse = 2,
150 Byte = 3,
151 I16 = 4,
152 I32 = 5,
153 I64 = 6,
154 Double = 7,
155 Binary = 8,
156 List = 9,
157 Set = 10,
158 Map = 11,
159 Struct = 12,
160 Uuid = 13,
161}
162
163impl TryFrom<u8> for FieldType {
164 type Error = ThriftProtocolError;
165 fn try_from(value: u8) -> ThriftProtocolResult<Self> {
166 match value {
167 0 => Ok(Self::Stop),
168 1 => Ok(Self::BooleanTrue),
169 2 => Ok(Self::BooleanFalse),
170 3 => Ok(Self::Byte),
171 4 => Ok(Self::I16),
172 5 => Ok(Self::I32),
173 6 => Ok(Self::I64),
174 7 => Ok(Self::Double),
175 8 => Ok(Self::Binary),
176 9 => Ok(Self::List),
177 10 => Ok(Self::Set),
178 11 => Ok(Self::Map),
179 12 => Ok(Self::Struct),
180 13 => Ok(Self::Uuid),
181 _ => Err(ThriftProtocolError::InvalidFieldType(value)),
182 }
183 }
184}
185
186impl From<ElementType> for FieldType {
187 fn from(value: ElementType) -> Self {
188 match value {
189 ElementType::Bool => Self::BooleanTrue,
190 ElementType::Byte => Self::Byte,
191 ElementType::I16 => Self::I16,
192 ElementType::I32 => Self::I32,
193 ElementType::I64 => Self::I64,
194 ElementType::Double => Self::Double,
195 ElementType::Binary => Self::Binary,
196 ElementType::List => Self::List,
197 ElementType::Set => Self::Set,
198 ElementType::Map => Self::Map,
199 ElementType::Struct => Self::Struct,
200 ElementType::Uuid => Self::Uuid,
201 }
202 }
203}
204
205#[derive(Clone, Copy, Debug, Eq, PartialEq)]
207pub(crate) enum ElementType {
208 Bool = 2,
209 Byte = 3,
210 I16 = 4,
211 I32 = 5,
212 I64 = 6,
213 Double = 7,
214 Binary = 8,
215 List = 9,
216 Set = 10,
217 Map = 11,
218 Struct = 12,
219 Uuid = 13,
220}
221
222impl TryFrom<u8> for ElementType {
223 type Error = ThriftProtocolError;
224 fn try_from(value: u8) -> ThriftProtocolResult<Self> {
225 match value {
226 1 | 2 => Ok(Self::Bool),
232 3 => Ok(Self::Byte),
233 4 => Ok(Self::I16),
234 5 => Ok(Self::I32),
235 6 => Ok(Self::I64),
236 7 => Ok(Self::Double),
237 8 => Ok(Self::Binary),
238 9 => Ok(Self::List),
239 10 => Ok(Self::Set),
240 11 => Ok(Self::Map),
241 12 => Ok(Self::Struct),
242 13 => Ok(Self::Uuid),
243 _ => Err(ThriftProtocolError::InvalidElementType(value)),
244 }
245 }
246}
247
248pub(crate) struct FieldIdentifier {
252 pub(crate) field_type: FieldType,
254 pub(crate) id: i16,
256}
257
258impl FieldIdentifier {
259 pub(crate) fn bool_val(&self) -> ThriftProtocolResult<bool> {
260 match self.field_type {
261 FieldType::BooleanTrue => Ok(true),
262 FieldType::BooleanFalse => Ok(false),
263 _ => Err(ThriftProtocolError::InvalidFieldType(self.field_type as u8)),
264 }
265 }
266}
267
268#[derive(Clone, Debug, Eq, PartialEq)]
272pub(crate) struct ListIdentifier {
273 pub(crate) element_type: ElementType,
275 pub(crate) size: i32,
277}
278
279pub(crate) trait ThriftCompactInputProtocol<'a> {
287 fn read_byte(&mut self) -> ThriftProtocolResult<u8>;
289
290 fn read_bytes(&mut self) -> ThriftProtocolResult<&'a [u8]>;
294
295 fn read_bytes_owned(&mut self) -> ThriftProtocolResult<Vec<u8>>;
296
297 fn skip_bytes(&mut self, n: usize) -> ThriftProtocolResult<()>;
299
300 fn remaining_bytes(&self) -> Option<usize> {
305 None
306 }
307
308 fn read_vlq(&mut self) -> ThriftProtocolResult<u64> {
310 let byte = self.read_byte()?;
312 if byte & 0x80 == 0 {
313 return Ok(byte as u64);
314 }
315 let mut in_progress = (byte & 0x7f) as u64;
316 let mut shift = 7;
317 loop {
318 let byte = self.read_byte()?;
319 in_progress |= ((byte & 0x7F) as u64).wrapping_shl(shift);
320 if byte & 0x80 == 0 {
321 return Ok(in_progress);
322 }
323 shift += 7;
324 }
325 }
326
327 fn read_zig_zag(&mut self) -> ThriftProtocolResult<i64> {
329 let val = self.read_vlq()?;
330 Ok((val >> 1) as i64 ^ -((val & 1) as i64))
331 }
332
333 fn read_list_begin(&mut self) -> ThriftProtocolResult<ListIdentifier> {
335 let header = self.read_byte()?;
336 if header == 0 {
339 return Ok(ListIdentifier {
340 element_type: ElementType::Byte,
341 size: 0,
342 });
343 }
344 let element_type = ElementType::try_from(header & 0x0f)?;
345
346 let possible_element_count = (header & 0xF0) >> 4;
347 let element_count = if possible_element_count != 15 {
348 possible_element_count as i32
350 } else {
351 i32::try_from(self.read_vlq()?)?
358 };
359
360 Ok(ListIdentifier {
361 element_type,
362 size: element_count,
363 })
364 }
365
366 #[cold]
370 fn read_full_field_id(&mut self) -> ThriftProtocolResult<i16> {
371 self.read_i16()
372 }
373
374 fn read_field_begin(&mut self, last_field_id: i16) -> ThriftProtocolResult<FieldIdentifier> {
376 let field_type = self.read_byte()?;
380 if field_type & 0xf == 0 {
381 return Ok(FieldIdentifier {
382 field_type: FieldType::Stop,
383 id: 0,
384 });
385 }
386
387 let field_delta = (field_type & 0xf0) >> 4;
388 let field_type = FieldType::try_from(field_type & 0xf)?;
389
390 let id = if field_delta != 0 {
391 last_field_id.checked_add(field_delta as i16).ok_or(
392 ThriftProtocolError::FieldDeltaOverflow {
393 field_delta,
394 last_field_id,
395 },
396 )?
397 } else {
398 self.read_full_field_id()?
399 };
400
401 Ok(FieldIdentifier { field_type, id })
402 }
403
404 fn read_field_header(&mut self) -> ThriftProtocolResult<(u8, u8)> {
411 let field_type = self.read_byte()?;
412 let field_delta = (field_type & 0xf0) >> 4;
413 let field_type = field_type & 0xf;
414 Ok((field_type, field_delta))
415 }
416
417 fn read_bool(&mut self) -> ThriftProtocolResult<bool> {
420 let b = self.read_byte()?;
421 match b {
426 0x01 => Ok(true),
427 0x00 | 0x02 => Ok(false),
428 _ => Err(ThriftProtocolError::InvalidBoolean(b)),
429 }
430 }
431
432 fn read_string(&mut self) -> ThriftProtocolResult<&'a str> {
436 let slice = self.read_bytes()?;
437 Ok(std::str::from_utf8(slice)?)
438 }
439
440 fn read_i8(&mut self) -> ThriftProtocolResult<i8> {
442 Ok(self.read_byte()? as _)
443 }
444
445 fn read_i16(&mut self) -> ThriftProtocolResult<i16> {
447 Ok(self.read_zig_zag()? as _)
448 }
449
450 fn read_i32(&mut self) -> ThriftProtocolResult<i32> {
452 Ok(self.read_zig_zag()? as _)
453 }
454
455 fn read_i64(&mut self) -> ThriftProtocolResult<i64> {
457 self.read_zig_zag()
458 }
459
460 fn read_double(&mut self) -> ThriftProtocolResult<f64>;
462
463 fn skip_vlq(&mut self) -> ThriftProtocolResult<()> {
465 loop {
466 let byte = self.read_byte()?;
467 if byte & 0x80 == 0 {
468 return Ok(());
469 }
470 }
471 }
472
473 fn skip_binary(&mut self) -> ThriftProtocolResult<()> {
477 let len = usize::try_from(self.read_vlq()?)?;
478 self.skip_bytes(len)
479 }
480
481 fn skip(&mut self, field_type: FieldType) -> ThriftProtocolResult<()> {
484 const DEFAULT_SKIP_DEPTH: i8 = 64;
485 self.skip_till_depth(field_type, DEFAULT_SKIP_DEPTH)
486 }
487
488 fn skip_empty_struct(&mut self) -> Result<()> {
492 let b = self.read_byte()?;
493 if b != 0 {
494 Err(general_err!("Empty struct has fields"))
495 } else {
496 Ok(())
497 }
498 }
499
500 fn skip_till_depth(&mut self, field_type: FieldType, depth: i8) -> ThriftProtocolResult<()> {
502 if depth == 0 {
503 return Err(ThriftProtocolError::SkipDepth(field_type));
504 }
505
506 match field_type {
507 FieldType::BooleanFalse | FieldType::BooleanTrue => Ok(()),
509 FieldType::Byte => self.read_i8().map(|_| ()),
510 FieldType::I16 => self.skip_vlq(),
511 FieldType::I32 => self.skip_vlq(),
512 FieldType::I64 => self.skip_vlq(),
513 FieldType::Double => self.skip_bytes(8),
514 FieldType::Binary => self.skip_binary(),
515 FieldType::Struct => {
517 loop {
518 let field_ident = self.read_field_begin(0)?;
520 if field_ident.field_type == FieldType::Stop {
521 break;
522 }
523 self.skip_till_depth(field_ident.field_type, depth - 1)?;
524 }
525 Ok(())
526 }
527 FieldType::List | FieldType::Set => {
530 let list_ident = self.read_list_begin()?;
531 if list_ident.element_type == ElementType::Bool {
532 self.skip_bool_list(list_ident.size, depth - 1)
533 } else {
534 let field_type = list_ident.element_type.into();
535 for _ in 0..list_ident.size {
536 self.skip_till_depth(field_type, depth - 1)?;
537 }
538 Ok(())
539 }
540 }
541 FieldType::Map => self.skip_map(depth),
543 FieldType::Uuid => self.skip_bytes(16),
545 FieldType::Stop => Err(ThriftProtocolError::SkipUnsupportedType(field_type)),
546 }
547 }
548
549 #[cold]
551 fn skip_bool_list(&mut self, size: i32, depth: i8) -> ThriftProtocolResult<()> {
552 if size > 0 && depth == 0 {
553 return Err(ThriftProtocolError::SkipDepth(FieldType::BooleanTrue));
554 }
555 self.skip_bytes(size as usize)
556 }
557
558 #[cold]
560 fn skip_map(&mut self, depth: i8) -> ThriftProtocolResult<()> {
561 let size = i32::try_from(self.read_vlq()?)?;
562 if size > 0 {
563 let kv = self.read_byte()?;
564 let key_type = ElementType::try_from(kv >> 4)?;
565 let val_type = ElementType::try_from(kv & 0xf)?;
566 for _ in 0..size {
567 self.skip_element_till_depth(key_type, depth - 1)?;
568 self.skip_element_till_depth(val_type, depth - 1)?;
569 }
570 }
571 Ok(())
572 }
573
574 fn skip_element_till_depth(
576 &mut self,
577 element_type: ElementType,
578 depth: i8,
579 ) -> ThriftProtocolResult<()> {
580 if depth == 0 {
581 return Err(ThriftProtocolError::SkipDepth(element_type.into()));
582 }
583 match element_type {
584 ElementType::Bool => self.skip_bytes(1),
585 other => self.skip_till_depth(other.into(), depth),
586 }
587 }
588}
589
590pub(crate) struct ThriftSliceInputProtocol<'a> {
592 buf: &'a [u8],
593}
594
595impl<'a> ThriftSliceInputProtocol<'a> {
596 pub fn new(buf: &'a [u8]) -> Self {
598 Self { buf }
599 }
600
601 pub fn as_slice(&self) -> &'a [u8] {
603 self.buf
604 }
605}
606
607impl<'b, 'a: 'b> ThriftCompactInputProtocol<'b> for ThriftSliceInputProtocol<'a> {
608 #[inline]
609 fn read_byte(&mut self) -> ThriftProtocolResult<u8> {
610 let ret = *self.buf.first().ok_or(ThriftProtocolError::Eof)?;
611 self.buf = &self.buf[1..];
612 Ok(ret)
613 }
614
615 fn read_bytes(&mut self) -> ThriftProtocolResult<&'b [u8]> {
616 let len = self.read_vlq()? as usize;
617 let ret = self.buf.get(..len).ok_or(ThriftProtocolError::Eof)?;
618 self.buf = &self.buf[len..];
619 Ok(ret)
620 }
621
622 fn read_bytes_owned(&mut self) -> ThriftProtocolResult<Vec<u8>> {
623 Ok(self.read_bytes()?.to_vec())
624 }
625
626 #[inline]
627 fn skip_bytes(&mut self, n: usize) -> ThriftProtocolResult<()> {
628 self.buf.get(..n).ok_or(ThriftProtocolError::Eof)?;
629 self.buf = &self.buf[n..];
630 Ok(())
631 }
632
633 fn read_double(&mut self) -> ThriftProtocolResult<f64> {
634 let slice = self.buf.get(..8).ok_or(ThriftProtocolError::Eof)?;
635 self.buf = &self.buf[8..];
636 match slice.try_into() {
637 Ok(slice) => Ok(f64::from_le_bytes(slice)),
638 Err(_) => unreachable!(),
639 }
640 }
641
642 fn remaining_bytes(&self) -> Option<usize> {
643 Some(self.buf.len())
644 }
645}
646
647pub(crate) struct ThriftReadInputProtocol<R: Read> {
652 reader: R,
653}
654
655impl<R: Read> ThriftReadInputProtocol<R> {
656 pub(crate) fn new(reader: R) -> Self {
657 Self { reader }
658 }
659}
660
661impl<'a, R: Read> ThriftCompactInputProtocol<'a> for ThriftReadInputProtocol<R> {
662 #[inline]
663 fn read_byte(&mut self) -> ThriftProtocolResult<u8> {
664 let mut buf = [0_u8; 1];
665 self.reader.read_exact(&mut buf)?;
666 Ok(buf[0])
667 }
668
669 fn read_bytes(&mut self) -> ThriftProtocolResult<&'a [u8]> {
670 unimplemented!()
671 }
672
673 fn read_bytes_owned(&mut self) -> ThriftProtocolResult<Vec<u8>> {
674 let len = self.read_vlq()? as usize;
675 let mut v = Vec::with_capacity(len);
676 std::io::copy(&mut self.reader.by_ref().take(len as u64), &mut v)?;
677 Ok(v)
678 }
679
680 fn skip_bytes(&mut self, n: usize) -> ThriftProtocolResult<()> {
681 let skipped = std::io::copy(
682 &mut self.reader.by_ref().take(n as u64),
683 &mut std::io::sink(),
684 )?;
685 if skipped != n as u64 {
686 return Err(ThriftProtocolError::Eof);
687 }
688 Ok(())
689 }
690
691 fn read_double(&mut self) -> ThriftProtocolResult<f64> {
692 let mut buf = [0_u8; 8];
693 self.reader.read_exact(&mut buf)?;
694 Ok(f64::from_le_bytes(buf))
695 }
696}
697
698pub(crate) trait ReadThrift<'a, R: ThriftCompactInputProtocol<'a>> {
701 fn read_thrift(prot: &mut R) -> Result<Self>
703 where
704 Self: Sized;
705}
706
707impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for bool {
708 fn read_thrift(prot: &mut R) -> Result<Self> {
709 Ok(prot.read_bool()?)
710 }
711}
712
713impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for i8 {
714 fn read_thrift(prot: &mut R) -> Result<Self> {
715 Ok(prot.read_i8()?)
716 }
717}
718
719impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for i16 {
720 fn read_thrift(prot: &mut R) -> Result<Self> {
721 Ok(prot.read_i16()?)
722 }
723}
724
725impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for i32 {
726 fn read_thrift(prot: &mut R) -> Result<Self> {
727 Ok(prot.read_i32()?)
728 }
729}
730
731impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for i64 {
732 fn read_thrift(prot: &mut R) -> Result<Self> {
733 Ok(prot.read_i64()?)
734 }
735}
736
737impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for OrderedF64 {
738 fn read_thrift(prot: &mut R) -> Result<Self> {
739 Ok(OrderedF64(prot.read_double()?))
740 }
741}
742
743impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for &'a str {
744 fn read_thrift(prot: &mut R) -> Result<Self> {
745 Ok(prot.read_string()?)
746 }
747}
748
749impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for String {
750 fn read_thrift(prot: &mut R) -> Result<Self> {
751 Ok(String::from_utf8(prot.read_bytes_owned()?)?)
752 }
753}
754
755impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for &'a [u8] {
756 fn read_thrift(prot: &mut R) -> Result<Self> {
757 Ok(prot.read_bytes()?)
758 }
759}
760
761pub(crate) fn read_thrift_vec<'a, T, R>(prot: &mut R) -> Result<Vec<T>>
765where
766 R: ThriftCompactInputProtocol<'a>,
767 T: ReadThrift<'a, R> + WriteThrift,
768{
769 let list_ident = prot.read_list_begin()?;
770 validate_list_type(T::ELEMENT_TYPE, &list_ident)?;
771 let size = list_ident.size as usize;
772 check_list_size(prot.remaining_bytes(), size)?;
773 let mut res = Vec::with_capacity(size);
774 for _ in 0..list_ident.size {
775 let val = T::read_thrift(prot)?;
776 res.push(val);
777 }
778 Ok(res)
779}
780
781pub(crate) fn validate_list_type(expected: ElementType, got: &ListIdentifier) -> Result<()> {
782 if got.element_type != expected {
783 return Err(general_err!(
784 "Expected list element type of {:?} but got {:?}",
785 expected,
786 got.element_type
787 ));
788 }
789 Ok(())
790}
791
792pub(crate) fn check_list_size(remaining: Option<usize>, size: usize) -> Result<()> {
798 if let Some(remaining) = remaining
799 && size > remaining
800 {
801 return Err(general_err!(
802 "Thrift list size {size} exceeds remaining input length {remaining}"
803 ));
804 }
805 Ok(())
806}
807
808pub(crate) struct ThriftCompactOutputProtocol<W: Write> {
820 writer: W,
821 write_path_in_schema: bool,
822 write_rg_ordinal: bool,
823}
824
825impl<W: Write> ThriftCompactOutputProtocol<W> {
826 pub(crate) fn new(writer: W) -> Self {
828 Self {
829 writer,
830 write_path_in_schema: true,
831 write_rg_ordinal: true,
832 }
833 }
834
835 pub(crate) fn set_write_path_in_schema(&mut self, val: bool) {
840 self.write_path_in_schema = val;
841 }
842
843 pub(crate) fn write_path_in_schema(&self) -> bool {
845 self.write_path_in_schema
846 }
847
848 pub(crate) fn set_write_row_group_ordinal(&mut self, val: bool) {
855 self.write_rg_ordinal = val;
856 }
857
858 pub(crate) fn write_row_group_ordinal(&self) -> bool {
860 self.write_rg_ordinal
861 }
862
863 fn write_byte(&mut self, b: u8) -> Result<()> {
865 self.writer.write_all(&[b])?;
866 Ok(())
867 }
868
869 fn write_vlq(&mut self, val: u64) -> Result<()> {
871 let mut v = val;
872 while v > 0x7f {
873 self.write_byte(v as u8 | 0x80)?;
874 v >>= 7;
875 }
876 self.write_byte(v as u8)
877 }
878
879 fn write_zig_zag(&mut self, val: i64) -> Result<()> {
881 let s = (val < 0) as i64;
882 self.write_vlq((((val ^ -s) << 1) + s) as u64)
883 }
884
885 pub(crate) fn write_field_begin(
890 &mut self,
891 field_type: FieldType,
892 field_id: i16,
893 last_field_id: i16,
894 ) -> Result<()> {
895 let delta = field_id.wrapping_sub(last_field_id);
896 if delta > 0 && delta <= 0xf {
897 self.write_byte(((delta as u8) << 4) | field_type as u8)
898 } else {
899 self.write_byte(field_type as u8)?;
900 self.write_i16(field_id)
901 }
902 }
903
904 pub(crate) fn write_list_begin(&mut self, element_type: ElementType, len: usize) -> Result<()> {
906 if len < 15 {
907 self.write_byte(((len as u8) << 4) | element_type as u8)
908 } else {
909 self.write_byte(0xf0u8 | element_type as u8)?;
910 self.write_vlq(len as _)
911 }
912 }
913
914 pub(crate) fn write_struct_end(&mut self) -> Result<()> {
917 self.write_byte(0)
918 }
919
920 pub(crate) fn write_bytes(&mut self, val: &[u8]) -> Result<()> {
923 self.write_vlq(val.len() as u64)?;
924 self.writer.write_all(val)?;
925 Ok(())
926 }
927
928 pub(crate) fn write_empty_struct(&mut self, field_id: i16, last_field_id: i16) -> Result<i16> {
931 self.write_field_begin(FieldType::Struct, field_id, last_field_id)?;
932 self.write_struct_end()?;
933 Ok(last_field_id)
934 }
935
936 pub(crate) fn write_bool(&mut self, val: bool) -> Result<()> {
938 match val {
939 true => self.write_byte(1),
940 false => self.write_byte(2),
941 }
942 }
943
944 pub(crate) fn write_i8(&mut self, val: i8) -> Result<()> {
946 self.write_byte(val as u8)
947 }
948
949 pub(crate) fn write_i16(&mut self, val: i16) -> Result<()> {
951 self.write_zig_zag(val as _)
952 }
953
954 pub(crate) fn write_i32(&mut self, val: i32) -> Result<()> {
956 self.write_zig_zag(val as _)
957 }
958
959 pub(crate) fn write_i64(&mut self, val: i64) -> Result<()> {
961 self.write_zig_zag(val)
962 }
963
964 pub(crate) fn write_double(&mut self, val: f64) -> Result<()> {
966 self.writer.write_all(&val.to_le_bytes())?;
967 Ok(())
968 }
969}
970
971pub(crate) trait WriteThrift {
976 const ELEMENT_TYPE: ElementType;
978
979 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()>;
981}
982
983impl<T> WriteThrift for Vec<T>
986where
987 T: WriteThrift,
988{
989 const ELEMENT_TYPE: ElementType = ElementType::List;
990
991 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
992 writer.write_list_begin(T::ELEMENT_TYPE, self.len())?;
993 for item in self {
994 item.write_thrift(writer)?;
995 }
996 Ok(())
997 }
998}
999
1000impl WriteThrift for bool {
1001 const ELEMENT_TYPE: ElementType = ElementType::Bool;
1002
1003 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
1004 writer.write_bool(*self)
1005 }
1006}
1007
1008impl WriteThrift for i8 {
1009 const ELEMENT_TYPE: ElementType = ElementType::Byte;
1010
1011 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
1012 writer.write_i8(*self)
1013 }
1014}
1015
1016impl WriteThrift for i16 {
1017 const ELEMENT_TYPE: ElementType = ElementType::I16;
1018
1019 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
1020 writer.write_i16(*self)
1021 }
1022}
1023
1024impl WriteThrift for i32 {
1025 const ELEMENT_TYPE: ElementType = ElementType::I32;
1026
1027 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
1028 writer.write_i32(*self)
1029 }
1030}
1031
1032impl WriteThrift for i64 {
1033 const ELEMENT_TYPE: ElementType = ElementType::I64;
1034
1035 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
1036 writer.write_i64(*self)
1037 }
1038}
1039
1040impl WriteThrift for OrderedF64 {
1041 const ELEMENT_TYPE: ElementType = ElementType::Double;
1042
1043 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
1044 writer.write_double(self.0)
1045 }
1046}
1047
1048impl WriteThrift for f64 {
1049 const ELEMENT_TYPE: ElementType = ElementType::Double;
1050
1051 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
1052 writer.write_double(*self)
1053 }
1054}
1055
1056impl WriteThrift for &[u8] {
1057 const ELEMENT_TYPE: ElementType = ElementType::Binary;
1058
1059 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
1060 writer.write_bytes(self)
1061 }
1062}
1063
1064impl WriteThrift for &str {
1065 const ELEMENT_TYPE: ElementType = ElementType::Binary;
1066
1067 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
1068 writer.write_bytes(self.as_bytes())
1069 }
1070}
1071
1072impl WriteThrift for String {
1073 const ELEMENT_TYPE: ElementType = ElementType::Binary;
1074
1075 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
1076 writer.write_bytes(self.as_bytes())
1077 }
1078}
1079
1080pub(crate) trait WriteThriftField {
1123 fn write_thrift_field<W: Write>(
1130 &self,
1131 writer: &mut ThriftCompactOutputProtocol<W>,
1132 field_id: i16,
1133 last_field_id: i16,
1134 ) -> Result<i16>;
1135}
1136
1137impl WriteThriftField for bool {
1139 fn write_thrift_field<W: Write>(
1140 &self,
1141 writer: &mut ThriftCompactOutputProtocol<W>,
1142 field_id: i16,
1143 last_field_id: i16,
1144 ) -> Result<i16> {
1145 match *self {
1147 true => writer.write_field_begin(FieldType::BooleanTrue, field_id, last_field_id)?,
1148 false => writer.write_field_begin(FieldType::BooleanFalse, field_id, last_field_id)?,
1149 }
1150 Ok(field_id)
1151 }
1152}
1153
1154write_thrift_field!(i8, FieldType::Byte);
1155write_thrift_field!(i16, FieldType::I16);
1156write_thrift_field!(i32, FieldType::I32);
1157write_thrift_field!(i64, FieldType::I64);
1158write_thrift_field!(OrderedF64, FieldType::Double);
1159write_thrift_field!(f64, FieldType::Double);
1160write_thrift_field!(String, FieldType::Binary);
1161
1162impl WriteThriftField for &[u8] {
1163 fn write_thrift_field<W: Write>(
1164 &self,
1165 writer: &mut ThriftCompactOutputProtocol<W>,
1166 field_id: i16,
1167 last_field_id: i16,
1168 ) -> Result<i16> {
1169 writer.write_field_begin(FieldType::Binary, field_id, last_field_id)?;
1170 writer.write_bytes(self)?;
1171 Ok(field_id)
1172 }
1173}
1174
1175impl WriteThriftField for &str {
1176 fn write_thrift_field<W: Write>(
1177 &self,
1178 writer: &mut ThriftCompactOutputProtocol<W>,
1179 field_id: i16,
1180 last_field_id: i16,
1181 ) -> Result<i16> {
1182 writer.write_field_begin(FieldType::Binary, field_id, last_field_id)?;
1183 writer.write_bytes(self.as_bytes())?;
1184 Ok(field_id)
1185 }
1186}
1187
1188impl<T> WriteThriftField for Vec<T>
1189where
1190 T: WriteThrift,
1191{
1192 fn write_thrift_field<W: Write>(
1193 &self,
1194 writer: &mut ThriftCompactOutputProtocol<W>,
1195 field_id: i16,
1196 last_field_id: i16,
1197 ) -> Result<i16> {
1198 writer.write_field_begin(FieldType::List, field_id, last_field_id)?;
1199 self.write_thrift(writer)?;
1200 Ok(field_id)
1201 }
1202}
1203
1204#[cfg(test)]
1205pub(crate) mod tests {
1206 use crate::basic::{TimeUnit, Type};
1207
1208 use super::*;
1209 use std::fmt::Debug;
1210
1211 pub(crate) fn test_roundtrip<T>(val: T)
1212 where
1213 T: for<'a> ReadThrift<'a, ThriftSliceInputProtocol<'a>> + WriteThrift + PartialEq + Debug,
1214 {
1215 let mut buf = Vec::<u8>::new();
1216 {
1217 let mut writer = ThriftCompactOutputProtocol::new(&mut buf);
1218 val.write_thrift(&mut writer).unwrap();
1219 }
1220
1221 let mut prot = ThriftSliceInputProtocol::new(&buf);
1222 let read_val = T::read_thrift(&mut prot).unwrap();
1223 assert_eq!(val, read_val);
1224 }
1225
1226 #[test]
1227 fn test_enum_roundtrip() {
1228 test_roundtrip(Type::BOOLEAN);
1229 test_roundtrip(Type::INT32);
1230 test_roundtrip(Type::INT64);
1231 test_roundtrip(Type::INT96);
1232 test_roundtrip(Type::FLOAT);
1233 test_roundtrip(Type::DOUBLE);
1234 test_roundtrip(Type::BYTE_ARRAY);
1235 test_roundtrip(Type::FIXED_LEN_BYTE_ARRAY);
1236 }
1237
1238 #[test]
1239 fn test_union_all_empty_roundtrip() {
1240 test_roundtrip(TimeUnit::MILLIS);
1241 test_roundtrip(TimeUnit::MICROS);
1242 test_roundtrip(TimeUnit::NANOS);
1243 }
1244
1245 #[test]
1246 fn test_decode_empty_list() {
1247 let data = vec![0u8; 1];
1248 let mut prot = ThriftSliceInputProtocol::new(&data);
1249 let header = prot.read_list_begin().expect("error reading list header");
1250 assert_eq!(header.size, 0);
1251 assert_eq!(header.element_type, ElementType::Byte);
1252 }
1253
1254 #[test]
1258 fn test_read_list_begin_size_above_i32_max_returns_err() {
1259 let mut data: Vec<u8> = vec![0xF8];
1262 data.extend_from_slice(&[0x80, 0x80, 0x80, 0x80, 0x08]);
1263 let mut prot = ThriftSliceInputProtocol::new(&data);
1264 let result = prot.read_list_begin();
1265 assert!(result.is_err(), "expected error, got {result:?}");
1266 }
1267
1268 crate::thrift_struct! {
1270 struct KnownField {
1271 2: required i32 value;
1272 }
1273 }
1274
1275 #[test]
1276 fn test_skip_boolean_collections_before_known_field() {
1277 for collection_type in [FieldType::List, FieldType::Set] {
1278 let data = [0x10 | collection_type as u8, 0x22, 2, 1, 0x15, 84, 0];
1281 let mut protocol = ThriftSliceInputProtocol::new(&data);
1282 assert_eq!(KnownField::read_thrift(&mut protocol).unwrap().value, 42);
1283 assert!(protocol.as_slice().is_empty());
1284 }
1285 }
1286
1287 #[test]
1288 fn test_skip_map_before_known_field() {
1289 let data = [0x1b, 2, 0x25, 1, 14, 2, 16, 0x15, 84, 0];
1291 let mut protocol = ThriftSliceInputProtocol::new(&data);
1292 assert_eq!(KnownField::read_thrift(&mut protocol).unwrap().value, 42);
1293 assert!(protocol.as_slice().is_empty());
1294 }
1295
1296 #[test]
1297 fn test_read_list_wrong_type() {
1298 let data = [0x42, 0x01];
1300 let mut prot = ThriftSliceInputProtocol::new(&data);
1301 let result = read_thrift_vec::<i32, ThriftSliceInputProtocol>(&mut prot);
1303 println!("{result:?}");
1304 assert!(
1305 result
1306 .unwrap_err()
1307 .to_string()
1308 .contains("Expected list element type of I32 but got Bool")
1309 );
1310 }
1311
1312 #[test]
1313 fn test_read_thrift_vec_roundtrip_i32() {
1314 let data = [0x25, 0x00, 0x00];
1316 let mut prot = ThriftSliceInputProtocol::new(&data);
1317 let result = read_thrift_vec::<i32, ThriftSliceInputProtocol>(&mut prot).unwrap();
1318 assert_eq!(result, vec![0, 0]);
1319 }
1320
1321 #[test]
1322 fn test_read_thrift_vec_size_exceeds_remaining_returns_err() {
1323 let data = [0xE5];
1327 let mut prot = ThriftSliceInputProtocol::new(&data);
1328 let result = read_thrift_vec::<i32, ThriftSliceInputProtocol>(&mut prot);
1329 assert!(result.is_err(), "expected error, got {result:?}");
1330 assert!(
1331 result
1332 .unwrap_err()
1333 .to_string()
1334 .contains("Thrift list size 14 exceeds remaining input length 0")
1335 );
1336 }
1337
1338 #[test]
1339 fn test_read_thrift_vec_huge_declared_size_returns_err() {
1340 let data = [0xF5, 0xfc, 0xfc, 0xfc, 0x33, 0x00, 0x00];
1344 let mut prot = ThriftSliceInputProtocol::new(&data);
1345 let result = read_thrift_vec::<i32, ThriftSliceInputProtocol>(&mut prot);
1346 assert!(result.is_err(), "expected error, got {result:?}");
1347 let err = result.unwrap_err().to_string();
1348 assert!(
1349 err.contains("Thrift list size 109002364 exceeds remaining input length 2"),
1350 "{err}"
1351 );
1352 }
1353}