1 use std::fmt; 2 3 #[cfg(any(test, feature = "quickcheck"))] 4 use quickcheck::{Arbitrary, Gen}; 5 6 use crate::packet; 7 use crate::Packet; 8 use crate::types::CompressionAlgorithm; 9 10 /// Holds a compressed data packet. 11 /// 12 /// A compressed data packet is a container. See [Section 5.6 of RFC 13 /// 4880] for details. 14 /// 15 /// When the parser encounters a compressed data packet with an 16 /// unknown compress algorithm, it returns an `Unknown` packet instead 17 /// of a `CompressedData` packet. 18 /// 19 /// [Section 5.6 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.6 20 // IMPORTANT: If you add fields to this struct, you need to explicitly 21 // IMPORTANT: implement PartialEq, Eq, and Hash. 22 #[derive(Clone, PartialEq, Eq, Hash)] 23 pub struct CompressedData { 24 /// CTB packet header fields. 25 pub(crate) common: packet::Common, 26 /// Algorithm used to compress the payload. 27 algo: CompressionAlgorithm, 28 29 /// This is a container packet. 30 container: packet::Container, 31 } 32 33 impl std::ops::Deref for CompressedData { 34 type Target = packet::Container; deref(&self) -> &Self::Target35 fn deref(&self) -> &Self::Target { 36 &self.container 37 } 38 } 39 40 impl std::ops::DerefMut for CompressedData { deref_mut(&mut self) -> &mut Self::Target41 fn deref_mut(&mut self) -> &mut Self::Target { 42 &mut self.container 43 } 44 } 45 46 impl fmt::Debug for CompressedData { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result47 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 48 f.debug_struct("CompressedData") 49 .field("algo", &self.algo) 50 .field("container", &self.container) 51 .finish() 52 } 53 } 54 55 impl CompressedData { 56 /// Returns a new `CompressedData` packet. new(algo: CompressionAlgorithm) -> Self57 pub fn new(algo: CompressionAlgorithm) -> Self { 58 CompressedData { 59 common: Default::default(), 60 algo, 61 container: Default::default(), 62 } 63 } 64 65 /// Gets the compression algorithm. algo(&self) -> CompressionAlgorithm66 pub fn algo(&self) -> CompressionAlgorithm { 67 self.algo 68 } 69 70 /// Sets the compression algorithm. set_algo(&mut self, algo: CompressionAlgorithm) -> CompressionAlgorithm71 pub fn set_algo(&mut self, algo: CompressionAlgorithm) -> CompressionAlgorithm { 72 ::std::mem::replace(&mut self.algo, algo) 73 } 74 75 /// Adds a new packet to the container. 76 #[cfg(test)] push(mut self, packet: Packet) -> Self77 pub fn push(mut self, packet: Packet) -> Self { 78 self.container.children_mut().unwrap().push(packet); 79 self 80 } 81 82 /// Inserts a new packet to the container at a particular index. 83 /// If `i` is 0, the new packet is insert at the front of the 84 /// container. If `i` is one, it is inserted after the first 85 /// packet, etc. 86 #[cfg(test)] insert(mut self, i: usize, packet: Packet) -> Self87 pub fn insert(mut self, i: usize, packet: Packet) -> Self { 88 self.container.children_mut().unwrap().insert(i, packet); 89 self 90 } 91 } 92 93 impl From<CompressedData> for Packet { from(s: CompressedData) -> Self94 fn from(s: CompressedData) -> Self { 95 Packet::CompressedData(s) 96 } 97 } 98 99 #[cfg(any(test, feature = "quickcheck"))] 100 impl Arbitrary for CompressedData { arbitrary<G: Gen>(g: &mut G) -> Self101 fn arbitrary<G: Gen>(g: &mut G) -> Self { 102 use rand::Rng; 103 use crate::serialize::SerializeInto; 104 loop { 105 let a = CompressionAlgorithm::from(g.gen_range(0, 4)); 106 if a.is_supported() { 107 let mut c = CompressedData::new(a); 108 // We arbitrarily chose to create packets with 109 // processed bodies, so that 110 // Packet::from_bytes(c.to_vec()) will roundtrip them. 111 c.set_body(packet::Body::Processed( 112 Packet::arbitrary(g).to_vec().unwrap() 113 )); 114 return c; 115 } 116 } 117 } 118 } 119