1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
extern crate byteorder;

use byteorder::{BigEndian, ReadBytesExt};
use std::io::Cursor;
use super::coils::Coil;
use super::exception_code::{Error, Reason, Result};

pub fn unpack_bits(bytes: &[u8], count: u16) -> Vec<Coil> {
    let mut res = Vec::with_capacity(count as usize);
    for i in 0..count {
        if (bytes[(i / 8u16) as usize] >> (i % 8)) & 0b1 > 0 {
            res.push(Coil::On);
        } else {
            res.push(Coil::Off);
        }
    }
    res
}

pub fn pack_bits(bits: &[Coil]) -> Vec<u8> {
    let bitcount = bits.len();
    let packed_size = bitcount / 8 + if bitcount % 8 > 0 { 1 } else { 0 };
    let mut res = vec![0; packed_size];
    for (i, b) in bits.iter().enumerate() {
        let v = match *b {
            Coil::On => 1u8,
            Coil::Off => 0u8,
        };
        res[(i / 8) as usize] |= v << (i % 8);
    }
    res
}

pub fn unpack_bytes(data: &[u16]) -> Vec<u8> {
    let size = data.len();
    let mut res = Vec::with_capacity(size * 2);
    for b in data {
        res.push((*b >> 8 & 0xff) as u8);
        res.push((*b & 0xff) as u8);
    }
    res
}

pub fn pack_bytes(bytes: &[u8]) -> Result<Vec<u16>> {
    let size = bytes.len();
    // check if we can create u16s from bytes by packing two u8s together without rest
    if size % 2 != 0 {
        return Err(Error::InvalidData(Reason::BytecountNotEven));
    }

    let mut res = Vec::with_capacity(size / 2 + 1);
    let mut rdr = Cursor::new(bytes);
    for _ in 0..size / 2 {
        res.push(rdr.read_u16::<BigEndian>()?);
    }
    Ok(res)
}

#[test]
fn test_unpack_bits() {
    // assert_eq!(unpack_bits(, 0), &[]);
    assert_eq!(unpack_bits(&[0, 0], 0), &[]);
    assert_eq!(unpack_bits(&[0b1], 1), &[Coil::On]);
    assert_eq!(unpack_bits(&[0b01], 2), &[Coil::On, Coil::Off]);
    assert_eq!(unpack_bits(&[0b10], 2), &[Coil::Off, Coil::On]);
    assert_eq!(unpack_bits(&[0b101], 3), &[Coil::On, Coil::Off, Coil::On]);
    assert_eq!(unpack_bits(&[0xff, 0b11], 10), &[Coil::On; 10]);
}

#[test]
fn test_pack_bits() {
    assert_eq!(pack_bits(&[]), &[]);
    assert_eq!(pack_bits(&[Coil::On]), &[1]);
    assert_eq!(pack_bits(&[Coil::Off]), &[0]);
    assert_eq!(pack_bits(&[Coil::On, Coil::Off]), &[1]);
    assert_eq!(pack_bits(&[Coil::Off, Coil::On]), &[2]);
    assert_eq!(pack_bits(&[Coil::On, Coil::On]), &[3]);
    assert_eq!(pack_bits(&[Coil::On; 8]), &[255]);
    assert_eq!(pack_bits(&[Coil::On; 9]), &[255, 1]);
    assert_eq!(pack_bits(&[Coil::Off; 8]), &[0]);
    assert_eq!(pack_bits(&[Coil::Off; 9]), &[0, 0]);
}

#[test]
fn test_unpack_bytes() {
    assert_eq!(unpack_bytes(&[]), &[]);
    assert_eq!(unpack_bytes(&[0]), &[0, 0]);
    assert_eq!(unpack_bytes(&[1]), &[0, 1]);
    assert_eq!(unpack_bytes(&[0xffff]), &[0xff, 0xff]);
    assert_eq!(unpack_bytes(&[0xffff, 0x0001]), &[0xff, 0xff, 0x00, 0x01]);
    assert_eq!(unpack_bytes(&[0xffff, 0x1001]), &[0xff, 0xff, 0x10, 0x01]);
}

#[test]
fn test_pack_bytes() {
    assert_eq!(pack_bytes(&[]).unwrap(), &[]);
    assert_eq!(pack_bytes(&[0, 0]).unwrap(), &[0]);
    assert_eq!(pack_bytes(&[0, 1]).unwrap(), &[1]);
    assert_eq!(pack_bytes(&[1, 0]).unwrap(), &[256]);
    assert_eq!(pack_bytes(&[1, 1]).unwrap(), &[257]);
    assert_eq!(pack_bytes(&[0, 1, 0, 2]).unwrap(), &[1, 2]);
    assert_eq!(pack_bytes(&[1, 1, 1, 2]).unwrap(), &[257, 258]);
    assert!(pack_bytes(&[1]).is_err());
    assert!(pack_bytes(&[1, 2, 3]).is_err());
}