#![allow(non_snake_case)]
pub use crate::decompress::zstd_decompress_block::ZSTD_REP_NUM;
pub const MINMATCH: u32 = 3;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct ZSTD_SequenceLength {
pub litLength: u32,
pub matchLength: u32,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct SeqDef {
pub offBase: u32,
pub litLength: u16,
pub mlBase: u16,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ZSTD_longLengthType_e {
#[default]
ZSTD_llt_none,
ZSTD_llt_literalLength,
ZSTD_llt_matchLength,
}
#[derive(Debug, Clone)]
pub struct SeqStore_t {
pub sequences: Vec<SeqDef>,
pub literals: Vec<u8>,
pub llCode: Vec<u8>,
pub mlCode: Vec<u8>,
pub ofCode: Vec<u8>,
pub maxNbSeq: usize,
pub maxNbLit: usize,
pub longLengthType: ZSTD_longLengthType_e,
pub longLengthPos: u32,
}
impl SeqStore_t {
pub fn with_capacity(maxNbSeq: usize, maxNbLit: usize) -> Self {
Self {
sequences: Vec::with_capacity(maxNbSeq),
literals: Vec::with_capacity(
maxNbLit + crate::common::zstd_internal::WILDCOPY_OVERLENGTH,
),
llCode: Vec::with_capacity(maxNbSeq),
mlCode: Vec::with_capacity(maxNbSeq),
ofCode: Vec::with_capacity(maxNbSeq),
maxNbSeq,
maxNbLit,
longLengthType: ZSTD_longLengthType_e::ZSTD_llt_none,
longLengthPos: 0,
}
}
pub fn reset(&mut self) {
self.sequences.clear();
self.literals.clear();
self.llCode.clear();
self.mlCode.clear();
self.ofCode.clear();
self.longLengthType = ZSTD_longLengthType_e::ZSTD_llt_none;
self.longLengthPos = 0;
}
}
#[inline(always)]
fn extend_literals(dst: &mut Vec<u8>, src: &[u8]) {
let old_len = dst.len();
let new_len = old_len + src.len();
if new_len <= dst.capacity() {
unsafe {
core::ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr().add(old_len), src.len());
dst.set_len(new_len);
}
} else {
dst.extend_from_slice(src);
}
}
#[inline]
pub fn ZSTD_storeLastLiterals(ss: &mut SeqStore_t, anchor: &[u8]) {
extend_literals(&mut ss.literals, anchor);
}
#[inline]
pub fn ZSTD_resetSeqStore(ss: &mut SeqStore_t) {
ss.sequences.clear();
ss.literals.clear();
ss.llCode.clear();
ss.mlCode.clear();
ss.ofCode.clear();
ss.longLengthType = ZSTD_longLengthType_e::ZSTD_llt_none;
}
pub fn ZSTD_deriveSeqStoreChunkInto(
dst: &mut SeqStore_t,
originalSeqStore: &SeqStore_t,
startIdx: usize,
endIdx: usize,
) {
debug_assert!(!core::ptr::eq(dst, originalSeqStore));
debug_assert!(endIdx <= originalSeqStore.sequences.len());
debug_assert!(startIdx <= endIdx);
let prior_lits: usize = originalSeqStore.sequences[..startIdx]
.iter()
.enumerate()
.map(|(i, s)| {
let mut n = s.litLength as usize;
if i as u32 == originalSeqStore.longLengthPos
&& originalSeqStore.longLengthType == ZSTD_longLengthType_e::ZSTD_llt_literalLength
{
n += 0x10000;
}
n
})
.sum();
let chunk_lits: usize = originalSeqStore.sequences[startIdx..endIdx]
.iter()
.enumerate()
.map(|(i, s)| {
let mut n = s.litLength as usize;
let orig_idx = startIdx + i;
if orig_idx as u32 == originalSeqStore.longLengthPos
&& originalSeqStore.longLengthType == ZSTD_longLengthType_e::ZSTD_llt_literalLength
{
n += 0x10000;
}
n
})
.sum();
let is_last_chunk = endIdx == originalSeqStore.sequences.len();
let lit_take = if is_last_chunk {
originalSeqStore.literals.len().saturating_sub(prior_lits)
} else {
chunk_lits
};
let (longLengthType, longLengthPos) = match originalSeqStore.longLengthType {
ZSTD_longLengthType_e::ZSTD_llt_none => (ZSTD_longLengthType_e::ZSTD_llt_none, 0),
_ => {
let p = originalSeqStore.longLengthPos as usize;
if p < startIdx || p > endIdx {
(ZSTD_longLengthType_e::ZSTD_llt_none, 0)
} else {
(originalSeqStore.longLengthType, (p - startIdx) as u32)
}
}
};
dst.sequences.clear();
dst.sequences
.extend_from_slice(&originalSeqStore.sequences[startIdx..endIdx]);
dst.literals.clear();
dst.literals
.extend_from_slice(&originalSeqStore.literals[prior_lits..prior_lits + lit_take]);
dst.llCode.clear();
if originalSeqStore.llCode.len() >= endIdx {
dst.llCode
.extend_from_slice(&originalSeqStore.llCode[startIdx..endIdx]);
}
dst.mlCode.clear();
if originalSeqStore.mlCode.len() >= endIdx {
dst.mlCode
.extend_from_slice(&originalSeqStore.mlCode[startIdx..endIdx]);
}
dst.ofCode.clear();
if originalSeqStore.ofCode.len() >= endIdx {
dst.ofCode
.extend_from_slice(&originalSeqStore.ofCode[startIdx..endIdx]);
}
dst.maxNbSeq = originalSeqStore.maxNbSeq;
dst.maxNbLit = originalSeqStore.maxNbLit;
dst.longLengthType = longLengthType;
dst.longLengthPos = longLengthPos;
}
pub fn ZSTD_deriveSeqStoreChunk(
originalSeqStore: &SeqStore_t,
startIdx: usize,
endIdx: usize,
) -> SeqStore_t {
let mut dst = SeqStore_t {
sequences: Vec::new(),
literals: Vec::new(),
llCode: Vec::new(),
mlCode: Vec::new(),
ofCode: Vec::new(),
maxNbSeq: originalSeqStore.maxNbSeq,
maxNbLit: originalSeqStore.maxNbLit,
longLengthType: ZSTD_longLengthType_e::ZSTD_llt_none,
longLengthPos: 0,
};
ZSTD_deriveSeqStoreChunkInto(&mut dst, originalSeqStore, startIdx, endIdx);
dst
}
pub fn ZSTD_countSeqStoreLiteralsBytes(seqStore: &SeqStore_t) -> usize {
let mut literalsBytes: usize = 0;
for (i, seq) in seqStore.sequences.iter().enumerate() {
literalsBytes += seq.litLength as usize;
if i as u32 == seqStore.longLengthPos
&& seqStore.longLengthType == ZSTD_longLengthType_e::ZSTD_llt_literalLength
{
literalsBytes += 0x10000;
}
}
literalsBytes
}
pub fn ZSTD_countSeqStoreMatchBytes(seqStore: &SeqStore_t) -> usize {
let mut matchBytes: usize = 0;
for (i, seq) in seqStore.sequences.iter().enumerate() {
matchBytes += seq.mlBase as usize + MINMATCH as usize;
if i as u32 == seqStore.longLengthPos
&& seqStore.longLengthType == ZSTD_longLengthType_e::ZSTD_llt_matchLength
{
matchBytes += 0x10000;
}
}
matchBytes
}
pub fn ZSTD_getSequenceLength(seqStore: &SeqStore_t, seqIdx: usize) -> ZSTD_SequenceLength {
let seq = seqStore.sequences[seqIdx];
let mut seqLen = ZSTD_SequenceLength {
litLength: seq.litLength as u32,
matchLength: seq.mlBase as u32 + MINMATCH,
};
if seqStore.longLengthPos == seqIdx as u32 {
match seqStore.longLengthType {
ZSTD_longLengthType_e::ZSTD_llt_literalLength => seqLen.litLength += 0x10000,
ZSTD_longLengthType_e::ZSTD_llt_matchLength => seqLen.matchLength += 0x10000,
ZSTD_longLengthType_e::ZSTD_llt_none => {}
}
}
seqLen
}
#[inline]
pub fn REPCODE_TO_OFFBASE(r: u32) -> u32 {
debug_assert!(r >= 1 && r <= ZSTD_REP_NUM as u32);
r
}
#[inline]
pub fn OFFSET_TO_OFFBASE(offset: u32) -> u32 {
debug_assert!(offset > 0);
offset.wrapping_add(ZSTD_REP_NUM as u32)
}
#[inline]
pub fn OFFBASE_IS_OFFSET(o: u32) -> bool {
o > ZSTD_REP_NUM as u32
}
#[inline]
pub fn OFFBASE_IS_REPCODE(o: u32) -> bool {
1 <= o && o <= ZSTD_REP_NUM as u32
}
#[inline]
pub fn OFFBASE_TO_OFFSET(o: u32) -> u32 {
debug_assert!(OFFBASE_IS_OFFSET(o));
o - ZSTD_REP_NUM as u32
}
#[inline]
pub fn OFFBASE_TO_REPCODE(o: u32) -> u32 {
debug_assert!(OFFBASE_IS_REPCODE(o));
o
}
#[inline(always)]
pub fn ZSTD_storeSeqOnly(
seqStore: &mut SeqStore_t,
litLength: usize,
offBase: u32,
matchLength: usize,
) {
debug_assert!(seqStore.sequences.len() < seqStore.maxNbSeq);
debug_assert!(litLength <= crate::decompress::zstd_decompress_block::ZSTD_BLOCKSIZE_MAX);
debug_assert!(matchLength >= MINMATCH as usize);
debug_assert!(matchLength <= crate::decompress::zstd_decompress_block::ZSTD_BLOCKSIZE_MAX);
if litLength > 0xFFFF {
debug_assert_eq!(
seqStore.longLengthType,
ZSTD_longLengthType_e::ZSTD_llt_none
);
seqStore.longLengthType = ZSTD_longLengthType_e::ZSTD_llt_literalLength;
seqStore.longLengthPos = seqStore.sequences.len() as u32;
}
let mlBase = matchLength - MINMATCH as usize;
if mlBase > 0xFFFF {
debug_assert_eq!(
seqStore.longLengthType,
ZSTD_longLengthType_e::ZSTD_llt_none
);
seqStore.longLengthType = ZSTD_longLengthType_e::ZSTD_llt_matchLength;
seqStore.longLengthPos = seqStore.sequences.len() as u32;
}
seqStore.sequences.push(SeqDef {
offBase,
litLength: litLength as u16,
mlBase: mlBase as u16,
});
}
#[inline(always)]
pub fn ZSTD_storeSeq(
seqStore: &mut SeqStore_t,
litLength: usize,
literals: &[u8],
offBase: u32,
matchLength: usize,
) {
assert!(litLength <= literals.len());
assert!(seqStore.literals.len() + litLength <= seqStore.maxNbLit);
if litLength != 0 {
let cur_len = seqStore.literals.len();
let has_wildcopy_slack = litLength
<= literals
.len()
.saturating_sub(crate::common::zstd_internal::WILDCOPY_OVERLENGTH);
if has_wildcopy_slack {
unsafe {
let dst = seqStore.literals.as_mut_ptr().add(cur_len);
let src = literals.as_ptr();
core::ptr::copy_nonoverlapping(src, dst, 16);
let mut off = 16;
while off < litLength {
core::ptr::copy_nonoverlapping(src.add(off), dst.add(off), 16);
off += 16;
}
seqStore.literals.set_len(cur_len + litLength);
}
} else {
extend_literals(&mut seqStore.literals, &literals[..litLength]);
}
}
ZSTD_storeSeqOnly(seqStore, litLength, offBase, matchLength);
}
#[derive(Debug, Clone, Copy, Default)]
pub struct Repcodes_t {
pub rep: [u32; ZSTD_REP_NUM],
}
pub fn ZSTD_updateRep(rep: &mut [u32; ZSTD_REP_NUM], offBase: u32, ll0: u32) {
if OFFBASE_IS_OFFSET(offBase) {
rep[2] = rep[1];
rep[1] = rep[0];
rep[0] = OFFBASE_TO_OFFSET(offBase);
} else {
let repCode = OFFBASE_TO_REPCODE(offBase) + ll0 - 1;
if repCode > 0 {
let currentOffset = if repCode == ZSTD_REP_NUM as u32 {
rep[0].wrapping_sub(1)
} else {
rep[repCode as usize]
};
if repCode >= 2 {
rep[2] = rep[1];
}
rep[1] = rep[0];
rep[0] = currentOffset;
}
}
}
pub fn ZSTD_resolveRepcodeToRawOffset(rep: &[u32; ZSTD_REP_NUM], offBase: u32, ll0: u32) -> u32 {
debug_assert!(OFFBASE_IS_REPCODE(offBase));
let adjustedRepCode = OFFBASE_TO_REPCODE(offBase) - 1 + ll0;
if adjustedRepCode == ZSTD_REP_NUM as u32 {
debug_assert!(ll0 != 0);
rep[0].wrapping_sub(1)
} else {
rep[adjustedRepCode as usize]
}
}
pub fn ZSTD_validateSeqStore(seqStore: &SeqStore_t, minMatchParam: u32) {
#[cfg(debug_assertions)]
{
let matchLenLowerBound: u32 = if minMatchParam == 3 { 3 } else { 4 };
for idx in 0..seqStore.sequences.len() {
let seqLen = ZSTD_getSequenceLength(seqStore, idx);
debug_assert!(seqLen.matchLength >= matchLenLowerBound);
}
}
#[cfg(not(debug_assertions))]
{
let _ = (seqStore, minMatchParam);
}
}
pub fn ZSTD_seqStore_resolveOffCodes(
dRepcodes: &mut Repcodes_t,
cRepcodes: &mut Repcodes_t,
seqStore: &mut SeqStore_t,
nbSeq: u32,
) {
let longLitLenIdx = if seqStore.longLengthType == ZSTD_longLengthType_e::ZSTD_llt_literalLength
{
seqStore.longLengthPos
} else {
nbSeq
};
for idx in 0..(nbSeq as usize) {
let seq = &mut seqStore.sequences[idx];
let ll0 = (seq.litLength == 0 && idx as u32 != longLitLenIdx) as u32;
let offBase = seq.offBase;
debug_assert!(offBase > 0);
if OFFBASE_IS_REPCODE(offBase) {
let dRaw = ZSTD_resolveRepcodeToRawOffset(&dRepcodes.rep, offBase, ll0);
let cRaw = ZSTD_resolveRepcodeToRawOffset(&cRepcodes.rep, offBase, ll0);
if dRaw != cRaw {
seq.offBase = OFFSET_TO_OFFBASE(cRaw);
}
}
let new_offBase = seq.offBase;
ZSTD_updateRep(&mut dRepcodes.rep, new_offBase, ll0);
ZSTD_updateRep(&mut cRepcodes.rep, offBase, ll0);
}
}
pub fn ZSTD_newRep(rep: &[u32; ZSTD_REP_NUM], offBase: u32, ll0: u32) -> Repcodes_t {
let mut newReps = Repcodes_t { rep: *rep };
ZSTD_updateRep(&mut newReps.rep, offBase, ll0);
newReps
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ZSTD_longLengthType_e_discriminants_match_upstream() {
assert_eq!(ZSTD_longLengthType_e::ZSTD_llt_none as u32, 0);
assert_eq!(ZSTD_longLengthType_e::ZSTD_llt_literalLength as u32, 1);
assert_eq!(ZSTD_longLengthType_e::ZSTD_llt_matchLength as u32, 2);
}
#[test]
fn storeLastLiterals_appends() {
let mut ss = SeqStore_t::with_capacity(16, 128);
ss.literals.extend_from_slice(b"head");
ZSTD_storeLastLiterals(&mut ss, b"tail");
assert_eq!(ss.literals, b"headtail");
}
#[test]
fn resetSeqStore_clears_cursors() {
let mut ss = SeqStore_t::with_capacity(16, 128);
ss.literals.extend_from_slice(b"junk");
ZSTD_storeSeqOnly(&mut ss, 5, OFFSET_TO_OFFBASE(17), 4);
ss.llCode.extend_from_slice(&[1, 2, 3]);
ss.mlCode.extend_from_slice(&[4, 5, 6]);
ss.ofCode.extend_from_slice(&[7, 8, 9]);
ss.longLengthType = ZSTD_longLengthType_e::ZSTD_llt_matchLength;
ZSTD_resetSeqStore(&mut ss);
assert!(ss.sequences.is_empty());
assert!(ss.literals.is_empty());
assert!(ss.llCode.is_empty());
assert!(ss.mlCode.is_empty());
assert!(ss.ofCode.is_empty());
assert_eq!(ss.longLengthType, ZSTD_longLengthType_e::ZSTD_llt_none);
}
#[test]
fn getSequenceLength_adds_minmatch_back() {
let mut ss = SeqStore_t::with_capacity(8, 128);
ZSTD_storeSeqOnly(&mut ss, 5, OFFSET_TO_OFFBASE(17), 10);
let got = ZSTD_getSequenceLength(&ss, 0);
assert_eq!(got.litLength, 5);
assert_eq!(got.matchLength, 10);
}
#[test]
fn getSequenceLength_resolves_long_litLength() {
let mut ss = SeqStore_t::with_capacity(8, 128);
ZSTD_storeSeqOnly(&mut ss, 5, OFFSET_TO_OFFBASE(17), 8);
ss.longLengthType = ZSTD_longLengthType_e::ZSTD_llt_literalLength;
ss.longLengthPos = 0;
let got = ZSTD_getSequenceLength(&ss, 0);
assert_eq!(got.litLength, 65541);
assert_eq!(got.matchLength, 8);
}
#[test]
fn getSequenceLength_resolves_long_matchLength() {
let mut ss = SeqStore_t::with_capacity(8, 128);
ZSTD_storeSeqOnly(&mut ss, 4, OFFSET_TO_OFFBASE(17), 10);
ss.longLengthType = ZSTD_longLengthType_e::ZSTD_llt_matchLength;
ss.longLengthPos = 0;
let got = ZSTD_getSequenceLength(&ss, 0);
assert_eq!(got.litLength, 4);
assert_eq!(got.matchLength, 10 + 0x10000);
}
#[test]
fn getSequenceLength_long_pos_only_applies_to_target_seq() {
let mut ss = SeqStore_t::with_capacity(8, 128);
ZSTD_storeSeqOnly(&mut ss, 3, OFFSET_TO_OFFBASE(17), 8);
ZSTD_storeSeqOnly(&mut ss, 2, OFFSET_TO_OFFBASE(17), 10);
ss.longLengthType = ZSTD_longLengthType_e::ZSTD_llt_literalLength;
ss.longLengthPos = 1; let s0 = ZSTD_getSequenceLength(&ss, 0);
let s1 = ZSTD_getSequenceLength(&ss, 1);
assert_eq!(s0.litLength, 3); assert_eq!(s1.litLength, 2 + 0x10000); }
#[test]
fn deriveSeqStoreChunk_keeps_long_length_at_end_boundary_like_c() {
let mut ss = SeqStore_t::with_capacity(8, 128);
ZSTD_storeSeqOnly(&mut ss, 3, OFFSET_TO_OFFBASE(10), 7);
ZSTD_storeSeqOnly(&mut ss, 4, OFFSET_TO_OFFBASE(11), 8);
ZSTD_storeSeqOnly(&mut ss, 5, OFFSET_TO_OFFBASE(12), 9);
ss.literals.extend_from_slice(&[b'a'; 12]);
ss.longLengthType = ZSTD_longLengthType_e::ZSTD_llt_matchLength;
ss.longLengthPos = 2;
let chunk = ZSTD_deriveSeqStoreChunk(&ss, 0, 2);
assert_eq!(chunk.sequences.len(), 2);
assert_eq!(
chunk.longLengthType,
ZSTD_longLengthType_e::ZSTD_llt_matchLength
);
assert_eq!(chunk.longLengthPos, 2);
}
#[test]
fn deriveSeqStoreChunk_end_boundary_marker_is_safe_for_seq_to_codes() {
let mut ss = SeqStore_t::with_capacity(8, 128);
ZSTD_storeSeqOnly(&mut ss, 3, OFFSET_TO_OFFBASE(10), 7);
ZSTD_storeSeqOnly(&mut ss, 4, OFFSET_TO_OFFBASE(11), 8);
ZSTD_storeSeqOnly(
&mut ss,
5,
OFFSET_TO_OFFBASE(12),
0x10000 + MINMATCH as usize,
);
ss.literals.extend_from_slice(&[b'a'; 12]);
let mut chunk = ZSTD_deriveSeqStoreChunk(&ss, 0, 2);
crate::compress::zstd_compress::ZSTD_seqToCodes(&mut chunk);
assert_eq!(chunk.llCode.len(), 2);
assert_eq!(chunk.mlCode.len(), 2);
assert_eq!(chunk.ofCode.len(), 2);
}
#[test]
fn offbase_sumtype_roundtrips() {
let ob = OFFSET_TO_OFFBASE(42);
assert!(OFFBASE_IS_OFFSET(ob));
assert_eq!(OFFBASE_TO_OFFSET(ob), 42);
let wrapped = OFFSET_TO_OFFBASE(u32::MAX);
assert_eq!(wrapped, (u32::MAX).wrapping_add(ZSTD_REP_NUM as u32));
for r in 1..=3u32 {
let ob = REPCODE_TO_OFFBASE(r);
assert!(OFFBASE_IS_REPCODE(ob));
assert_eq!(OFFBASE_TO_REPCODE(ob), r);
}
assert!(!OFFBASE_IS_REPCODE(0));
}
#[test]
fn store_seq_only_appends() {
let mut ss = SeqStore_t::with_capacity(16, 1024);
ZSTD_storeSeqOnly(&mut ss, 5, OFFSET_TO_OFFBASE(17), 4);
assert_eq!(ss.sequences.len(), 1);
let s = ss.sequences[0];
assert_eq!(s.litLength, 5);
assert!(OFFBASE_IS_OFFSET(s.offBase));
assert_eq!(OFFBASE_TO_OFFSET(s.offBase), 17);
assert_eq!(s.mlBase, 4 - MINMATCH as u16);
}
#[test]
fn store_seq_appends_literals_and_bumps_sequences() {
let mut ss = SeqStore_t::with_capacity(16, 1024);
let src = b"hello matchdata";
ZSTD_storeSeq(&mut ss, 5, src, REPCODE_TO_OFFBASE(1), 3);
assert_eq!(ss.literals, b"hello");
assert_eq!(ss.sequences.len(), 1);
assert_eq!(ss.sequences[0].litLength, 5);
assert_eq!(ss.sequences[0].mlBase, 0);
}
#[test]
fn store_seq_near_literal_limit_uses_exact_copy() {
let mut ss = SeqStore_t::with_capacity(16, 1024);
let src = b"abcdefghijklmnopqrst";
ZSTD_storeSeq(&mut ss, src.len(), src, OFFSET_TO_OFFBASE(33), 5);
assert_eq!(ss.literals, src);
assert_eq!(ss.sequences.len(), 1);
assert_eq!(ss.sequences[0].litLength, src.len() as u16);
}
#[test]
fn store_seq_long_litlength_sets_flag() {
let mut ss = SeqStore_t::with_capacity(16, 200_000);
let lit = vec![b'x'; 0x10001];
ZSTD_storeSeq(&mut ss, 0x10001, &lit, OFFSET_TO_OFFBASE(100), 5);
assert_eq!(
ss.longLengthType,
ZSTD_longLengthType_e::ZSTD_llt_literalLength
);
assert_eq!(ss.longLengthPos, 0);
}
#[test]
fn update_rep_full_offset_shifts_history() {
let mut rep = [1u32, 4, 8];
ZSTD_updateRep(&mut rep, OFFSET_TO_OFFBASE(42), 0);
assert_eq!(rep, [42, 1, 4]);
}
#[test]
fn update_rep_repcode_1_noop() {
let rep_before = [5u32, 10, 20];
let mut rep = rep_before;
ZSTD_updateRep(&mut rep, REPCODE_TO_OFFBASE(1), 0);
assert_eq!(rep, rep_before);
}
#[test]
fn update_rep_repcode_2_promotes() {
let mut rep = [5u32, 10, 20];
ZSTD_updateRep(&mut rep, REPCODE_TO_OFFBASE(2), 0);
assert_eq!(rep, [10, 5, 20]);
}
#[test]
fn update_rep_uses_rep0_minus_one_when_repCode_equals_ZSTD_REP_NUM() {
let mut rep = [5u32, 10, 20];
ZSTD_updateRep(&mut rep, REPCODE_TO_OFFBASE(3), 1);
assert_eq!(rep, [4, 5, 10]); }
#[test]
fn update_rep_rep0_minus_one_wraps_like_u32() {
let mut rep = [0u32, 10, 20];
ZSTD_updateRep(&mut rep, REPCODE_TO_OFFBASE(3), 1);
assert_eq!(rep, [u32::MAX, 0, 10]);
}
#[test]
fn newRep_is_non_destructive_to_input() {
let rep = [5u32, 10, 20];
let result = ZSTD_newRep(&rep, OFFSET_TO_OFFBASE(42), 0);
assert_eq!(rep, [5, 10, 20], "input must not be mutated");
assert_eq!(result.rep, [42, 5, 10]);
}
}