Like `unpack_bytes` but all values are less than `N` so it can avoid encoding the packing. Bytes returned by this function are guaranteed less than `N`. If `HISTOGRAM` is set to `N` it also returns a histogram of the output bytes. This is because the histogram can be calculated much faster when operating on the packed bytes. If `HISTOGRAM` is set to `0` it only checks variants < `N` and doesn't
(
input: &mut &'a [u8],
length: usize,
out: &mut CowSlice<'a, u8>,
)
| 208 | /// |
| 209 | /// If `HISTOGRAM` is set to `0` it only checks variants < `N` and doesn't calculate a histogram. |
| 210 | pub fn unpack_bytes_less_than<'a, const N: usize, const HISTOGRAM: usize>( |
| 211 | input: &mut &'a [u8], |
| 212 | length: usize, |
| 213 | out: &mut CowSlice<'a, u8>, |
| 214 | ) -> Result<[usize; HISTOGRAM]> { |
| 215 | assert!(HISTOGRAM == N || HISTOGRAM == 0); |
| 216 | |
| 217 | /// Checks that `unpacked` bytes are less than `N`. All of `unpacked` is assumed to be < `FACTOR`. |
| 218 | /// `HISTOGRAM` must be 0. |
| 219 | fn check_less_than<const N: usize, const HISTOGRAM: usize, const FACTOR: usize>( |
| 220 | unpacked: &[u8], |
| 221 | ) -> Result<[usize; HISTOGRAM]> { |
| 222 | assert!(FACTOR >= N); |
| 223 | debug_assert!(unpacked.iter().all(|&v| (v as usize) < FACTOR)); |
| 224 | if FACTOR > N && unpacked.iter().copied().max().unwrap_or(0) as usize >= N { |
| 225 | return invalid_packing(); |
| 226 | } |
| 227 | Ok(std::array::from_fn(|_| unreachable!("HISTOGRAM not 0"))) |
| 228 | } |
| 229 | |
| 230 | /// Returns `Ok(histogram)` if buckets after `OUT` are 0. |
| 231 | fn check_histogram<const IN: usize, const OUT: usize>( |
| 232 | histogram: [usize; IN], |
| 233 | ) -> Result<[usize; OUT]> { |
| 234 | let (histogram, remaining) = histogram.split_at(OUT); |
| 235 | if remaining.iter().copied().sum::<usize>() != 0 { |
| 236 | return invalid_packing(); |
| 237 | } |
| 238 | Ok(*<&[usize; OUT]>::try_from(histogram).unwrap()) |
| 239 | } |
| 240 | |
| 241 | let p = Packing::new(N.saturating_sub(1) as u8); |
| 242 | if p == Packing::_256 { |
| 243 | let bytes = consume_bytes(input, length)?; |
| 244 | out.set_borrowed(bytes); |
| 245 | return if HISTOGRAM == 0 { |
| 246 | check_less_than::<N, HISTOGRAM, 256>(bytes) |
| 247 | } else { |
| 248 | check_histogram(crate::histogram::histogram(bytes)) |
| 249 | }; |
| 250 | } |
| 251 | |
| 252 | /// `FACTOR_POW_DIVISOR == (FACTOR as usize).pow(factor_to_divisor::<FACTOR>() as u32)` but as a constant. |
| 253 | fn unpack_arithmetic_less_than< |
| 254 | const N: usize, |
| 255 | const HISTOGRAM: usize, |
| 256 | const FACTOR: usize, |
| 257 | const FACTOR_POW_DIVISOR: usize, |
| 258 | >( |
| 259 | input: &mut &[u8], |
| 260 | length: usize, |
| 261 | out: &mut Vec<u8>, |
| 262 | ) -> Result<[usize; HISTOGRAM]> { |
| 263 | assert!(HISTOGRAM == N || HISTOGRAM == 0); |
| 264 | assert!(FACTOR >= 2 && FACTOR >= N); |
| 265 | let divisor = factor_to_divisor::<FACTOR>(); |
| 266 | assert_eq!(FACTOR.pow(divisor as u32), FACTOR_POW_DIVISOR); |
| 267 |
nothing calls this directly
no test coverage detected