use crate::Offset;
mod sealed {
pub trait Sealed {}
}
pub trait Connectivity: sealed::Sealed + Copy {
const NEIGHBOURS: usize;
const OFFSETS: &'static [Offset];
type Dual: Connectivity;
}
#[derive(Clone, Copy, Debug)]
pub struct Connectivity4;
#[derive(Clone, Copy, Debug)]
pub struct Connectivity8;
impl sealed::Sealed for Connectivity4 {}
impl sealed::Sealed for Connectivity8 {}
impl Connectivity for Connectivity4 {
const NEIGHBOURS: usize = 2;
const OFFSETS: &'static [Offset] = &[Offset::new(-1, 0), Offset::new(0, -1)];
type Dual = Connectivity8;
}
impl Connectivity for Connectivity8 {
const NEIGHBOURS: usize = 4;
const OFFSETS: &'static [Offset] = &[
Offset::new(-1, -1),
Offset::new(0, -1),
Offset::new(1, -1),
Offset::new(-1, 0),
];
type Dual = Connectivity4;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn connectivity4_offsets_are_w_n_only() {
assert_eq!(Connectivity4::NEIGHBOURS, 2);
assert_eq!(
Connectivity4::OFFSETS,
&[Offset::new(-1, 0), Offset::new(0, -1)]
);
}
#[test]
fn connectivity8_offsets_are_nw_n_ne_w() {
assert_eq!(Connectivity8::NEIGHBOURS, 4);
assert_eq!(
Connectivity8::OFFSETS,
&[
Offset::new(-1, -1),
Offset::new(0, -1),
Offset::new(1, -1),
Offset::new(-1, 0),
]
);
}
#[test]
fn all_offsets_are_raster_preceding() {
for offsets in [Connectivity4::OFFSETS, Connectivity8::OFFSETS] {
for &off in offsets {
assert!(
off.dy < 0 || (off.dy == 0 && off.dx < 0),
"offset {off:?} is not raster-scan-preceding"
);
}
}
}
#[test]
fn neighbours_matches_offsets_length() {
assert_eq!(Connectivity4::NEIGHBOURS, Connectivity4::OFFSETS.len());
assert_eq!(Connectivity8::NEIGHBOURS, Connectivity8::OFFSETS.len());
}
}