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
106
107
108
109
110
111
112
113
114
115
116
use crate::{
    core::prelude::*,
    errors::prelude::*,
    extensions::prelude::*,
    numeric::prelude::*,
};

/// ArrayTrait - Binary Array bits operations
pub trait ArrayBinaryBits where Self: Sized + Clone {

    /// Unpacks elements of a uint8 array into a binary-valued output array
    ///
    /// # Arguments
    ///
    /// * `axis` - the dimension over which bit-unpacking is done. if none, array is flattened
    /// * `count` - the number of elements to unpack along axis. if negative, array is trimmed
    /// * `bit_order` - {`big`, `little`}, optional. defaults to `big`
    ///
    /// # Examples
    ///
    /// ```
    /// use arr_rs::prelude::*;
    ///
    /// let expected = array!(u8, [[0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 1, 0, 1, 1, 1]]);
    /// let array = array!(u8, [[2], [7], [23]]);
    /// assert_eq!(expected, array.unpack_bits(Some(1), None, Some("big")));
    /// ```
    fn unpack_bits(&self, axis: Option<isize>, count: Option<isize>, bit_order: Option<impl BitOrderType>) -> Result<Array<u8>, ArrayError>;

    /// Packs the elements of a binary-valued array into bits in a uint8 array
    ///
    /// # Arguments
    ///
    /// * `axis` - the dimension over which bit-packing is done. if none, array is flattened
    /// * `bit_order` - {`big`, `little`}, optional. defaults to `big`
    ///
    /// # Examples
    ///
    /// ```
    /// use arr_rs::prelude::*;
    ///
    /// let expected = array!(u8, [[2], [7], [23]]);
    /// let array = array!(u8, [[0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 1, 0, 1, 1, 1]]);
    /// assert_eq!(expected, array.pack_bits(Some(1), Some("big")));
    /// ```
    fn pack_bits(&self, axis: Option<isize>, bit_order: Option<impl BitOrderType>) -> Result<Array<u8>, ArrayError>;
}

impl ArrayBinaryBits for Array<u8> {

    fn unpack_bits(&self, axis: Option<isize>, count: Option<isize>, bit_order: Option<impl BitOrderType>) -> Result<Array<u8>, ArrayError> {
        if self.is_empty()? { return Array::empty() }
        let bit_order = match bit_order {
            Some(bo) => bo.to_bit_order()?,
            None => BitOrder::Big,
        };
        match axis {
            None => {
                let result = self.ravel()?
                    .into_iter()
                    .flat_map(|a| {
                        let mut elems = (0..8).rev().map(move |idx| (a >> idx) & 1).collect::<Vec<u8>>();
                        if bit_order == BitOrder::Little { elems.reverse_ext() } else { elems }
                    })
                    .collect::<Array<u8>>();
                let count = count.unwrap_or(self.len()? as isize * 8);
                if count >= 0 { result.slice(0 .. count as usize) }
                else { result.slice(0 .. self.len()? - count as usize) }
            },
            Some(axis) => {
                let axis = self.normalize_axis(axis);
                self.apply_along_axis(axis, |arr| arr.unpack_bits(None, count, Some(bit_order)))
            }
        }
    }

    fn pack_bits(&self, axis: Option<isize>, bit_order: Option<impl BitOrderType>) -> Result<Array<u8>, ArrayError> {
        if self.is_empty()? { return Array::empty() }
        let bit_order = match bit_order {
            Some(bo) => bo.to_bit_order()?,
            None => BitOrder::Big,
        };
        match axis {
            None => {
                let mut elements = self.get_elements()?;
                if elements.len() % 8 != 0 { elements.extend_from_slice(&vec![0; 8 - elements.len() % 8]) }

                let parts = elements.len() / 8;
                let result = (0 .. parts).map(|p| {
                    let subarray = elements[p * 8 .. (p + 1) * 8].iter()
                        .map(|i| if i > &0 { "1" } else { "0" })
                        .collect::<Vec<&str>>()
                        .join("");
                    let subarray = if bit_order == BitOrder::Little { subarray.chars().rev().collect() } else { subarray };
                    u8::from_str_radix(&subarray, 2).unwrap()
                }).collect();
                Ok(result)
            },
            Some(axis) => {
                let axis = self.normalize_axis(axis);
                self.apply_along_axis(axis, |arr| arr.pack_bits(None, Some(bit_order)))
            },
        }
    }
}

impl ArrayBinaryBits for Result<Array<u8>, ArrayError> {

    fn unpack_bits(&self, axis: Option<isize>, count: Option<isize>, bit_order: Option<impl BitOrderType>) -> Result<Array<u8>, ArrayError> {
        self.clone()?.unpack_bits(axis, count, bit_order)
    }

    fn pack_bits(&self, axis: Option<isize>, bit_order: Option<impl BitOrderType>) -> Result<Array<u8>, ArrayError> {
        self.clone()?.pack_bits(axis, bit_order)
    }
}