brotli/enc/
interface.rs

1use alloc::{Allocator, SliceWrapper, SliceWrapperMut};
2use core;
3
4use super::histogram;
5pub use super::input_pair::{InputPair, InputReference, InputReferenceMut};
6
7#[derive(Debug, Copy, Clone, Default)]
8pub struct BlockSwitch(pub u8);
9
10/// Commands that can instantiate as a no-op should implement this.
11pub trait Nop<T> {
12    fn nop() -> T;
13}
14
15impl BlockSwitch {
16    #[inline(always)]
17    pub fn new(block_type: u8) -> Self {
18        BlockSwitch(block_type)
19    }
20    #[inline(always)]
21    pub fn block_type(&self) -> u8 {
22        self.0
23    }
24}
25
26#[derive(Debug, Copy, Clone, Default)]
27pub struct LiteralBlockSwitch(pub BlockSwitch, pub u8);
28
29impl LiteralBlockSwitch {
30    pub fn new(block_type: u8, stride: u8) -> Self {
31        LiteralBlockSwitch(BlockSwitch::new(block_type), stride)
32    }
33    #[inline(always)]
34    pub fn block_type(&self) -> u8 {
35        self.0.block_type()
36    }
37    #[inline(always)]
38    pub fn stride(&self) -> u8 {
39        self.1
40    }
41    #[inline(always)]
42    pub fn update_stride(&mut self, new_stride: u8) {
43        self.1 = new_stride;
44    }
45}
46
47pub const LITERAL_PREDICTION_MODE_SIGN: u8 = 3;
48pub const LITERAL_PREDICTION_MODE_UTF8: u8 = 2;
49pub const LITERAL_PREDICTION_MODE_MSB6: u8 = 1;
50pub const LITERAL_PREDICTION_MODE_LSB6: u8 = 0;
51
52#[derive(Default, Copy, Clone, Debug, PartialEq, Eq, Hash)]
53pub struct LiteralPredictionModeNibble(pub u8);
54
55impl LiteralPredictionModeNibble {
56    #[inline(always)]
57    pub fn new(prediction_mode: u8) -> Result<Self, ()> {
58        if prediction_mode < 16 {
59            return Ok(LiteralPredictionModeNibble(prediction_mode));
60        }
61        Err(())
62    }
63    #[inline(always)]
64    pub fn prediction_mode(&self) -> u8 {
65        self.0
66    }
67    #[inline(always)]
68    pub fn signed() -> Self {
69        LiteralPredictionModeNibble(LITERAL_PREDICTION_MODE_SIGN)
70    }
71    #[inline(always)]
72    pub fn utf8() -> Self {
73        LiteralPredictionModeNibble(LITERAL_PREDICTION_MODE_UTF8)
74    }
75    #[inline(always)]
76    pub fn msb6() -> Self {
77        LiteralPredictionModeNibble(LITERAL_PREDICTION_MODE_MSB6)
78    }
79    #[inline(always)]
80    pub fn lsb6() -> Self {
81        LiteralPredictionModeNibble(LITERAL_PREDICTION_MODE_LSB6)
82    }
83    #[inline(always)]
84    pub fn to_context_enum(&self) -> Result<histogram::ContextType, ()> {
85        match self.0 {
86            LITERAL_PREDICTION_MODE_LSB6 => Ok(histogram::ContextType::CONTEXT_LSB6),
87            LITERAL_PREDICTION_MODE_MSB6 => Ok(histogram::ContextType::CONTEXT_MSB6),
88            LITERAL_PREDICTION_MODE_UTF8 => Ok(histogram::ContextType::CONTEXT_UTF8),
89            LITERAL_PREDICTION_MODE_SIGN => Ok(histogram::ContextType::CONTEXT_SIGNED),
90            _ => Err(()),
91        }
92    }
93}
94pub const NUM_SPEED_VALUES: usize = 12;
95pub const NUM_MIXING_VALUES: usize = 16 * 256 + 16 * 256;
96pub const NUM_PREDMODE_SETUP_VALUES: usize = 4;
97pub const RESERVED_OFFSET: usize = 3;
98pub const ADV_CONTEXT_MAP_OFFSET: usize = 2;
99pub const MIXING_MATH_OFFSET: usize = 1;
100pub const PREDMODE_OFFSET: usize = 0;
101pub const MIXING_OFFSET: usize = NUM_PREDMODE_SETUP_VALUES + PREDMODE_OFFSET;
102pub const SPEED_OFFSET: usize = MIXING_OFFSET + NUM_MIXING_VALUES;
103pub const DISTANCE_CONTEXT_MAP_OFFSET: usize = SPEED_OFFSET + NUM_SPEED_VALUES;
104pub const MAX_PREDMODE_SPEED_AND_DISTANCE_CONTEXT_MAP_SIZE: usize =
105    DISTANCE_CONTEXT_MAP_OFFSET + 256 * 4;
106pub const MAX_LITERAL_CONTEXT_MAP_SIZE: usize = 256 * 64;
107pub const MAX_ADV_LITERAL_CONTEXT_MAP_SIZE: usize = 256 * 64 * 2;
108#[derive(Debug)]
109pub struct PredictionModeContextMap<SliceType: SliceWrapper<u8>> {
110    pub literal_context_map: SliceType,
111    pub predmode_speed_and_distance_context_map: SliceType,
112}
113impl<SliceType: SliceWrapper<u8> + SliceWrapperMut<u8>> PredictionModeContextMap<SliceType> {
114    #[inline]
115    pub fn distance_context_map_mut(&mut self) -> &mut [u8] {
116        self.predmode_speed_and_distance_context_map
117            .slice_mut()
118            .split_at_mut(DISTANCE_CONTEXT_MAP_OFFSET)
119            .1
120    }
121    #[inline]
122    pub fn set_stride_context_speed(&mut self, speed_max: [(u16, u16); 2]) {
123        let cm_slice = self.predmode_speed_and_distance_context_map.slice_mut();
124        for high in 0..2 {
125            cm_slice[Self::stride_context_speed_offset() + high] =
126                Self::u16_to_f8(speed_max[high].0);
127            cm_slice[Self::stride_context_speed_max_offset() + high] =
128                Self::u16_to_f8(speed_max[high].1);
129        }
130    }
131    #[inline]
132    pub fn set_context_map_speed(&mut self, speed_max: [(u16, u16); 2]) {
133        let cm_slice = self.predmode_speed_and_distance_context_map.slice_mut();
134        for high in 0..2 {
135            cm_slice[Self::context_map_speed_offset() + high] = Self::u16_to_f8(speed_max[high].0);
136            cm_slice[Self::context_map_speed_max_offset() + high] =
137                Self::u16_to_f8(speed_max[high].1);
138        }
139    }
140    pub fn set_mixing_math(&mut self, math_enum: u8) {
141        let cm_slice = self.predmode_speed_and_distance_context_map.slice_mut();
142        cm_slice[MIXING_MATH_OFFSET] = math_enum;
143    }
144    pub fn set_adv_context_map(&mut self, is_adv: u8) {
145        let cm_slice = self.predmode_speed_and_distance_context_map.slice_mut();
146        cm_slice[ADV_CONTEXT_MAP_OFFSET] = is_adv;
147    }
148    #[inline]
149    pub fn set_mixing_values(&mut self, mixing_mask: &[u8; NUM_MIXING_VALUES]) {
150        let cm_slice = self.predmode_speed_and_distance_context_map.slice_mut();
151        cm_slice[MIXING_OFFSET..(MIXING_OFFSET + NUM_MIXING_VALUES)]
152            .clone_from_slice(&mixing_mask[..]);
153    }
154    #[inline]
155    pub fn get_mixing_values_mut(&mut self) -> &mut [u8] {
156        let cm_slice = self.predmode_speed_and_distance_context_map.slice_mut();
157        &mut cm_slice[MIXING_OFFSET..(MIXING_OFFSET + NUM_MIXING_VALUES)]
158    }
159    #[inline]
160    pub fn set_combined_stride_context_speed(&mut self, speed_max: [(u16, u16); 2]) {
161        let cm_slice = self.predmode_speed_and_distance_context_map.slice_mut();
162        for high in 0..2 {
163            cm_slice[Self::combined_stride_context_speed_offset() + high] =
164                Self::u16_to_f8(speed_max[high].0);
165            cm_slice[Self::combined_stride_context_speed_max_offset() + high] =
166                Self::u16_to_f8(speed_max[high].1);
167        }
168    }
169    pub fn set_literal_prediction_mode(&mut self, val: LiteralPredictionModeNibble) {
170        let cm_slice = self.predmode_speed_and_distance_context_map.slice_mut();
171        cm_slice[PREDMODE_OFFSET] = val.0;
172    }
173}
174impl<SliceType: SliceWrapper<u8>> PredictionModeContextMap<SliceType> {
175    #[inline]
176    pub fn from_mut<Other: SliceWrapper<u8>>(
177        other: PredictionModeContextMap<Other>,
178    ) -> PredictionModeContextMap<SliceType>
179    where
180        SliceType: From<Other>,
181    {
182        PredictionModeContextMap::<SliceType> {
183            literal_context_map: SliceType::from(other.literal_context_map),
184            predmode_speed_and_distance_context_map: SliceType::from(
185                other.predmode_speed_and_distance_context_map,
186            ),
187        }
188    }
189    #[inline]
190    pub fn get_mixing_values(&self) -> &[u8] {
191        let cm_slice = self.predmode_speed_and_distance_context_map.slice();
192        &cm_slice[MIXING_OFFSET..(MIXING_OFFSET + NUM_MIXING_VALUES)]
193    }
194    #[inline]
195    pub fn get_mixing_math(&self) -> u8 {
196        let cm_slice = self.predmode_speed_and_distance_context_map.slice();
197        if cm_slice.len() <= MIXING_MATH_OFFSET {
198            return 1;
199        }
200        cm_slice[MIXING_MATH_OFFSET]
201    }
202    #[inline]
203    pub fn get_is_adv_context_map(&self) -> u8 {
204        let cm_slice = self.predmode_speed_and_distance_context_map.slice();
205        if cm_slice.len() <= ADV_CONTEXT_MAP_OFFSET {
206            return 0;
207        }
208        cm_slice[ADV_CONTEXT_MAP_OFFSET]
209    }
210    #[inline]
211    pub fn has_context_speeds(&self) -> bool {
212        self.predmode_speed_and_distance_context_map.slice().len() >= DISTANCE_CONTEXT_MAP_OFFSET
213    }
214    #[inline]
215    pub fn size_of_combined_array(distance_context_map_size: usize) -> usize {
216        distance_context_map_size + DISTANCE_CONTEXT_MAP_OFFSET
217    }
218    #[inline]
219    pub fn context_speeds_standard_len(&self) -> usize {
220        NUM_SPEED_VALUES
221    }
222    #[inline]
223    pub fn context_speeds_f8(&self) -> &[u8] {
224        &self.predmode_speed_and_distance_context_map.slice()
225            [SPEED_OFFSET..DISTANCE_CONTEXT_MAP_OFFSET]
226    }
227    #[inline]
228    pub fn distance_context_map(&self) -> &[u8] {
229        self.predmode_speed_and_distance_context_map
230            .slice()
231            .split_at(DISTANCE_CONTEXT_MAP_OFFSET)
232            .1
233    }
234    #[inline]
235    pub fn f8_to_u16(data: u8) -> u16 {
236        self::u8_to_speed(data)
237    }
238    #[inline]
239    pub fn u16_to_f8(data: u16) -> u8 {
240        self::speed_to_u8(data)
241    }
242    #[inline]
243    pub fn stride_context_speed_offset() -> usize {
244        SPEED_OFFSET
245    }
246    #[inline]
247    pub fn stride_context_speed_max_offset() -> usize {
248        SPEED_OFFSET + 2
249    }
250    #[inline]
251    pub fn context_map_speed_offset() -> usize {
252        SPEED_OFFSET + 4
253    }
254    #[inline]
255    pub fn context_map_speed_max_offset() -> usize {
256        SPEED_OFFSET + 6
257    }
258    #[inline]
259    pub fn combined_stride_context_speed_offset() -> usize {
260        SPEED_OFFSET + 8
261    }
262    #[inline]
263    pub fn combined_stride_context_speed_max_offset() -> usize {
264        SPEED_OFFSET + 10
265    }
266    #[inline]
267    pub fn literal_prediction_mode(&self) -> LiteralPredictionModeNibble {
268        let cm_slice = self.predmode_speed_and_distance_context_map.slice();
269        if PREDMODE_OFFSET < cm_slice.len() {
270            LiteralPredictionModeNibble(cm_slice[PREDMODE_OFFSET])
271        } else {
272            LiteralPredictionModeNibble::default()
273        }
274    }
275    pub fn stride_context_speed(&self) -> [(u16, u16); 2] {
276        let v = self.stride_context_speed_f8();
277        [
278            (self::u8_to_speed(v[0].0), self::u8_to_speed(v[0].1)),
279            (self::u8_to_speed(v[1].0), self::u8_to_speed(v[1].1)),
280        ]
281    }
282    pub fn context_map_speed(&self) -> [(u16, u16); 2] {
283        let v = self.context_map_speed_f8();
284        [
285            (self::u8_to_speed(v[0].0), self::u8_to_speed(v[0].1)),
286            (self::u8_to_speed(v[1].0), self::u8_to_speed(v[1].1)),
287        ]
288    }
289    pub fn combined_stride_context_speed(&self) -> [(u16, u16); 2] {
290        let v = self.combined_stride_context_speed_f8();
291        [
292            (self::u8_to_speed(v[0].0), self::u8_to_speed(v[0].1)),
293            (self::u8_to_speed(v[1].0), self::u8_to_speed(v[1].1)),
294        ]
295    }
296    #[inline]
297    pub fn stride_context_speed_f8(&self) -> [(u8, u8); 2] {
298        let cm_slice = self.predmode_speed_and_distance_context_map.slice();
299        let low_speed = cm_slice[Self::stride_context_speed_offset()];
300        let high_speed = cm_slice[Self::stride_context_speed_offset() + 1];
301        let low_max = cm_slice[Self::stride_context_speed_max_offset()];
302        let high_max = cm_slice[Self::stride_context_speed_max_offset() + 1];
303        [(low_speed, low_max), (high_speed, high_max)]
304    }
305    #[inline]
306    pub fn combined_stride_context_speed_f8(&self) -> [(u8, u8); 2] {
307        let cm_slice = self.predmode_speed_and_distance_context_map.slice();
308        let low_speed = cm_slice[Self::combined_stride_context_speed_offset()];
309        let high_speed = cm_slice[Self::combined_stride_context_speed_offset() + 1];
310        let low_max = cm_slice[Self::combined_stride_context_speed_max_offset()];
311        let high_max = cm_slice[Self::combined_stride_context_speed_max_offset() + 1];
312        [(low_speed, low_max), (high_speed, high_max)]
313    }
314    #[inline]
315    pub fn context_map_speed_f8(&self) -> [(u8, u8); 2] {
316        let cm_slice = self.predmode_speed_and_distance_context_map.slice();
317        let low_speed = cm_slice[Self::context_map_speed_offset()];
318        let high_speed = cm_slice[Self::context_map_speed_offset() + 1];
319        let low_max = cm_slice[Self::context_map_speed_max_offset()];
320        let high_max = cm_slice[Self::context_map_speed_max_offset() + 1];
321        [(low_speed, low_max), (high_speed, high_max)]
322    }
323}
324
325impl<SliceType: SliceWrapper<u8> + Clone> Clone for PredictionModeContextMap<SliceType> {
326    #[inline(always)]
327    fn clone(&self) -> Self {
328        PredictionModeContextMap::<SliceType> {
329            literal_context_map: self.literal_context_map.clone(),
330            predmode_speed_and_distance_context_map: self
331                .predmode_speed_and_distance_context_map
332                .clone(),
333        }
334    }
335}
336impl<SliceType: SliceWrapper<u8> + Clone + Copy> Copy for PredictionModeContextMap<SliceType> {}
337
338#[derive(Debug, Clone, Copy)]
339pub struct CopyCommand {
340    pub distance: u32,
341    pub num_bytes: u32,
342}
343
344impl Nop<CopyCommand> for CopyCommand {
345    #[inline(always)]
346    fn nop() -> Self {
347        CopyCommand {
348            distance: 1,
349            num_bytes: 0,
350        }
351    }
352}
353
354#[derive(Debug, Clone, Copy)]
355pub struct DictCommand {
356    pub word_size: u8,
357    pub transform: u8,
358    pub final_size: u8,
359    pub empty: u8,
360    pub word_id: u32,
361}
362
363impl Nop<DictCommand> for DictCommand {
364    #[inline(always)]
365    fn nop() -> Self {
366        DictCommand {
367            word_size: 0,
368            transform: 0,
369            final_size: 0,
370            empty: 1,
371            word_id: 0,
372        }
373    }
374}
375
376#[derive(Debug)]
377#[cfg(not(feature = "external-literal-probability"))]
378pub struct FeatureFlagSliceType<SliceType: SliceWrapper<u8>>(core::marker::PhantomData<SliceType>);
379
380#[cfg(not(feature = "external-literal-probability"))]
381impl<SliceType: SliceWrapper<u8>> SliceWrapper<u8> for FeatureFlagSliceType<SliceType> {
382    fn slice(&self) -> &[u8] {
383        &[]
384    }
385}
386
387#[cfg(not(feature = "external-literal-probability"))]
388impl<SliceType: SliceWrapper<u8> + Default> Default for FeatureFlagSliceType<SliceType> {
389    fn default() -> Self {
390        FeatureFlagSliceType::<SliceType>(core::marker::PhantomData::<SliceType>)
391    }
392}
393
394#[derive(Debug)]
395#[cfg(feature = "external-literal-probability")]
396pub struct FeatureFlagSliceType<SliceType: SliceWrapper<u8>>(pub SliceType);
397
398#[cfg(feature = "external-literal-probability")]
399impl<SliceType: SliceWrapper<u8>> SliceWrapper<u8> for FeatureFlagSliceType<SliceType> {
400    #[inline(always)]
401    fn slice(&self) -> &[u8] {
402        self.0.slice()
403    }
404}
405
406#[cfg(feature = "external-literal-probability")]
407impl<SliceType: SliceWrapper<u8> + Default> Default for FeatureFlagSliceType<SliceType> {
408    #[inline(always)]
409    fn default() -> Self {
410        FeatureFlagSliceType::<SliceType>(SliceType::default())
411    }
412}
413
414impl<SliceType: SliceWrapper<u8> + Clone> Clone for FeatureFlagSliceType<SliceType> {
415    #[inline(always)]
416    fn clone(&self) -> Self {
417        FeatureFlagSliceType::<SliceType>(self.0)
418    }
419}
420impl<SliceType: SliceWrapper<u8> + Clone + Copy> Copy for FeatureFlagSliceType<SliceType> {}
421
422#[derive(Debug)]
423pub struct LiteralCommand<SliceType: SliceWrapper<u8>> {
424    pub data: SliceType,
425    pub prob: FeatureFlagSliceType<SliceType>,
426    pub high_entropy: bool, // this block of bytes is high entropy with a few patterns never seen again; adapt slower
427}
428impl<SliceType: SliceWrapper<u8>> SliceWrapper<u8> for LiteralCommand<SliceType> {
429    #[inline(always)]
430    fn slice(&self) -> &[u8] {
431        self.data.slice()
432    }
433}
434impl<SliceType: SliceWrapper<u8> + SliceWrapperMut<u8>> SliceWrapperMut<u8>
435    for LiteralCommand<SliceType>
436{
437    #[inline(always)]
438    fn slice_mut(&mut self) -> &mut [u8] {
439        self.data.slice_mut()
440    }
441}
442
443impl<SliceType: SliceWrapper<u8> + Default> Nop<LiteralCommand<SliceType>>
444    for LiteralCommand<SliceType>
445{
446    #[inline(always)]
447    fn nop() -> Self {
448        LiteralCommand {
449            data: SliceType::default(),
450            prob: FeatureFlagSliceType::<SliceType>::default(),
451            high_entropy: false,
452        }
453    }
454}
455impl<SliceType: SliceWrapper<u8> + Clone> Clone for LiteralCommand<SliceType> {
456    #[inline(always)]
457    fn clone(&self) -> LiteralCommand<SliceType> {
458        LiteralCommand::<SliceType> {
459            data: self.data.clone(),
460            prob: self.prob.clone(),
461            high_entropy: self.high_entropy,
462        }
463    }
464}
465impl<SliceType: SliceWrapper<u8> + Clone + Copy> Copy for LiteralCommand<SliceType> {}
466
467#[derive(Debug)]
468pub enum Command<SliceType: SliceWrapper<u8>> {
469    Copy(CopyCommand),
470    Dict(DictCommand),
471    Literal(LiteralCommand<SliceType>),
472    BlockSwitchCommand(BlockSwitch),
473    BlockSwitchLiteral(LiteralBlockSwitch),
474    BlockSwitchDistance(BlockSwitch),
475    PredictionMode(PredictionModeContextMap<SliceType>),
476}
477impl<SliceType: SliceWrapper<u8> + Default> Command<SliceType> {
478    #[inline]
479    pub fn free_array<F>(&mut self, apply_func: &mut F)
480    where
481        F: FnMut(SliceType),
482    {
483        match self {
484            Command::Literal(ref mut lit) => apply_func(core::mem::take(&mut lit.data)),
485            Command::PredictionMode(ref mut pm) => {
486                apply_func(core::mem::take(&mut pm.literal_context_map));
487                apply_func(core::mem::take(
488                    &mut pm.predmode_speed_and_distance_context_map,
489                ));
490            }
491            _ => {}
492        }
493    }
494}
495
496impl<SliceType: SliceWrapper<u8>> Default for Command<SliceType> {
497    #[inline(always)]
498    fn default() -> Self {
499        Command::<SliceType>::nop()
500    }
501}
502
503impl<SliceType: SliceWrapper<u8>> Nop<Command<SliceType>> for Command<SliceType> {
504    #[inline(always)]
505    fn nop() -> Command<SliceType> {
506        Command::Copy(CopyCommand::nop())
507    }
508}
509
510impl<SliceType: SliceWrapper<u8> + Clone> Clone for Command<SliceType> {
511    #[inline]
512    fn clone(&self) -> Command<SliceType> {
513        match self {
514            Command::Copy(copy) => Command::Copy(*copy),
515            Command::Dict(dict) => Command::Dict(*dict),
516            Command::Literal(literal) => Command::Literal(literal.clone()),
517            Command::BlockSwitchCommand(switch) => Command::BlockSwitchCommand(*switch),
518            Command::BlockSwitchLiteral(switch) => Command::BlockSwitchLiteral(*switch),
519            Command::BlockSwitchDistance(switch) => Command::BlockSwitchDistance(*switch),
520            Command::PredictionMode(pm) => Command::PredictionMode(pm.clone()),
521        }
522    }
523}
524
525impl<SliceType: SliceWrapper<u8> + Clone + Copy> Copy for Command<SliceType> {}
526
527#[inline(always)]
528pub fn free_cmd_inline<SliceTypeAllocator: Allocator<u8>>(
529    xself: &mut Command<SliceTypeAllocator::AllocatedMemory>,
530    m8: &mut SliceTypeAllocator,
531) {
532    match *xself {
533        Command::Literal(ref mut lit) => m8.free_cell(core::mem::take(&mut lit.data)),
534        Command::PredictionMode(ref mut pm) => {
535            m8.free_cell(core::mem::take(&mut pm.literal_context_map));
536            m8.free_cell(core::mem::take(
537                &mut pm.predmode_speed_and_distance_context_map,
538            ));
539        }
540        Command::Dict(_)
541        | Command::Copy(_)
542        | Command::BlockSwitchCommand(_)
543        | Command::BlockSwitchLiteral(_)
544        | Command::BlockSwitchDistance(_) => {}
545    }
546}
547
548#[inline(never)]
549pub fn free_cmd<SliceTypeAllocator: Allocator<u8>>(
550    xself: &mut Command<SliceTypeAllocator::AllocatedMemory>,
551    m8: &mut SliceTypeAllocator,
552) {
553    free_cmd_inline(xself, m8)
554}
555
556#[derive(Clone, Copy, Default, Debug)]
557pub struct SliceOffset(pub usize, pub u32);
558impl SliceWrapper<u8> for SliceOffset {
559    fn slice(&self) -> &[u8] {
560        // not perfect--shouldn't be calling this without thawing the wrapper
561        &[]
562    }
563}
564
565pub trait Freezable {
566    fn freeze(&self) -> SliceOffset;
567}
568
569pub trait Unfreezable {
570    fn thaw<'a>(&self, data: &'a [u8]) -> InputReference<'a>;
571    fn thaw_mut<'a>(&self, data: &'a mut [u8]) -> InputReferenceMut<'a>;
572    fn thaw_pair<'a>(&self, pair: &InputPair<'a>) -> Result<InputReference<'a>, ()>;
573}
574
575impl<'a> From<InputReference<'a>> for SliceOffset {
576    fn from(f: InputReference<'a>) -> Self {
577        debug_assert!(f.data.len() <= 0xffff_ffff);
578        SliceOffset(f.orig_offset, f.data.len() as u32)
579    }
580}
581impl Unfreezable for SliceOffset {
582    fn thaw<'a>(&self, data: &'a [u8]) -> InputReference<'a> {
583        InputReference {
584            data: data.split_at(self.0).1.split_at(self.1 as usize).0,
585            orig_offset: self.0,
586        }
587    }
588    fn thaw_mut<'a>(&self, data: &'a mut [u8]) -> InputReferenceMut<'a> {
589        InputReferenceMut {
590            data: data.split_at_mut(self.0).1.split_at_mut(self.1 as usize).0,
591            orig_offset: self.0,
592        }
593    }
594    fn thaw_pair<'a>(&self, pair: &InputPair<'a>) -> Result<InputReference<'a>, ()> {
595        if self.0 >= pair.1.orig_offset {
596            return Ok(InputReference {
597                data: pair
598                    .1
599                    .data
600                    .split_at(self.0 - pair.1.orig_offset)
601                    .1
602                    .split_at(self.1 as usize)
603                    .0,
604                orig_offset: self.0,
605            });
606        }
607        let offset = self.0 - pair.0.orig_offset;
608        if offset + self.1 as usize <= pair.0.data.len() {
609            // overlap
610            Ok(InputReference {
611                data: pair.0.data.split_at(offset).1.split_at(self.1 as usize).0,
612                orig_offset: self.0,
613            })
614        } else {
615            Err(())
616        }
617    }
618}
619impl SliceOffset {
620    pub fn offset(&self) -> usize {
621        self.0
622    }
623    pub fn len(&self) -> usize {
624        self.1 as usize
625    }
626    pub fn len32(&self) -> u32 {
627        self.1
628    }
629}
630
631pub type StaticCommand = Command<SliceOffset>;
632
633pub trait CommandProcessor<'a> {
634    fn push(&mut self, val: Command<InputReference<'a>>);
635    fn push_literals(&mut self, data: &InputPair<'a>) {
636        if data.0.len() != 0 {
637            self.push(Command::Literal(LiteralCommand {
638                data: data.0,
639                prob: FeatureFlagSliceType::<InputReference>::default(),
640                high_entropy: false,
641            }));
642        }
643        if data.1.len() != 0 {
644            self.push(Command::Literal(LiteralCommand {
645                data: data.1,
646                prob: FeatureFlagSliceType::<InputReference>::default(),
647                high_entropy: false,
648            }));
649        }
650    }
651    fn push_rand_literals(&mut self, data: &InputPair<'a>) {
652        if data.0.len() != 0 {
653            self.push(Command::Literal(LiteralCommand {
654                data: data.0,
655                prob: FeatureFlagSliceType::<InputReference>::default(),
656                high_entropy: true,
657            }));
658        }
659        if data.1.len() != 0 {
660            self.push(Command::Literal(LiteralCommand {
661                data: data.1,
662                prob: FeatureFlagSliceType::<InputReference>::default(),
663                high_entropy: true,
664            }));
665        }
666    }
667    fn push_block_switch_literal(&mut self, block_type: u8) {
668        self.push(Command::BlockSwitchLiteral(LiteralBlockSwitch::new(
669            block_type, 0,
670        )))
671    }
672}
673
674impl<SliceType: Unfreezable + SliceWrapper<u8>> Command<SliceType> {
675    pub fn thaw_pair<'a>(&self, data: &InputPair<'a>) -> Command<InputReference<'a>> {
676        match self {
677            Command::Literal(ref lit) => Command::Literal(LiteralCommand {
678                data: lit.data.thaw_pair(data).unwrap(),
679                prob: FeatureFlagSliceType::default(),
680                high_entropy: lit.high_entropy,
681            }),
682            Command::PredictionMode(ref pm) => Command::PredictionMode(PredictionModeContextMap {
683                literal_context_map: pm.literal_context_map.thaw_pair(data).unwrap(),
684                predmode_speed_and_distance_context_map: pm
685                    .predmode_speed_and_distance_context_map
686                    .thaw_pair(data)
687                    .unwrap(),
688            }),
689            Command::Dict(ref d) => Command::Dict(*d),
690            Command::Copy(ref c) => Command::Copy(*c),
691            Command::BlockSwitchCommand(ref c) => Command::BlockSwitchCommand(*c),
692            Command::BlockSwitchLiteral(ref c) => Command::BlockSwitchLiteral(*c),
693            Command::BlockSwitchDistance(ref c) => Command::BlockSwitchDistance(*c),
694        }
695    }
696
697    pub fn thaw<'a>(&self, data: &'a [u8]) -> Command<InputReference<'a>> {
698        match self {
699            Command::Literal(ref lit) => Command::Literal(LiteralCommand {
700                data: lit.data.thaw(data),
701                prob: FeatureFlagSliceType::default(),
702                high_entropy: lit.high_entropy,
703            }),
704            Command::PredictionMode(ref pm) => Command::PredictionMode(PredictionModeContextMap {
705                literal_context_map: pm.literal_context_map.thaw(data),
706                predmode_speed_and_distance_context_map: pm
707                    .predmode_speed_and_distance_context_map
708                    .thaw(data),
709            }),
710            Command::Dict(ref d) => Command::Dict(*d),
711            Command::Copy(ref c) => Command::Copy(*c),
712            Command::BlockSwitchCommand(ref c) => Command::BlockSwitchCommand(*c),
713            Command::BlockSwitchLiteral(ref c) => Command::BlockSwitchLiteral(*c),
714            Command::BlockSwitchDistance(ref c) => Command::BlockSwitchDistance(*c),
715        }
716    }
717}
718
719impl<SliceType: SliceWrapper<u8> + Freezable> Command<SliceType> {
720    pub fn freeze(&self) -> Command<SliceOffset> {
721        match self {
722            Command::Literal(ref lit) => Command::Literal(LiteralCommand {
723                data: lit.data.freeze(),
724                prob: FeatureFlagSliceType::default(),
725                high_entropy: lit.high_entropy,
726            }),
727            Command::PredictionMode(ref pm) => Command::PredictionMode(PredictionModeContextMap {
728                literal_context_map: pm.literal_context_map.freeze(),
729                predmode_speed_and_distance_context_map: pm
730                    .predmode_speed_and_distance_context_map
731                    .freeze(),
732            }),
733            Command::Dict(ref d) => Command::Dict(*d),
734            Command::Copy(ref c) => Command::Copy(*c),
735            Command::BlockSwitchCommand(ref c) => Command::BlockSwitchCommand(*c),
736            Command::BlockSwitchLiteral(ref c) => Command::BlockSwitchLiteral(*c),
737            Command::BlockSwitchDistance(ref c) => Command::BlockSwitchDistance(*c),
738        }
739    }
740}
741
742#[inline(always)]
743pub fn speed_to_u8(data: u16) -> u8 {
744    let length = 16 - data.leading_zeros() as u8;
745    let mantissa = if data != 0 {
746        let rem = data - (1 << (length - 1));
747        (rem << 3) >> (length - 1)
748    } else {
749        0
750    };
751    (length << 3) | mantissa as u8
752}
753
754#[inline(always)]
755pub fn u8_to_speed(data: u8) -> u16 {
756    if data < 8 {
757        0
758    } else {
759        let log_val = (data >> 3) - 1;
760        let rem = (u16::from(data) & 0x07) << log_val;
761        (1u16 << log_val) | (rem >> 3)
762    }
763}
764
765#[cfg(test)]
766mod test {
767    use super::{speed_to_u8, u8_to_speed};
768    fn tst_u8_to_speed(data: u16) {
769        assert_eq!(u8_to_speed(speed_to_u8(data)), data);
770    }
771    #[test]
772    fn test_u8_to_speed() {
773        tst_u8_to_speed(0);
774        tst_u8_to_speed(1);
775        tst_u8_to_speed(2);
776        tst_u8_to_speed(3);
777        tst_u8_to_speed(4);
778        tst_u8_to_speed(5);
779        tst_u8_to_speed(6);
780        tst_u8_to_speed(7);
781        tst_u8_to_speed(8);
782        tst_u8_to_speed(10);
783        tst_u8_to_speed(12);
784        tst_u8_to_speed(16);
785        tst_u8_to_speed(24);
786        tst_u8_to_speed(32);
787        tst_u8_to_speed(48);
788        tst_u8_to_speed(64);
789        tst_u8_to_speed(96);
790        tst_u8_to_speed(768);
791        tst_u8_to_speed(1280);
792        tst_u8_to_speed(1536);
793        tst_u8_to_speed(1664);
794    }
795}