// SPDX-FileCopyrightText: 2024 Topola contributors // // SPDX-License-Identifier: MIT use std::collections::VecDeque; use enum_dispatch::enum_dispatch; use petgraph::visit::Walker; use crate::{ drawing::{ bend::{BendIndex, FixedBendIndex, LooseBendIndex}, dot::FixedDotIndex, graph::{MakePrimitiveRef, PrimitiveIndex}, primitive::{FixedBendRef, FixedDotRef, LooseBendRef, PrimitiveRef}, rules::AccessRules, Drawing, }, graph::{GetIndex, MakeRef}, }; #[enum_dispatch(GetIndex, MakePrimitiveRef)] #[derive(Debug, Clone, Copy, PartialEq)] pub enum GearIndex { FixedDot(FixedDotIndex), FixedBend(FixedBendIndex), LooseBend(LooseBendIndex), } impl<'a, CW: 'a, Cel: 'a, R: 'a> MakeRef<'a, Drawing> for GearIndex { type Output = GearRef<'a, CW, Cel, R>; fn ref_(&self, drawing: &'a Drawing) -> GearRef<'a, CW, Cel, R> { GearRef::<'a, CW, Cel, R>::new(*self, drawing) } } impl From for PrimitiveIndex { fn from(wraparoundable: GearIndex) -> Self { match wraparoundable { GearIndex::FixedDot(dot) => PrimitiveIndex::FixedDot(dot), GearIndex::FixedBend(bend) => PrimitiveIndex::FixedBend(bend), GearIndex::LooseBend(bend) => PrimitiveIndex::LooseBend(bend), } } } impl From for GearIndex { fn from(bend: BendIndex) -> Self { match bend { BendIndex::Fixed(bend) => GearIndex::FixedBend(bend), BendIndex::Loose(bend) => GearIndex::LooseBend(bend), } } } #[enum_dispatch(GetOuterGears, WalkOutwards, GetDrawing, GetIndex)] pub enum GearRef<'a, CW, Cel, R> { FixedDot(FixedDotRef<'a, CW, Cel, R>), FixedBend(FixedBendRef<'a, CW, Cel, R>), LooseBend(LooseBendRef<'a, CW, Cel, R>), } impl<'a, CW, Cel, R> GearRef<'a, CW, Cel, R> { pub fn new(index: GearIndex, drawing: &'a Drawing) -> Self { match index { GearIndex::FixedDot(dot) => drawing.primitive_ref(dot).into(), GearIndex::FixedBend(bend) => drawing.primitive_ref(bend).into(), GearIndex::LooseBend(bend) => drawing.primitive_ref(bend).into(), } } } #[enum_dispatch] pub trait GetOuterGears { // TODO: This duplicates `.outers()` methods in some other places, we need // to merge them with this. // TODO: Use iterator instead of vec. fn outer_gears(&self) -> Vec; } #[enum_dispatch] pub trait WalkOutwards { fn outwards(&self) -> DrawingOutwardWalker; } /// I found it easier to just duplicate `OutwardWalker` for `Drawing<...>`. pub struct DrawingOutwardWalker { frontier: VecDeque, } impl DrawingOutwardWalker { pub fn new(initial_frontier: impl Iterator) -> Self { let mut frontier = VecDeque::new(); frontier.extend(initial_frontier); Self { frontier } } } impl Walker<&Drawing> for DrawingOutwardWalker { type Item = LooseBendIndex; fn walk_next(&mut self, drawing: &Drawing) -> Option { let front = self.frontier.pop_front()?; self.frontier.extend(drawing.primitive_ref(front).outers()); Some(front) } }