1use std::{fmt, mem};
4
5use crate::{div_ceil, Bitset};
6
7#[derive(Debug, Clone)]
12pub struct BitMatrix(Bitset<Box<[u32]>>);
13impl BitMatrix {
14 #[inline]
22 #[must_use]
23 pub fn height(&self, width: usize) -> usize {
24 match self.0.bit_len() {
25 0 => 0,
26 total => total / width,
27 }
28 }
29 #[inline]
36 #[must_use]
37 pub fn active_rows_in_column(&self, width: usize, x: usize) -> Column {
38 assert_ne!(width, 0);
39 Column { data: &self.0 .0, width, current_cell: x }
40 }
41 pub fn row(&self, width: usize, y: usize) -> impl Iterator<Item = usize> + '_ {
45 let start = y * width;
46 let end = (y + 1) * width;
47
48 self.0
49 .ones_in_range(start..end)
50 .map(move |i| (i as usize) - start)
51 }
52 #[inline]
59 pub fn enable_bit(&mut self, width: usize, x: usize, y: usize) -> Option<()> {
60 if width == 0 {
61 return Some(());
62 }
63 self.0.enable_bit(width * y + x)
64 }
65 #[must_use]
69 pub fn new_with_size(width: usize, height: usize) -> Self {
70 let bit_size = width * height;
71 let u32_size = div_ceil(bit_size, mem::size_of::<u32>());
72 BitMatrix(Bitset(vec![0; u32_size].into_boxed_slice()))
73 }
74
75 #[must_use]
79 pub fn bit(&self, width: usize, x: usize, y: usize) -> bool {
80 x < width && self.0.bit(x + y * width)
81 }
82
83 #[must_use]
88 pub const fn sextant_display(&self, width: usize, height: usize) -> SextantDisplay {
89 SextantDisplay { matrix: self, width, height }
90 }
91}
92
93pub struct Column<'a> {
96 width: usize,
97 current_cell: usize,
98 data: &'a [u32],
99}
100impl Iterator for Column<'_> {
101 type Item = usize;
102
103 fn next(&mut self) -> Option<Self::Item> {
104 loop {
105 let bit = self.current_cell;
106 let row = self.current_cell / self.width;
107 self.current_cell += self.width;
108
109 let block = bit / u32::BITS as usize;
110 let offset = bit % u32::BITS as usize;
111
112 let is_active = |block: u32| block & (1 << offset) != 0;
113 match self.data.get(block) {
114 Some(block) if is_active(*block) => return Some(row),
115 Some(_) => continue,
116 None => return None,
117 }
118 }
119 }
120 #[inline]
121 fn size_hint(&self) -> (usize, Option<usize>) {
122 let upper = self.data.len().saturating_sub(self.current_cell) / self.width;
123 (0, Some(upper))
124 }
125 #[inline]
126 fn nth(&mut self, n: usize) -> Option<Self::Item> {
127 self.current_cell = self.current_cell.saturating_add(n * self.width);
128 self.next()
129 }
130}
131
132#[derive(Copy, Clone)]
134pub struct SextantDisplay<'a> {
135 matrix: &'a BitMatrix,
136 width: usize,
137 height: usize,
138}
139impl<'a> fmt::Debug for SextantDisplay<'a> {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 fmt::Display::fmt(self, f)
142 }
143}
144impl<'a> fmt::Display for SextantDisplay<'a> {
145 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146 if self.height == 0 {
147 write!(f, "\u{1fb74}\u{1fb70}")?;
148 }
149 for y in 0..div_ceil(self.height, 3) {
150 if y != 0 {
151 writeln!(f)?;
152 }
153 write!(f, "\u{1fb74}")?;
154 for x in 0..div_ceil(self.width, 2) {
155 let get_bit = |offset_x, offset_y| {
156 let (x, y) = (x * 2 + offset_x, y * 3 + offset_y);
157 u32::from(self.matrix.bit(self.width, x, y))
158 };
159 let offset = get_bit(0, 0)
160 | get_bit(1, 0) << 1
161 | get_bit(0, 1) << 2
162 | get_bit(1, 1) << 3
163 | get_bit(0, 2) << 4
164 | get_bit(1, 2) << 5;
165 let character = match offset {
166 0b11_1111 => '\u{2588}',
167 0b00_0000 => ' ',
168 offset => char::from_u32(0x1fb00 + offset - 1).unwrap(),
169 };
170 write!(f, "{character}")?;
171 }
172 write!(f, "\u{1fb70}")?;
173 }
174 Ok(())
175 }
176}