arr_rs/numeric/operations/
binary_bits.rs

1use crate::{
2    core::prelude::*,
3    errors::prelude::*,
4    extensions::prelude::*,
5    numeric::prelude::*,
6};
7
8/// `ArrayTrait` - Binary Array bits operations
9pub trait ArrayBinaryBits where Self: Sized + Clone {
10
11    /// Unpacks elements of a uint8 array into a binary-valued output array
12    ///
13    /// # Arguments
14    ///
15    /// * `axis` - the dimension over which bit-unpacking is done. if none, array is flattened
16    /// * `count` - the number of elements to unpack along axis. if negative, array is trimmed
17    /// * `bit_order` - {`big`, `little`}, optional. defaults to `big`
18    ///
19    /// # Examples
20    ///
21    /// ```
22    /// use arr_rs::prelude::*;
23    ///
24    /// 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]]);
25    /// let array = array!(u8, [[2], [7], [23]]);
26    /// assert_eq!(expected, array.unpack_bits(Some(1), None, Some("big")));
27    /// ```
28    ///
29    /// # Errors
30    ///
31    /// may returns `ArrayError`
32    fn unpack_bits(&self, axis: Option<isize>, count: Option<isize>, bit_order: Option<impl BitOrderType>) -> Result<Array<u8>, ArrayError>;
33
34    /// Packs the elements of a binary-valued array into bits in a uint8 array
35    ///
36    /// # Arguments
37    ///
38    /// * `axis` - the dimension over which bit-packing is done. if none, array is flattened
39    /// * `bit_order` - {`big`, `little`}, optional. defaults to `big`
40    ///
41    /// # Examples
42    ///
43    /// ```
44    /// use arr_rs::prelude::*;
45    ///
46    /// let expected = array!(u8, [[2], [7], [23]]);
47    /// 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]]);
48    /// assert_eq!(expected, array.pack_bits(Some(1), Some("big")));
49    /// ```
50    ///
51    /// # Errors
52    ///
53    /// may returns `ArrayError`
54    fn pack_bits(&self, axis: Option<isize>, bit_order: Option<impl BitOrderType>) -> Result<Array<u8>, ArrayError>;
55}
56
57impl ArrayBinaryBits for Array<u8> {
58
59    fn unpack_bits(&self, axis: Option<isize>, count: Option<isize>, bit_order: Option<impl BitOrderType>) -> Result<Array<u8>, ArrayError> {
60        if self.is_empty()? { return Self::empty() }
61        let bit_order = match bit_order {
62            Some(bo) => bo.to_bit_order()?,
63            None => BitOrder::Big,
64        };
65        match axis {
66            None => {
67                let result = self.ravel()?
68                    .into_iter()
69                    .flat_map(|a| {
70                        let mut elems = (0..8).rev().map(move |idx| (a >> idx) & 1).collect::<Vec<u8>>();
71                        if bit_order == BitOrder::Little { elems.reverse_ext() } else { elems }
72                    })
73                    .collect::<Self>();
74                let count = count.unwrap_or(self.len()?.to_isize() * 8);
75                if count >= 0 { result.slice(0..count.to_usize()) }
76                else { result.slice(0..self.len()? - count.to_usize()) }
77            },
78            Some(axis) => {
79                let axis = self.normalize_axis(axis);
80                self.apply_along_axis(axis, |arr| arr.unpack_bits(None, count, Some(bit_order)))
81            }
82        }
83    }
84
85    fn pack_bits(&self, axis: Option<isize>, bit_order: Option<impl BitOrderType>) -> Result<Array<u8>, ArrayError> {
86        if self.is_empty()? { return Self::empty() }
87        let bit_order = match bit_order {
88            Some(bo) => bo.to_bit_order()?,
89            None => BitOrder::Big,
90        };
91        match axis {
92            None => {
93                let mut elements = self.get_elements()?;
94                if elements.len() % 8 != 0 { elements.extend_from_slice(&vec![0; 8 - elements.len() % 8]) }
95
96                let parts = elements.len() / 8;
97                let result = (0..parts).map(|p| {
98                    let subarray = elements[p * 8..(p + 1) * 8].iter()
99                        .map(|i| if i > &0 { "1" } else { "0" })
100                        .collect::<Vec<&str>>()
101                        .join("");
102                    let subarray = if bit_order == BitOrder::Little { subarray.chars().rev().collect() } else { subarray };
103                    u8::from_str_radix(&subarray, 2).unwrap()
104                }).collect();
105                Ok(result)
106            },
107            Some(axis) => {
108                let axis = self.normalize_axis(axis);
109                self.apply_along_axis(axis, |arr| arr.pack_bits(None, Some(bit_order)))
110            },
111        }
112    }
113}
114
115impl ArrayBinaryBits for Result<Array<u8>, ArrayError> {
116
117    fn unpack_bits(&self, axis: Option<isize>, count: Option<isize>, bit_order: Option<impl BitOrderType>) -> Result<Array<u8>, ArrayError> {
118        self.clone()?.unpack_bits(axis, count, bit_order)
119    }
120
121    fn pack_bits(&self, axis: Option<isize>, bit_order: Option<impl BitOrderType>) -> Result<Array<u8>, ArrayError> {
122        self.clone()?.pack_bits(axis, bit_order)
123    }
124}