#![allow(incomplete_features)]
#![feature(const_generics)]
#![feature(const_evaluatable_checked)]
#![allow(unused_parens)]
extern crate log;
use log::warn;
#[cfg(feature = "serde")]
extern crate serde;
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
pub const fn get_array_length(bits: u8, size: usize) -> usize {
(((bits as usize) * size) + (u8::BITS as usize) - 1) / (u8::BITS as usize)
}
#[derive(Debug, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(transparent)]
pub struct PackedIntegerArray<const BITS: u8, const LEN: usize>
where [u8; get_array_length(BITS, LEN)]: Sized {
content: [u8; get_array_length(BITS, LEN)]
}
impl <const BITS: u8, const LEN: usize> PackedIntegerArray<BITS, LEN>
where [u8; get_array_length(BITS, LEN)]: Sized {
pub fn new() -> Self {
Self::default()
}
pub fn get(&self, index: usize) -> u8 {
if index >= LEN {
panic!("index out of bounds: the len is {} but the index is {}", LEN, index);
}
let start_byte = (index * (BITS as usize)) / (u8::BITS as usize); let start_bit = (index * (BITS as usize)) - (start_byte * (u8::BITS as usize));
let mut result = ((self.content[start_byte] << start_bit) >> ((u8::BITS as usize) - (BITS as usize)));
if start_bit + (BITS as usize) > (u8::BITS as usize) {
result |= (self.content[start_byte + 1] >> ((u8::BITS as usize * 2) - (start_bit + (BITS as usize))));
}
result
}
pub fn set(&mut self, index: usize, value: u8) {
let max = usize::pow(2, BITS as u32);
if value as usize >= max {
warn!("Warning: input value {} is greater than the maximum value {} for {} bits. This may cause unintended functionality.", value, max - 1, BITS);
}
if index >= LEN {
panic!("index out of bounds: the len is {} but the index is {}", LEN, index);
}
let start_byte = (index * (BITS as usize)) / (u8::BITS as usize); let start_bit = (index * (BITS as usize)) - (start_byte * (u8::BITS as usize));
if start_bit + (BITS as usize) > (u8::BITS as usize) {
self.content[start_byte] ^= ((self.content[start_byte] << start_bit) >> start_bit);
self.content[start_byte + 1] ^= (self.content[start_byte + 1] >> ((u8::BITS as usize * 2) - (start_bit + (BITS as usize)))) << ((u8::BITS as usize * 2) - (start_bit + (BITS as usize)));
} else {
self.content[start_byte] ^= ((self.content[start_byte] << start_bit) >> ((u8::BITS as usize) - (BITS as usize))) << ((u8::BITS as usize) - (BITS as usize) - start_bit);
}
self.content[start_byte] |= ((value << ((u8::BITS as usize) - (BITS as usize))) >> start_bit);
if start_bit + (BITS as usize) > (u8::BITS as usize) {
self.content[start_byte + 1] |= (value << (u8::BITS as usize * 2) - BITS as usize - start_bit);
}
}
pub fn clear(&mut self, index: usize) {
if index >= LEN {
panic!("index out of bounds: the len is {} but the index is {}", LEN, index);
}
let start_byte = (index * (BITS as usize)) / (u8::BITS as usize); let start_bit = (index * (BITS as usize)) - (start_byte * (u8::BITS as usize));
if start_bit + (BITS as usize) > (u8::BITS as usize) {
self.content[start_byte] ^= ((self.content[start_byte] << start_bit) >> start_bit);
self.content[start_byte + 1] ^= (self.content[start_byte + 1] >> ((u8::BITS as usize * 2) - (start_bit + (BITS as usize)))) << ((u8::BITS as usize * 2) - (start_bit + (BITS as usize)));
} else {
self.content[start_byte] ^= ((self.content[start_byte] << start_bit) >> ((u8::BITS as usize) - (BITS as usize))) << ((u8::BITS as usize) - (BITS as usize) - start_bit);
}
}
pub fn unpack(self) -> [u8; LEN] {
let mut items: [u8; LEN] = [0; LEN];
for i in 0..LEN {
items[i] = self.get(i)
}
items
}
}
use std::default::Default;
impl <const BITS: u8, const LEN: usize> Default for PackedIntegerArray<BITS, LEN>
where [u8; get_array_length(BITS, LEN)]: Sized {
fn default() -> Self {
Self {
content: [0; get_array_length(BITS, LEN)]
}
}
}
use std::convert::AsMut;
impl <const BITS: u8, const LEN: usize> AsMut<[u8]> for PackedIntegerArray<BITS, LEN>
where [u8; get_array_length(BITS, LEN)]: Sized {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.content[..]
}
}
use std::convert::AsRef;
impl <const BITS: u8, const LEN: usize> AsRef<[u8]> for PackedIntegerArray<BITS, LEN>
where [u8; get_array_length(BITS, LEN)]: Sized {
fn as_ref(&self) -> &[u8] {
&self.content[..]
}
}
use std::hash::Hash;
use std::hash::Hasher;
impl <const BITS: u8, const LEN: usize> Hash for PackedIntegerArray<BITS, LEN>
where [u8; get_array_length(BITS, LEN)]: Sized {
fn hash<H>(&self, state: &mut H) where H: Hasher {
Hash::hash(&self.content[..], state)
}
}
use std::iter::IntoIterator;
impl <const BITS: u8, const LEN: usize> IntoIterator for PackedIntegerArray<BITS, LEN>
where [u8; get_array_length(BITS, LEN)]: Sized {
type Item = u8;
type IntoIter = PackedIntegerArrayIterator<BITS, LEN>;
fn into_iter(self) -> <Self as IntoIterator>::IntoIter {
PackedIntegerArrayIterator {
index: 0,
array: self
}
}
}
use std::cmp::PartialEq;
impl <const BITS: u8, const LEN: usize> PartialEq<[u8; LEN]> for PackedIntegerArray<BITS, LEN>
where [u8; get_array_length(BITS, LEN)]: Sized {
fn eq(&self, other: &[u8; LEN]) -> bool {
for i in 0..LEN {
if other[i] != self.get(i) {
return false;
}
}
return true;
}
}
impl <const BITS: u8, const LEN: usize> PartialEq<PackedIntegerArray<BITS, LEN>> for PackedIntegerArray<BITS, LEN>
where [u8; get_array_length(BITS, LEN)]: Sized {
fn eq(&self, other: &PackedIntegerArray<BITS, LEN>) -> bool {
self.content == other.content
}
}
use std::iter::Iterator;
pub struct PackedIntegerArrayIterator<const BITS: u8, const LEN: usize>
where [u8; get_array_length(BITS, LEN)]: Sized {
index: usize,
array: PackedIntegerArray<BITS, LEN>
}
impl <const BITS: u8, const LEN: usize> Iterator for PackedIntegerArrayIterator<BITS, LEN>
where [u8; get_array_length(BITS, LEN)]: Sized {
type Item = u8;
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
if (self.index < LEN) {
let val = self.array.get(self.index);
self.index += 1;
Some(val)
} else {
None
}
}
}