Decode ALP-RD compressed data back to f64 values.
(data: &[u8])
| 121 | |
| 122 | /// Decode ALP-RD compressed data back to f64 values. |
| 123 | pub fn decode(data: &[u8]) -> Result<Vec<f64>, CodecError> { |
| 124 | if data.len() < 7 { |
| 125 | return Err(CodecError::Truncated { |
| 126 | expected: 7, |
| 127 | actual: data.len(), |
| 128 | }); |
| 129 | } |
| 130 | |
| 131 | let count = u32::from_le_bytes([data[0], data[1], data[2], data[3]]) as usize; |
| 132 | let cut = data[4]; |
| 133 | let dict_size = u16::from_le_bytes([data[5], data[6]]) as usize; |
| 134 | |
| 135 | if count == 0 { |
| 136 | return Ok(Vec::new()); |
| 137 | } |
| 138 | |
| 139 | if cut > 64 { |
| 140 | return Err(CodecError::Corrupt { |
| 141 | detail: format!("invalid ALP-RD cut position: {cut}"), |
| 142 | }); |
| 143 | } |
| 144 | |
| 145 | let tail_bytes_per_value = (cut as usize).div_ceil(8); |
| 146 | let tail_mask: u64 = if cut == 0 { 0 } else { (1u64 << cut) - 1 }; |
| 147 | let use_u8_indices = dict_size <= 256; |
| 148 | |
| 149 | // Read dictionary. |
| 150 | let mut pos = 7; |
| 151 | let dict_bytes = dict_size * 8; |
| 152 | if pos + dict_bytes > data.len() { |
| 153 | return Err(CodecError::Truncated { |
| 154 | expected: pos + dict_bytes, |
| 155 | actual: data.len(), |
| 156 | }); |
| 157 | } |
| 158 | let mut dict = Vec::with_capacity(dict_size); |
| 159 | for _ in 0..dict_size { |
| 160 | dict.push(u64::from_le_bytes([ |
| 161 | data[pos], |
| 162 | data[pos + 1], |
| 163 | data[pos + 2], |
| 164 | data[pos + 3], |
| 165 | data[pos + 4], |
| 166 | data[pos + 5], |
| 167 | data[pos + 6], |
| 168 | data[pos + 7], |
| 169 | ])); |
| 170 | pos += 8; |
| 171 | } |
| 172 | |
| 173 | // Read indices. |
| 174 | let index_bytes = count * if use_u8_indices { 1 } else { 2 }; |
| 175 | if pos + index_bytes > data.len() { |
| 176 | return Err(CodecError::Truncated { |
| 177 | expected: pos + index_bytes, |
| 178 | actual: data.len(), |
| 179 | }); |
| 180 | } |