wordlists 0.2.0

Take bits, give words.
Documentation
use crate::*;

/// Indexes into a wordlist can only ever be a max width. Rather than wasting space, we
/// encode a binary by stripping the padding to the devices usize bit width.
pub(crate) fn pack_indexes(indexes: Vec<usize>, width: usize) -> Result<BitVec> {
    let mut bits = BitVec::new();
    for index in indexes.iter() {
        //  - INDEX usize should be made into bit-array.
        //  - Then we should trim to only N bits, where N is self.bits().unwrap();
        //  - Finally extend 'bytes' vec with the given bits.
        let index_as_bits = &index.view_bits::<Lsb0>()[..width];
        bits.extend(index_as_bits);
    }
    //println!("packed: {:?}\nunpacked: {:?}", bits, indexes);
    Ok(bits)
}

/// Given a list of bits and the width of the wordlist-index (in bits), chunk the bits
/// into the correct width and cast to usize for indexing into wordlists. The result of
/// this function will be a list of indexes into a wordlist.
pub(crate) fn unpack_indexes(bitvec: &BitVec, width: usize) -> Result<Vec<usize>> {
    let mut indexes = Vec::new();
    for slice in bitvec.chunks(width) {
        indexes.push(slice.load());
    }
    //println!("packed: {:?}\nunpacked: {:?}", bitvec, indexes);
    Ok(indexes)
}

/// Find the minimum number of bits needed to represent an index for the wordlist of the given size.
/// This will fail if the wordlist size is not 2^N for some positive value of N.
pub(crate) fn index_width(wordlist_size: usize) -> Result<usize> {
    if wordlist_size <= 0 {
        return Err(WordlistError::InvalidWordlistSize(wordlist_size));
    }

    for shift in 1.. {
        let bits: usize = 1 << shift;
        if bits == wordlist_size {
            return Ok(shift);
        } else if bits > wordlist_size {
            break;
        }
    }
    Err(WordlistError::InvalidWordlistSize(wordlist_size))
}