#[must_use]
pub fn camera_column_air_gap(column: &[u8], cz: i32) -> Option<(i32, i32, usize)> {
if column.len() < 4 {
return None;
}
let first_z1 = i32::from(column[1]);
if cz < first_z1 {
return Some((0, first_z1, 0));
}
let mut pos = 0usize;
loop {
let nextptr = column[pos];
if nextptr == 0 {
return None;
}
pos = pos.checked_add(usize::from(nextptr) * 4)?;
if pos.checked_add(4)? > column.len() {
return None;
}
let z1 = i32::from(column[pos + 1]);
if cz < z1 {
let z0 = i32::from(column[pos + 3]);
if cz < z0 {
return None;
}
return Some((z0, z1, pos));
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn single_slab_5_15() -> Vec<u8> {
vec![0, 5, 14, 0]
}
fn two_slabs_air_at_20_30() -> Vec<u8> {
let mut col = Vec::new();
col.extend_from_slice(&[6, 10, 14, 0]);
col.resize(col.len() + 5 * 4, 0xab);
col.extend_from_slice(&[0, 30, 39, 20]);
col.resize(col.len() + 10 * 4, 0xcd);
col
}
#[test]
fn camera_above_first_slab_returns_zero_to_z1() {
let col = single_slab_5_15();
assert_eq!(camera_column_air_gap(&col, 0), Some((0, 5, 0)));
assert_eq!(camera_column_air_gap(&col, 4), Some((0, 5, 0)));
}
#[test]
fn camera_inside_solid_returns_none() {
let col = single_slab_5_15();
assert_eq!(camera_column_air_gap(&col, 10), None);
assert_eq!(camera_column_air_gap(&col, 100), None);
}
#[test]
fn camera_above_first_slab_in_two_slab_column() {
let col = two_slabs_air_at_20_30();
assert_eq!(camera_column_air_gap(&col, 5), Some((0, 10, 0)));
}
#[test]
fn camera_in_air_gap_between_slabs() {
let col = two_slabs_air_at_20_30();
assert_eq!(camera_column_air_gap(&col, 25), Some((20, 30, 24)));
assert_eq!(camera_column_air_gap(&col, 20), Some((20, 30, 24)));
assert_eq!(camera_column_air_gap(&col, 29), Some((20, 30, 24)));
}
#[test]
fn camera_in_first_slabs_hidden_interior_returns_none() {
let col = two_slabs_air_at_20_30();
assert_eq!(camera_column_air_gap(&col, 12), None);
}
#[test]
fn camera_in_last_slab_returns_none() {
let col = two_slabs_air_at_20_30();
assert_eq!(camera_column_air_gap(&col, 35), None);
assert_eq!(camera_column_air_gap(&col, 1000), None);
}
#[test]
fn malformed_too_short_returns_none() {
assert_eq!(camera_column_air_gap(&[1, 2, 3], 10), None);
}
#[test]
fn malformed_nextptr_overruns_returns_none() {
let col = vec![99, 10, 14, 0];
assert_eq!(camera_column_air_gap(&col, 100), None);
}
}