use crate::Error;
pub fn split_packed(
ebuf: &[u64],
slen: usize,
idx: usize,
lbuf: &mut Vec<u64>,
rbuf: &mut Vec<u64>,
) -> Result<(), Error> {
if idx > slen {
return Err(Error::IndexOutOfBounds {
index: idx,
length: slen,
});
}
lbuf.clear();
rbuf.clear();
if idx == 0 {
rbuf.extend_from_slice(ebuf);
return Ok(());
}
if idx == slen {
lbuf.extend_from_slice(ebuf);
return Ok(());
}
if ebuf.is_empty() {
return Ok(());
}
let left_chunks = (idx / 32) + 1; let right_chunks = if idx == slen {
0
} else {
(slen - idx).div_ceil(32)
};
lbuf.reserve(left_chunks);
rbuf.reserve(right_chunks);
let chunk_idx = idx / 32; let bit_idx = (idx % 32) * 2;
if chunk_idx > 0 && chunk_idx <= ebuf.len() {
lbuf.extend_from_slice(&ebuf[..chunk_idx]);
}
let split_mask = if bit_idx == 0 {
0
} else {
(1u64 << bit_idx) - 1
};
lbuf.push(ebuf[chunk_idx] & split_mask);
let right_shift = bit_idx;
let mut carry = 0u64;
for curr in ebuf.iter().skip(chunk_idx) {
let shifted = carry | (curr >> right_shift);
rbuf.push(shifted);
carry = if right_shift == 0 {
0
} else {
curr << (64 - right_shift)
};
}
if carry != 0 && rbuf.len() < right_chunks {
rbuf.push(carry);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::twobit::{decode, encode};
#[test]
fn test_split_basic() {
let seq = b"ACTGACTG";
let mut ebuf = Vec::new();
encode(seq, &mut ebuf).unwrap();
let mut lbuf = Vec::new();
let mut rbuf = Vec::new();
split_packed(&ebuf, seq.len(), 4, &mut lbuf, &mut rbuf).unwrap();
assert_eq!(lbuf.len(), 1);
assert_eq!(rbuf.len(), 1);
let mut left = Vec::new();
decode(&lbuf, 4, &mut left).unwrap();
assert_eq!(&left, b"ACTG");
let mut right = Vec::new();
decode(&rbuf, 4, &mut right).unwrap();
assert_eq!(&right, b"ACTG");
}
#[test]
fn test_split_edge_cases() {
let seq = b"ACTG";
let mut ebuf = Vec::new();
encode(seq, &mut ebuf).unwrap();
let mut lbuf = Vec::new();
let mut rbuf = Vec::new();
split_packed(&ebuf, seq.len(), 0, &mut lbuf, &mut rbuf).unwrap();
let mut decoded = Vec::new();
decode(&rbuf, seq.len(), &mut decoded).unwrap();
assert_eq!(&decoded, seq);
assert_eq!(lbuf.len(), 0);
assert_eq!(rbuf.len(), 1);
split_packed(&ebuf, seq.len(), seq.len(), &mut lbuf, &mut rbuf).unwrap();
let mut decoded = Vec::new();
decode(&lbuf, seq.len(), &mut decoded).unwrap();
assert_eq!(&decoded, seq);
assert_eq!(lbuf.len(), 1);
assert_eq!(rbuf.len(), 0);
}
#[test]
fn test_split_odd_lengths() {
let seq = b"ACTGACTGAC"; let mut ebuf = Vec::new();
encode(seq, &mut ebuf).unwrap();
let mut lbuf = Vec::new();
let mut rbuf = Vec::new();
split_packed(&ebuf, seq.len(), 7, &mut lbuf, &mut rbuf).unwrap();
assert_eq!(lbuf.len(), 1);
assert_eq!(rbuf.len(), 1);
let mut left = Vec::new();
decode(&lbuf, 7, &mut left).unwrap();
assert_eq!(&left, b"ACTGACT");
let mut right = Vec::new();
decode(&rbuf, 3, &mut right).unwrap();
assert_eq!(&right, b"GAC");
}
#[test]
fn test_split_at_chunk_boundary() {
let seq = b"ACTGACTGACTGACTGACTGACTGACTGACTGACTGACTG"; let mut ebuf = Vec::new();
encode(seq, &mut ebuf).unwrap();
let mut lbuf = Vec::new();
let mut rbuf = Vec::new();
split_packed(&ebuf, seq.len(), 32, &mut lbuf, &mut rbuf).unwrap();
assert_eq!(lbuf.len(), 2);
assert_eq!(rbuf.len(), 1);
let mut left = Vec::new();
decode(&lbuf, 32, &mut left).unwrap();
assert_eq!(&left, &seq[..32]);
let mut right = Vec::new();
decode(&rbuf, 8, &mut right).unwrap();
assert_eq!(&right, &seq[32..]);
}
#[test]
fn test_invalid_inputs() {
let seq = b"ACTG";
let mut ebuf = Vec::new();
encode(seq, &mut ebuf).unwrap();
let mut lbuf = Vec::new();
let mut rbuf = Vec::new();
assert!(split_packed(&ebuf, seq.len(), seq.len() + 1, &mut lbuf, &mut rbuf).is_err());
}
}