pub trait PixelMap {
const WIDTH: u32;
const HEIGHT: u32;
const BUFFER_LEN: usize;
const CASET_FIRST: u8;
const RASET_FIRST: u8;
fn locate(x: u32, y: u32) -> Option<(usize, u8)>;
fn read_row(buf: &[u8], y: u32, out: &mut [bool]) -> bool;
fn write_row(buf: &mut [u8], y: u32, row: &[bool]);
fn write_row_rev(buf: &mut [u8], y: u32, row: &[bool]);
fn read_col(buf: &[u8], x: u32, out: &mut [bool]) -> bool;
fn write_col(buf: &mut [u8], x: u32, col: &[bool]);
fn write_col_rev(buf: &mut [u8], x: u32, col: &[bool]);
}
#[derive(Debug)]
pub enum Landscape<const W: u32, const H: u32, const CASET0: u8, const RASET0: u8> {}
impl<const W: u32, const H: u32, const CASET0: u8, const RASET0: u8>
Landscape<W, H, CASET0, RASET0>
{
const fn len() -> usize {
((W / 2) * (H / 4)) as usize
}
const fn locate(x: u32, y: u32) -> Option<(usize, u8)> {
if x >= W || y >= H {
return None;
}
let inv_y = H - 1 - y;
Some((
((x / 2) * (H / 4) + inv_y / 4) as usize,
(7 - inv_y % 4 * 2 - x % 2) as u8,
))
}
}
const _: () = assert!(matches!(
Landscape::<400, 300, 0x12, 0>::locate(0, 299),
Some((0, 7))
));
const _: () = assert!(matches!(
Landscape::<400, 300, 0x12, 0>::locate(0, 0),
Some((74, 1))
));
const _: () = assert!(matches!(
Landscape::<400, 300, 0x12, 0>::locate(399, 0),
Some((14999, 0))
));
const _: () = assert!(matches!(
Landscape::<400, 300, 0x12, 0>::locate(399, 299),
Some((14925, 6))
));
const _: () = assert!(matches!(
Landscape::<400, 300, 0x12, 0>::locate(1, 299),
Some((0, 6))
));
const _: () = assert!(matches!(
Landscape::<400, 300, 0x12, 0>::locate(2, 299),
Some((75, 7))
));
const _: () = assert!(matches!(
Landscape::<400, 300, 0x12, 0>::locate(5, 100),
Some((199, 0))
));
const _: () = assert!(Landscape::<400, 300, 0x12, 0>::locate(400, 0).is_none());
const _: () = assert!(Landscape::<400, 300, 0x12, 0>::locate(0, 300).is_none());
const _: () = assert!(matches!(Landscape::<400, 300, 0x12, 0>::len(), 15000));
impl<const W: u32, const H: u32, const CASET0: u8, const RASET0: u8> PixelMap
for Landscape<W, H, CASET0, RASET0>
{
const WIDTH: u32 = W;
const HEIGHT: u32 = H;
const BUFFER_LEN: usize = {
assert!(
W.is_multiple_of(2) && H.is_multiple_of(4),
"W must be multiple of 2, H must be multiple of 4"
);
Self::len()
};
const CASET_FIRST: u8 = CASET0;
const RASET_FIRST: u8 = RASET0;
fn locate(x: u32, y: u32) -> Option<(usize, u8)> {
Self::locate(x, y)
}
fn read_row(buf: &[u8], y: u32, out: &mut [bool]) -> bool {
assert!(y < H && out.len() == W as usize && buf.len() == Self::len());
let inv_y = H - 1 - y;
let base = (inv_y / 4) as usize; let hi = 7 - 2 * (inv_y % 4); let mask = 0b11u8 << (hi - 1);
let mut acc = 0u8;
let bytes = buf[base..].iter().step_by((H / 4) as usize);
for (pair, &b) in out.chunks_exact_mut(2).zip(bytes) {
pair[0] = (b >> hi) & 1 != 0;
pair[1] = (b >> (hi - 1)) & 1 != 0;
acc |= b & mask;
}
acc != 0
}
fn write_row(buf: &mut [u8], y: u32, row: &[bool]) {
assert!(y < H && row.len() == W as usize && buf.len() == Self::len());
let inv_y = H - 1 - y;
let base = (inv_y / 4) as usize;
let hi = 7 - 2 * (inv_y % 4);
let bytes = buf[base..].iter_mut().step_by((H / 4) as usize);
for (pair, b) in row.chunks_exact(2).zip(bytes) {
*b |= (u8::from(pair[0]) << hi) | (u8::from(pair[1]) << (hi - 1));
}
}
fn write_row_rev(buf: &mut [u8], y: u32, row: &[bool]) {
assert!(y < H && row.len() == W as usize && buf.len() == Self::len());
let inv_y = H - 1 - y;
let base = (inv_y / 4) as usize;
let hi = 7 - 2 * (inv_y % 4);
let bytes = buf[base..].iter_mut().step_by((H / 4) as usize);
for (pair, b) in row.rchunks_exact(2).zip(bytes) {
*b |= (u8::from(pair[1]) << hi) | (u8::from(pair[0]) << (hi - 1));
}
}
fn read_col(buf: &[u8], x: u32, out: &mut [bool]) -> bool {
assert!(x < W && out.len() == H as usize && buf.len() == Self::len());
let lane = (x % 2) as u8;
let base = (x / 2 * (H / 4)) as usize;
let mask = 0xAAu8 >> lane;
let mut acc = 0u8;
let bytes = &buf[base..base + (H / 4) as usize];
for (quad, &b) in out.rchunks_exact_mut(4).zip(bytes) {
quad[3] = (b >> (7 - lane)) & 1 != 0;
quad[2] = (b >> (5 - lane)) & 1 != 0;
quad[1] = (b >> (3 - lane)) & 1 != 0;
quad[0] = (b >> (1 - lane)) & 1 != 0;
acc |= b & mask;
}
acc != 0
}
fn write_col(buf: &mut [u8], x: u32, col: &[bool]) {
assert!(x < W && col.len() == H as usize && buf.len() == Self::len());
let lane = (x % 2) as u8;
let base = (x / 2 * (H / 4)) as usize;
let bytes = buf[base..base + (H / 4) as usize].iter_mut();
for (quad, b) in col.rchunks_exact(4).zip(bytes) {
*b |= (u8::from(quad[3]) << (7 - lane))
| (u8::from(quad[2]) << (5 - lane))
| (u8::from(quad[1]) << (3 - lane))
| (u8::from(quad[0]) << (1 - lane));
}
}
fn write_col_rev(buf: &mut [u8], x: u32, col: &[bool]) {
assert!(x < W && col.len() == H as usize && buf.len() == Self::len());
let lane = (x % 2) as u8;
let base = (x / 2 * (H / 4)) as usize;
let bytes = buf[base..base + (H / 4) as usize].iter_mut();
for (quad, b) in col.chunks_exact(4).zip(bytes) {
*b |= (u8::from(quad[0]) << (7 - lane))
| (u8::from(quad[1]) << (5 - lane))
| (u8::from(quad[2]) << (3 - lane))
| (u8::from(quad[3]) << (1 - lane));
}
}
}
const _: () = assert!(<Landscape<400, 300, 0x12, 0> as PixelMap>::BUFFER_LEN == 15000);