use super::{CoordPos, Direction};
use std::fmt;
#[derive(Copy, Clone, PartialEq)]
pub(crate) enum TopologyPosition {
Area {
on: Option<CoordPos>,
left: Option<CoordPos>,
right: Option<CoordPos>,
},
LineOrPoint {
on: Option<CoordPos>,
},
}
impl fmt::Debug for TopologyPosition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fn fmt_position(position: &Option<CoordPos>, f: &mut fmt::Formatter) -> fmt::Result {
match position {
Some(CoordPos::Inside) => write!(f, "i"),
Some(CoordPos::OnBoundary) => write!(f, "b"),
Some(CoordPos::Outside) => write!(f, "e"),
None => write!(f, "_"),
}
}
match self {
Self::LineOrPoint { on } => fmt_position(on, f)?,
Self::Area { on, left, right } => {
fmt_position(left, f)?;
fmt_position(on, f)?;
fmt_position(right, f)?;
}
}
Ok(())
}
}
impl TopologyPosition {
pub fn area(on: CoordPos, left: CoordPos, right: CoordPos) -> Self {
Self::Area {
on: Some(on),
left: Some(left),
right: Some(right),
}
}
pub fn empty_area() -> Self {
Self::Area {
on: None,
left: None,
right: None,
}
}
pub fn line_or_point(on: CoordPos) -> Self {
Self::LineOrPoint { on: Some(on) }
}
pub fn empty_line_or_point() -> Self {
Self::LineOrPoint { on: None }
}
pub fn get(&self, direction: Direction) -> Option<CoordPos> {
match (direction, self) {
(Direction::Left, Self::Area { left, .. }) => *left,
(Direction::Right, Self::Area { right, .. }) => *right,
(Direction::On, Self::LineOrPoint { on }) | (Direction::On, Self::Area { on, .. }) => {
*on
}
(_, Self::LineOrPoint { .. }) => {
panic!("LineOrPoint only has a position for `Direction::On`")
}
}
}
pub fn is_empty(&self) -> bool {
matches!(
self,
Self::LineOrPoint { on: None }
| Self::Area {
on: None,
left: None,
right: None,
}
)
}
pub fn is_any_empty(&self) -> bool {
!matches!(
self,
Self::LineOrPoint { on: Some(_) }
| Self::Area {
on: Some(_),
left: Some(_),
right: Some(_),
}
)
}
pub fn is_area(&self) -> bool {
matches!(self, Self::Area { .. })
}
pub fn is_line(&self) -> bool {
matches!(self, Self::LineOrPoint { .. })
}
pub fn flip(&mut self) {
match self {
Self::LineOrPoint { .. } => {}
Self::Area { left, right, .. } => {
std::mem::swap(left, right);
}
}
}
pub fn set_all_positions(&mut self, position: CoordPos) {
match self {
Self::LineOrPoint { on } => {
*on = Some(position);
}
Self::Area { on, left, right } => {
*on = Some(position);
*left = Some(position);
*right = Some(position);
}
}
}
pub fn set_all_positions_if_empty(&mut self, position: CoordPos) {
match self {
Self::LineOrPoint { on } => {
if on.is_none() {
*on = Some(position);
}
}
Self::Area { on, left, right } => {
if on.is_none() {
*on = Some(position);
}
if left.is_none() {
*left = Some(position);
}
if right.is_none() {
*right = Some(position);
}
}
}
}
pub fn set_position(&mut self, direction: Direction, position: CoordPos) {
match (direction, self) {
(Direction::On, Self::LineOrPoint { on }) => *on = Some(position),
(_, Self::LineOrPoint { .. }) => {
panic!("invalid assignment dimensions for Self::Line")
}
(Direction::On, Self::Area { on, .. }) => *on = Some(position),
(Direction::Left, Self::Area { left, .. }) => *left = Some(position),
(Direction::Right, Self::Area { right, .. }) => *right = Some(position),
}
}
pub fn set_on_position(&mut self, position: CoordPos) {
match self {
Self::LineOrPoint { on } | Self::Area { on, .. } => {
*on = Some(position);
}
}
}
pub fn set_locations(&mut self, new_on: CoordPos, new_left: CoordPos, new_right: CoordPos) {
match self {
Self::LineOrPoint { .. } => {
error!("invalid assignment dimensions for {self:?}");
debug_assert!(false, "invalid assignment dimensions for {self:?}");
}
Self::Area { on, left, right } => {
*on = Some(new_on);
*left = Some(new_left);
*right = Some(new_right);
}
}
}
}