brotli/enc/
interface.rs

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