topola 0.1.0

Work-in-progress free and open-source topological (rubberband) router and autorouter for printed circuit boards (PCBs)
Documentation
// SPDX-FileCopyrightText: 2026 Topola contributors
//
// SPDX-License-Identifier: MIT OR Apache-2.0

use std::ops::ControlFlow;

use crate::{
    autoplacer::{
        AutoplacerSchedule,
        interactors::{AutoplacerMasterInteractor, JostlerMasterInteractor},
    },
    board::{
        Board,
        interactors::{BoardMasterInteractor, SelectInteractor},
        selections::PersistableSelection,
    },
    layout::LayerId,
    vector::Vector2,
};

pub trait Interactor {
    fn step(&mut self, _board: &mut Board) -> ControlFlow<()> {
        ControlFlow::Continue(())
    }
    fn delete(&mut self, board: &mut Board) {
        let _ = board;
    }
    fn press(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {
        let _ = (board, layer, pointer);
    }
    fn hold(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {
        let _ = (board, layer, pointer);
    }
    fn release(
        &mut self,
        board: &mut Board,
        layer: LayerId,
        pointer: Vector2<i64>,
    ) -> ControlFlow<()> {
        let _ = (board, layer, pointer);
        ControlFlow::Continue(())
    }
    fn abort(&mut self, board: &mut Board) {
        let _ = board;
    }
}

pub enum MasterInteractor {
    Board(BoardMasterInteractor),
    Autoplacer(AutoplacerMasterInteractor),
    Jostler(JostlerMasterInteractor),
}

impl MasterInteractor {
    pub fn new(board: &mut Board, selection: PersistableSelection) -> Self {
        Self::Jostler(JostlerMasterInteractor::new(
            board,
            BoardMasterInteractor::new(selection),
        ))
    }

    pub fn autoplace(&mut self, board: &mut Board, schedule: AutoplacerSchedule) {
        match self {
            Self::Board(board_master) => {
                *self = Self::Autoplacer(AutoplacerMasterInteractor::new(
                    board,
                    board_master.clone(),
                    schedule,
                ));
            }
            Self::Jostler(jostler_master) => {
                *self = Self::Autoplacer(AutoplacerMasterInteractor::new(
                    board,
                    jostler_master.board_master().clone(),
                    schedule,
                ));
            }
            _ => (),
        }
    }

    pub fn jostle(&mut self, board: &mut Board) {
        match self {
            Self::Board(board_master) => {
                *self = Self::Jostler(JostlerMasterInteractor::new(board, board_master.clone()));
            }
            _ => (),
        }
    }

    pub fn noclip(&mut self, board: &mut Board) {
        match self {
            Self::Jostler(jostler_master) => {
                *self = Self::Board(BoardMasterInteractor::new(
                    jostler_master.selection().clone(),
                ))
            }
            _ => (),
        }
    }

    pub fn selection(&self) -> &PersistableSelection {
        match self {
            Self::Board(board_master) => board_master.selection(),
            Self::Autoplacer(autoplacer_master) => autoplacer_master.selection(),
            Self::Jostler(jostler_master) => jostler_master.selection(),
        }
    }

    pub fn select_interactor(&self) -> &Option<SelectInteractor> {
        match self {
            Self::Board(board_master) => board_master.select_interactor(),
            Self::Autoplacer(autoplacer_master) => autoplacer_master.select_interactor(),
            Self::Jostler(jostler_master) => jostler_master.select_interactor(),
        }
    }
}

impl Interactor for MasterInteractor {
    fn step(&mut self, board: &mut Board) -> ControlFlow<()> {
        match self {
            Self::Board(interactor) => interactor.step(board),
            Self::Autoplacer(interactor) => {
                if interactor.step(board).is_break() {
                    *self = Self::Board(interactor.board_master().clone());
                    ControlFlow::Break(())
                } else {
                    ControlFlow::Continue(())
                }
            }
            Self::Jostler(interactor) => interactor.step(board),
        }
    }

    fn delete(&mut self, board: &mut Board) {
        match self {
            Self::Board(interactor) => interactor.delete(board),
            Self::Autoplacer(interactor) => interactor.delete(board),
            Self::Jostler(interactor) => interactor.delete(board),
        }
    }

    fn press(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {
        match self {
            Self::Board(interactor) => interactor.press(board, layer, pointer),
            Self::Autoplacer(interactor) => interactor.press(board, layer, pointer),
            Self::Jostler(interactor) => interactor.press(board, layer, pointer),
        }
    }

    fn hold(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {
        match self {
            Self::Board(interactor) => interactor.hold(board, layer, pointer),
            Self::Autoplacer(interactor) => interactor.hold(board, layer, pointer),
            Self::Jostler(interactor) => interactor.hold(board, layer, pointer),
        }
    }

    fn release(
        &mut self,
        board: &mut Board,
        layer: LayerId,
        pointer: Vector2<i64>,
    ) -> ControlFlow<()> {
        match self {
            Self::Board(interactor) => interactor.release(board, layer, pointer),
            Self::Autoplacer(interactor) => interactor.release(board, layer, pointer),
            Self::Jostler(interactor) => interactor.release(board, layer, pointer),
        }
    }

    fn abort(&mut self, board: &mut Board) {
        match self {
            Self::Board(interactor) => interactor.abort(board),
            Self::Autoplacer(interactor) => interactor.abort(board),
            Self::Jostler(interactor) => interactor.abort(board),
        }
    }
}