hdrhistogram/serialization/
v2_serializer.rs1use super::{Serializer, V2_COOKIE, V2_HEADER_SIZE};
2use crate::{Counter, Histogram};
3use byteorder::{BigEndian, WriteBytesExt};
4use std::io::{self, Write};
5use std::{error, fmt};
6
7#[derive(Debug)]
9pub enum V2SerializeError {
10 CountNotSerializable,
13 UsizeTypeTooSmall,
16 IoError(io::Error),
18}
19
20impl std::convert::From<std::io::Error> for V2SerializeError {
21 fn from(e: std::io::Error) -> Self {
22 V2SerializeError::IoError(e)
23 }
24}
25
26impl fmt::Display for V2SerializeError {
27 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
28 match self {
29 V2SerializeError::CountNotSerializable => write!(
30 f,
31 "A count above i64::max_value() cannot be zig-zag encoded"
32 ),
33 V2SerializeError::UsizeTypeTooSmall => {
34 write!(f, "Internal calculations cannot be represented in `usize`")
35 }
36 V2SerializeError::IoError(e) => write!(f, "An i/o operation failed: {}", e),
37 }
38 }
39}
40
41impl error::Error for V2SerializeError {
42 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
43 match self {
44 V2SerializeError::IoError(e) => Some(e),
45 _ => None,
46 }
47 }
48}
49
50pub struct V2Serializer {
52 buf: Vec<u8>,
53}
54
55impl Default for V2Serializer {
56 fn default() -> Self {
57 Self::new()
58 }
59}
60impl V2Serializer {
61 pub fn new() -> V2Serializer {
63 V2Serializer { buf: Vec::new() }
64 }
65}
66
67impl Serializer for V2Serializer {
68 type SerializeError = V2SerializeError;
69
70 fn serialize<T: Counter, W: Write>(
71 &mut self,
72 h: &Histogram<T>,
73 writer: &mut W,
74 ) -> Result<usize, V2SerializeError> {
75 self.buf.clear();
78 let max_size = max_encoded_size(h).ok_or(V2SerializeError::UsizeTypeTooSmall)?;
79 self.buf.reserve(max_size);
80
81 self.buf.write_u32::<BigEndian>(V2_COOKIE)?;
82 self.buf.write_u32::<BigEndian>(0)?;
84 self.buf.write_u32::<BigEndian>(0)?;
86 self.buf
87 .write_u32::<BigEndian>(u32::from(h.significant_value_digits))?;
88 self.buf
89 .write_u64::<BigEndian>(h.lowest_discernible_value)?;
90 self.buf.write_u64::<BigEndian>(h.highest_trackable_value)?;
91 self.buf.write_f64::<BigEndian>(1.0)?;
93
94 debug_assert_eq!(V2_HEADER_SIZE, self.buf.len());
95
96 unsafe {
97 self.buf.set_len(max_size);
100 }
101
102 let counts_len = encode_counts(h, &mut self.buf[V2_HEADER_SIZE..])?;
103 let total_len = V2_HEADER_SIZE + counts_len;
105
106 (&mut self.buf[4..8]).write_u32::<BigEndian>(counts_len as u32)?;
109
110 writer
111 .write_all(&self.buf[0..(total_len)])
112 .map(|_| total_len)
113 .map_err(V2SerializeError::IoError)
114 }
115}
116
117fn max_encoded_size<T: Counter>(h: &Histogram<T>) -> Option<usize> {
118 h.index_for(h.max())
119 .and_then(|i| counts_array_max_encoded_size(i + 1))
120 .and_then(|x| x.checked_add(V2_HEADER_SIZE))
121}
122
123pub fn counts_array_max_encoded_size(length: usize) -> Option<usize> {
125 length.checked_mul(9)
130}
131
132pub fn encode_counts<T: Counter>(
136 h: &Histogram<T>,
137 buf: &mut [u8],
138) -> Result<usize, V2SerializeError> {
139 let index_limit = h
140 .index_for(h.max())
141 .expect("Index for max value must exist");
142 let mut index = 0;
143 let mut bytes_written = 0;
144
145 assert!(index_limit <= h.counts.len());
146
147 while index <= index_limit {
148 let count = unsafe { *(h.counts.get_unchecked(index)) };
150 index += 1;
151
152 let mut zero_count = 0;
156 if count == T::zero() {
157 zero_count = 1;
158
159 while (index <= index_limit)
161 && (unsafe { *(h.counts.get_unchecked(index)) } == T::zero())
162 {
163 zero_count += 1;
164 index += 1;
165 }
166 }
167
168 let count_or_zeros: i64 = if zero_count > 1 {
169 -zero_count
172 } else {
173 count
179 .to_i64()
180 .ok_or(V2SerializeError::CountNotSerializable)?
181 };
182
183 let zz = zig_zag_encode(count_or_zeros);
184
185 bytes_written += varint_write(zz, &mut buf[bytes_written..]);
187 }
188
189 Ok(bytes_written)
190}
191
192#[inline]
199pub fn varint_write(input: u64, buf: &mut [u8]) -> usize {
200 if shift_by_7s(input, 1) == 0 {
206 buf[0] = input as u8;
207 return 1;
208 }
209 buf[0] = 0x80 | ((input & 0x7F) as u8);
211 if shift_by_7s(input, 2) == 0 {
212 buf[1] = shift_by_7s(input, 1) as u8;
214 return 2;
215 }
216 buf[1] = nth_7b_chunk_with_high_bit(input, 1);
217 if shift_by_7s(input, 3) == 0 {
218 buf[2] = shift_by_7s(input, 2) as u8;
219 return 3;
220 }
221 buf[2] = nth_7b_chunk_with_high_bit(input, 2);
222 if shift_by_7s(input, 4) == 0 {
223 buf[3] = shift_by_7s(input, 3) as u8;
224 return 4;
225 }
226 buf[3] = nth_7b_chunk_with_high_bit(input, 3);
227 if shift_by_7s(input, 5) == 0 {
228 buf[4] = shift_by_7s(input, 4) as u8;
229 return 5;
230 }
231 buf[4] = nth_7b_chunk_with_high_bit(input, 4);
232 if shift_by_7s(input, 6) == 0 {
233 buf[5] = shift_by_7s(input, 5) as u8;
234 return 6;
235 }
236 buf[5] = nth_7b_chunk_with_high_bit(input, 5);
237 if shift_by_7s(input, 7) == 0 {
238 buf[6] = shift_by_7s(input, 6) as u8;
239 return 7;
240 }
241 buf[6] = nth_7b_chunk_with_high_bit(input, 6);
242 if shift_by_7s(input, 8) == 0 {
243 buf[7] = shift_by_7s(input, 7) as u8;
244 return 8;
245 }
246 buf[7] = nth_7b_chunk_with_high_bit(input, 7);
247 buf[8] = (input >> 56) as u8;
249 9
250}
251
252#[inline]
256fn shift_by_7s(input: u64, n: u8) -> u64 {
257 input >> (7 * n)
258}
259
260#[inline]
265fn nth_7b_chunk_with_high_bit(input: u64, n: u8) -> u8 {
266 (shift_by_7s(input, n) as u8) | 0x80
267}
268
269#[inline]
272pub fn zig_zag_encode(num: i64) -> u64 {
273 ((num << 1) ^ (num >> 63)) as u64
275}