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 = self.read_vlq()? as usize;
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 let element_type = FieldType::from(list_ident.element_type);
532 for _ in 0..list_ident.size {
533 self.skip_till_depth(element_type, depth - 1)?;
534 }
535 Ok(())
536 }
537 FieldType::Map => {
539 let size = i32::try_from(self.read_vlq()?)?;
540 if size > 0 {
541 let kv = self.read_byte()?;
542 let key_type = FieldType::from(ElementType::try_from(kv >> 4)?);
543 let val_type = FieldType::from(ElementType::try_from(kv & 0xf)?);
544 for _ in 0..size {
545 self.skip_till_depth(key_type, depth - 1)?;
546 self.skip_till_depth(val_type, depth - 1)?;
547 }
548 }
549 Ok(())
550 }
551 FieldType::Uuid => self.skip_bytes(16),
553 FieldType::Stop => Err(ThriftProtocolError::SkipUnsupportedType(field_type)),
554 }
555 }
556}
557
558pub(crate) struct ThriftSliceInputProtocol<'a> {
560 buf: &'a [u8],
561}
562
563impl<'a> ThriftSliceInputProtocol<'a> {
564 pub fn new(buf: &'a [u8]) -> Self {
566 Self { buf }
567 }
568
569 pub fn as_slice(&self) -> &'a [u8] {
571 self.buf
572 }
573}
574
575impl<'b, 'a: 'b> ThriftCompactInputProtocol<'b> for ThriftSliceInputProtocol<'a> {
576 #[inline]
577 fn read_byte(&mut self) -> ThriftProtocolResult<u8> {
578 let ret = *self.buf.first().ok_or(ThriftProtocolError::Eof)?;
579 self.buf = &self.buf[1..];
580 Ok(ret)
581 }
582
583 fn read_bytes(&mut self) -> ThriftProtocolResult<&'b [u8]> {
584 let len = self.read_vlq()? as usize;
585 let ret = self.buf.get(..len).ok_or(ThriftProtocolError::Eof)?;
586 self.buf = &self.buf[len..];
587 Ok(ret)
588 }
589
590 fn read_bytes_owned(&mut self) -> ThriftProtocolResult<Vec<u8>> {
591 Ok(self.read_bytes()?.to_vec())
592 }
593
594 #[inline]
595 fn skip_bytes(&mut self, n: usize) -> ThriftProtocolResult<()> {
596 self.buf.get(..n).ok_or(ThriftProtocolError::Eof)?;
597 self.buf = &self.buf[n..];
598 Ok(())
599 }
600
601 fn read_double(&mut self) -> ThriftProtocolResult<f64> {
602 let slice = self.buf.get(..8).ok_or(ThriftProtocolError::Eof)?;
603 self.buf = &self.buf[8..];
604 match slice.try_into() {
605 Ok(slice) => Ok(f64::from_le_bytes(slice)),
606 Err(_) => unreachable!(),
607 }
608 }
609
610 fn remaining_bytes(&self) -> Option<usize> {
611 Some(self.buf.len())
612 }
613}
614
615pub(crate) struct ThriftReadInputProtocol<R: Read> {
620 reader: R,
621}
622
623impl<R: Read> ThriftReadInputProtocol<R> {
624 pub(crate) fn new(reader: R) -> Self {
625 Self { reader }
626 }
627}
628
629impl<'a, R: Read> ThriftCompactInputProtocol<'a> for ThriftReadInputProtocol<R> {
630 #[inline]
631 fn read_byte(&mut self) -> ThriftProtocolResult<u8> {
632 let mut buf = [0_u8; 1];
633 self.reader.read_exact(&mut buf)?;
634 Ok(buf[0])
635 }
636
637 fn read_bytes(&mut self) -> ThriftProtocolResult<&'a [u8]> {
638 unimplemented!()
639 }
640
641 fn read_bytes_owned(&mut self) -> ThriftProtocolResult<Vec<u8>> {
642 let len = self.read_vlq()? as usize;
643 let mut v = Vec::with_capacity(len);
644 std::io::copy(&mut self.reader.by_ref().take(len as u64), &mut v)?;
645 Ok(v)
646 }
647
648 fn skip_bytes(&mut self, n: usize) -> ThriftProtocolResult<()> {
649 std::io::copy(
650 &mut self.reader.by_ref().take(n as u64),
651 &mut std::io::sink(),
652 )?;
653 Ok(())
654 }
655
656 fn read_double(&mut self) -> ThriftProtocolResult<f64> {
657 let mut buf = [0_u8; 8];
658 self.reader.read_exact(&mut buf)?;
659 Ok(f64::from_le_bytes(buf))
660 }
661}
662
663pub(crate) trait ReadThrift<'a, R: ThriftCompactInputProtocol<'a>> {
666 fn read_thrift(prot: &mut R) -> Result<Self>
668 where
669 Self: Sized;
670}
671
672impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for bool {
673 fn read_thrift(prot: &mut R) -> Result<Self> {
674 Ok(prot.read_bool()?)
675 }
676}
677
678impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for i8 {
679 fn read_thrift(prot: &mut R) -> Result<Self> {
680 Ok(prot.read_i8()?)
681 }
682}
683
684impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for i16 {
685 fn read_thrift(prot: &mut R) -> Result<Self> {
686 Ok(prot.read_i16()?)
687 }
688}
689
690impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for i32 {
691 fn read_thrift(prot: &mut R) -> Result<Self> {
692 Ok(prot.read_i32()?)
693 }
694}
695
696impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for i64 {
697 fn read_thrift(prot: &mut R) -> Result<Self> {
698 Ok(prot.read_i64()?)
699 }
700}
701
702impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for OrderedF64 {
703 fn read_thrift(prot: &mut R) -> Result<Self> {
704 Ok(OrderedF64(prot.read_double()?))
705 }
706}
707
708impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for &'a str {
709 fn read_thrift(prot: &mut R) -> Result<Self> {
710 Ok(prot.read_string()?)
711 }
712}
713
714impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for String {
715 fn read_thrift(prot: &mut R) -> Result<Self> {
716 Ok(String::from_utf8(prot.read_bytes_owned()?)?)
717 }
718}
719
720impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for &'a [u8] {
721 fn read_thrift(prot: &mut R) -> Result<Self> {
722 Ok(prot.read_bytes()?)
723 }
724}
725
726pub(crate) fn read_thrift_vec<'a, T, R>(prot: &mut R) -> Result<Vec<T>>
730where
731 R: ThriftCompactInputProtocol<'a>,
732 T: ReadThrift<'a, R> + WriteThrift,
733{
734 let list_ident = prot.read_list_begin()?;
735 validate_list_type(T::ELEMENT_TYPE, &list_ident)?;
736 let size = list_ident.size as usize;
737 if let Some(remaining) = prot.remaining_bytes()
741 && size > remaining
742 {
743 return Err(general_err!(
744 "Thrift list size {} exceeds remaining input length {}",
745 size,
746 remaining
747 ));
748 }
749 let mut res = Vec::with_capacity(size);
750 for _ in 0..list_ident.size {
751 let val = T::read_thrift(prot)?;
752 res.push(val);
753 }
754 Ok(res)
755}
756
757pub(crate) fn validate_list_type(expected: ElementType, got: &ListIdentifier) -> Result<()> {
758 if got.element_type != expected {
759 return Err(general_err!(
760 "Expected list element type of {:?} but got {:?}",
761 expected,
762 got.element_type
763 ));
764 }
765 Ok(())
766}
767
768pub(crate) struct ThriftCompactOutputProtocol<W: Write> {
780 writer: W,
781 write_path_in_schema: bool,
782 write_rg_ordinal: bool,
783}
784
785impl<W: Write> ThriftCompactOutputProtocol<W> {
786 pub(crate) fn new(writer: W) -> Self {
788 Self {
789 writer,
790 write_path_in_schema: true,
791 write_rg_ordinal: true,
792 }
793 }
794
795 pub(crate) fn set_write_path_in_schema(&mut self, val: bool) {
800 self.write_path_in_schema = val;
801 }
802
803 pub(crate) fn write_path_in_schema(&self) -> bool {
805 self.write_path_in_schema
806 }
807
808 pub(crate) fn set_write_row_group_ordinal(&mut self, val: bool) {
815 self.write_rg_ordinal = val;
816 }
817
818 pub(crate) fn write_row_group_ordinal(&self) -> bool {
820 self.write_rg_ordinal
821 }
822
823 fn write_byte(&mut self, b: u8) -> Result<()> {
825 self.writer.write_all(&[b])?;
826 Ok(())
827 }
828
829 fn write_vlq(&mut self, val: u64) -> Result<()> {
831 let mut v = val;
832 while v > 0x7f {
833 self.write_byte(v as u8 | 0x80)?;
834 v >>= 7;
835 }
836 self.write_byte(v as u8)
837 }
838
839 fn write_zig_zag(&mut self, val: i64) -> Result<()> {
841 let s = (val < 0) as i64;
842 self.write_vlq((((val ^ -s) << 1) + s) as u64)
843 }
844
845 pub(crate) fn write_field_begin(
850 &mut self,
851 field_type: FieldType,
852 field_id: i16,
853 last_field_id: i16,
854 ) -> Result<()> {
855 let delta = field_id.wrapping_sub(last_field_id);
856 if delta > 0 && delta <= 0xf {
857 self.write_byte(((delta as u8) << 4) | field_type as u8)
858 } else {
859 self.write_byte(field_type as u8)?;
860 self.write_i16(field_id)
861 }
862 }
863
864 pub(crate) fn write_list_begin(&mut self, element_type: ElementType, len: usize) -> Result<()> {
866 if len < 15 {
867 self.write_byte(((len as u8) << 4) | element_type as u8)
868 } else {
869 self.write_byte(0xf0u8 | element_type as u8)?;
870 self.write_vlq(len as _)
871 }
872 }
873
874 pub(crate) fn write_struct_end(&mut self) -> Result<()> {
877 self.write_byte(0)
878 }
879
880 pub(crate) fn write_bytes(&mut self, val: &[u8]) -> Result<()> {
883 self.write_vlq(val.len() as u64)?;
884 self.writer.write_all(val)?;
885 Ok(())
886 }
887
888 pub(crate) fn write_empty_struct(&mut self, field_id: i16, last_field_id: i16) -> Result<i16> {
891 self.write_field_begin(FieldType::Struct, field_id, last_field_id)?;
892 self.write_struct_end()?;
893 Ok(last_field_id)
894 }
895
896 pub(crate) fn write_bool(&mut self, val: bool) -> Result<()> {
898 match val {
899 true => self.write_byte(1),
900 false => self.write_byte(2),
901 }
902 }
903
904 pub(crate) fn write_i8(&mut self, val: i8) -> Result<()> {
906 self.write_byte(val as u8)
907 }
908
909 pub(crate) fn write_i16(&mut self, val: i16) -> Result<()> {
911 self.write_zig_zag(val as _)
912 }
913
914 pub(crate) fn write_i32(&mut self, val: i32) -> Result<()> {
916 self.write_zig_zag(val as _)
917 }
918
919 pub(crate) fn write_i64(&mut self, val: i64) -> Result<()> {
921 self.write_zig_zag(val)
922 }
923
924 pub(crate) fn write_double(&mut self, val: f64) -> Result<()> {
926 self.writer.write_all(&val.to_le_bytes())?;
927 Ok(())
928 }
929}
930
931pub(crate) trait WriteThrift {
936 const ELEMENT_TYPE: ElementType;
938
939 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()>;
941}
942
943impl<T> WriteThrift for Vec<T>
946where
947 T: WriteThrift,
948{
949 const ELEMENT_TYPE: ElementType = ElementType::List;
950
951 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
952 writer.write_list_begin(T::ELEMENT_TYPE, self.len())?;
953 for item in self {
954 item.write_thrift(writer)?;
955 }
956 Ok(())
957 }
958}
959
960impl WriteThrift for bool {
961 const ELEMENT_TYPE: ElementType = ElementType::Bool;
962
963 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
964 writer.write_bool(*self)
965 }
966}
967
968impl WriteThrift for i8 {
969 const ELEMENT_TYPE: ElementType = ElementType::Byte;
970
971 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
972 writer.write_i8(*self)
973 }
974}
975
976impl WriteThrift for i16 {
977 const ELEMENT_TYPE: ElementType = ElementType::I16;
978
979 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
980 writer.write_i16(*self)
981 }
982}
983
984impl WriteThrift for i32 {
985 const ELEMENT_TYPE: ElementType = ElementType::I32;
986
987 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
988 writer.write_i32(*self)
989 }
990}
991
992impl WriteThrift for i64 {
993 const ELEMENT_TYPE: ElementType = ElementType::I64;
994
995 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
996 writer.write_i64(*self)
997 }
998}
999
1000impl WriteThrift for OrderedF64 {
1001 const ELEMENT_TYPE: ElementType = ElementType::Double;
1002
1003 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
1004 writer.write_double(self.0)
1005 }
1006}
1007
1008impl WriteThrift for f64 {
1009 const ELEMENT_TYPE: ElementType = ElementType::Double;
1010
1011 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
1012 writer.write_double(*self)
1013 }
1014}
1015
1016impl WriteThrift for &[u8] {
1017 const ELEMENT_TYPE: ElementType = ElementType::Binary;
1018
1019 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
1020 writer.write_bytes(self)
1021 }
1022}
1023
1024impl WriteThrift for &str {
1025 const ELEMENT_TYPE: ElementType = ElementType::Binary;
1026
1027 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
1028 writer.write_bytes(self.as_bytes())
1029 }
1030}
1031
1032impl WriteThrift for String {
1033 const ELEMENT_TYPE: ElementType = ElementType::Binary;
1034
1035 fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
1036 writer.write_bytes(self.as_bytes())
1037 }
1038}
1039
1040pub(crate) trait WriteThriftField {
1083 fn write_thrift_field<W: Write>(
1090 &self,
1091 writer: &mut ThriftCompactOutputProtocol<W>,
1092 field_id: i16,
1093 last_field_id: i16,
1094 ) -> Result<i16>;
1095}
1096
1097impl WriteThriftField for bool {
1099 fn write_thrift_field<W: Write>(
1100 &self,
1101 writer: &mut ThriftCompactOutputProtocol<W>,
1102 field_id: i16,
1103 last_field_id: i16,
1104 ) -> Result<i16> {
1105 match *self {
1107 true => writer.write_field_begin(FieldType::BooleanTrue, field_id, last_field_id)?,
1108 false => writer.write_field_begin(FieldType::BooleanFalse, field_id, last_field_id)?,
1109 }
1110 Ok(field_id)
1111 }
1112}
1113
1114write_thrift_field!(i8, FieldType::Byte);
1115write_thrift_field!(i16, FieldType::I16);
1116write_thrift_field!(i32, FieldType::I32);
1117write_thrift_field!(i64, FieldType::I64);
1118write_thrift_field!(OrderedF64, FieldType::Double);
1119write_thrift_field!(f64, FieldType::Double);
1120write_thrift_field!(String, FieldType::Binary);
1121
1122impl WriteThriftField for &[u8] {
1123 fn write_thrift_field<W: Write>(
1124 &self,
1125 writer: &mut ThriftCompactOutputProtocol<W>,
1126 field_id: i16,
1127 last_field_id: i16,
1128 ) -> Result<i16> {
1129 writer.write_field_begin(FieldType::Binary, field_id, last_field_id)?;
1130 writer.write_bytes(self)?;
1131 Ok(field_id)
1132 }
1133}
1134
1135impl WriteThriftField for &str {
1136 fn write_thrift_field<W: Write>(
1137 &self,
1138 writer: &mut ThriftCompactOutputProtocol<W>,
1139 field_id: i16,
1140 last_field_id: i16,
1141 ) -> Result<i16> {
1142 writer.write_field_begin(FieldType::Binary, field_id, last_field_id)?;
1143 writer.write_bytes(self.as_bytes())?;
1144 Ok(field_id)
1145 }
1146}
1147
1148impl<T> WriteThriftField for Vec<T>
1149where
1150 T: WriteThrift,
1151{
1152 fn write_thrift_field<W: Write>(
1153 &self,
1154 writer: &mut ThriftCompactOutputProtocol<W>,
1155 field_id: i16,
1156 last_field_id: i16,
1157 ) -> Result<i16> {
1158 writer.write_field_begin(FieldType::List, field_id, last_field_id)?;
1159 self.write_thrift(writer)?;
1160 Ok(field_id)
1161 }
1162}
1163
1164#[cfg(test)]
1165pub(crate) mod tests {
1166 use crate::basic::{TimeUnit, Type};
1167
1168 use super::*;
1169 use std::fmt::Debug;
1170
1171 pub(crate) fn test_roundtrip<T>(val: T)
1172 where
1173 T: for<'a> ReadThrift<'a, ThriftSliceInputProtocol<'a>> + WriteThrift + PartialEq + Debug,
1174 {
1175 let mut buf = Vec::<u8>::new();
1176 {
1177 let mut writer = ThriftCompactOutputProtocol::new(&mut buf);
1178 val.write_thrift(&mut writer).unwrap();
1179 }
1180
1181 let mut prot = ThriftSliceInputProtocol::new(&buf);
1182 let read_val = T::read_thrift(&mut prot).unwrap();
1183 assert_eq!(val, read_val);
1184 }
1185
1186 #[test]
1187 fn test_enum_roundtrip() {
1188 test_roundtrip(Type::BOOLEAN);
1189 test_roundtrip(Type::INT32);
1190 test_roundtrip(Type::INT64);
1191 test_roundtrip(Type::INT96);
1192 test_roundtrip(Type::FLOAT);
1193 test_roundtrip(Type::DOUBLE);
1194 test_roundtrip(Type::BYTE_ARRAY);
1195 test_roundtrip(Type::FIXED_LEN_BYTE_ARRAY);
1196 }
1197
1198 #[test]
1199 fn test_union_all_empty_roundtrip() {
1200 test_roundtrip(TimeUnit::MILLIS);
1201 test_roundtrip(TimeUnit::MICROS);
1202 test_roundtrip(TimeUnit::NANOS);
1203 }
1204
1205 #[test]
1206 fn test_decode_empty_list() {
1207 let data = vec![0u8; 1];
1208 let mut prot = ThriftSliceInputProtocol::new(&data);
1209 let header = prot.read_list_begin().expect("error reading list header");
1210 assert_eq!(header.size, 0);
1211 assert_eq!(header.element_type, ElementType::Byte);
1212 }
1213
1214 #[test]
1218 fn test_read_list_begin_size_above_i32_max_returns_err() {
1219 let mut data: Vec<u8> = vec![0xF8];
1222 data.extend_from_slice(&[0x80, 0x80, 0x80, 0x80, 0x08]);
1223 let mut prot = ThriftSliceInputProtocol::new(&data);
1224 let result = prot.read_list_begin();
1225 assert!(result.is_err(), "expected error, got {result:?}");
1226 }
1227
1228 #[test]
1229 fn test_read_list_wrong_type() {
1230 let data = [0x42, 0x01];
1232 let mut prot = ThriftSliceInputProtocol::new(&data);
1233 let result = read_thrift_vec::<i32, ThriftSliceInputProtocol>(&mut prot);
1235 println!("{result:?}");
1236 assert!(
1237 result
1238 .unwrap_err()
1239 .to_string()
1240 .contains("Expected list element type of I32 but got Bool")
1241 );
1242 }
1243
1244 #[test]
1245 fn test_read_thrift_vec_roundtrip_i32() {
1246 let data = [0x25, 0x00, 0x00];
1248 let mut prot = ThriftSliceInputProtocol::new(&data);
1249 let result = read_thrift_vec::<i32, ThriftSliceInputProtocol>(&mut prot).unwrap();
1250 assert_eq!(result, vec![0, 0]);
1251 }
1252
1253 #[test]
1254 fn test_read_thrift_vec_size_exceeds_remaining_returns_err() {
1255 let data = [0xE5];
1259 let mut prot = ThriftSliceInputProtocol::new(&data);
1260 let result = read_thrift_vec::<i32, ThriftSliceInputProtocol>(&mut prot);
1261 assert!(result.is_err(), "expected error, got {result:?}");
1262 assert!(
1263 result
1264 .unwrap_err()
1265 .to_string()
1266 .contains("Thrift list size 14 exceeds remaining input length 0")
1267 );
1268 }
1269
1270 #[test]
1271 fn test_read_thrift_vec_huge_declared_size_returns_err() {
1272 let data = [0xF5, 0xfc, 0xfc, 0xfc, 0x33, 0x00, 0x00];
1276 let mut prot = ThriftSliceInputProtocol::new(&data);
1277 let result = read_thrift_vec::<i32, ThriftSliceInputProtocol>(&mut prot);
1278 assert!(result.is_err(), "expected error, got {result:?}");
1279 let err = result.unwrap_err().to_string();
1280 assert!(
1281 err.contains("Thrift list size 109002364 exceeds remaining input length 2"),
1282 "{err}"
1283 );
1284 }
1285}