From 3f362d62c304a923109b839ac2e6f9b51fb03fda Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Fri, 13 Mar 2026 11:22:40 +0100 Subject: [PATCH] Wrap net ids in `NetId` type --- topola/src/board.rs | 11 +++++----- topola/src/layout.rs | 21 ++++++++++++++++++ topola/src/specctra.rs | 50 ++++++++++++++++++++++++++++++++++-------- 3 files changed, 68 insertions(+), 14 deletions(-) diff --git a/topola/src/board.rs b/topola/src/board.rs index ea3c104..31fc5ea 100644 --- a/topola/src/board.rs +++ b/topola/src/board.rs @@ -7,7 +7,8 @@ use derive_getters::{Dissolve, Getters}; use undoredo::{ApplyDelta, Delta, FlushDelta}; use crate::layout::{ - Joint, JointId, Layout, LayoutHalfDelta, Polygon, PolygonId, Segment, SegmentId, Via, ViaId, + Joint, JointId, Layout, LayoutHalfDelta, NetId, Polygon, PolygonId, Segment, SegmentId, Via, + ViaId, }; struct Layer { @@ -21,7 +22,7 @@ pub struct Board { #[getter(skip)] layer_names: BiBTreeMap, #[getter(skip)] - net_names: BiBTreeMap, + net_names: BiBTreeMap, } impl Board { @@ -37,7 +38,7 @@ impl Board { boundary: Vec<[i64; 2]>, layer_count: usize, layer_names: BiBTreeMap, - net_names: BiBTreeMap, + net_names: BiBTreeMap, ) -> Self { Self { layout: Layout::new(boundary, layer_count), @@ -70,11 +71,11 @@ impl Board { self.layer_names.get_by_right(name).copied() } - pub fn net_name(&self, net: usize) -> Option<&str> { + pub fn net_name(&self, net: NetId) -> Option<&str> { self.net_names.get_by_left(&net).map(String::as_str) } - pub fn net_id(&self, name: &str) -> Option { + pub fn net_id(&self, name: &str) -> Option { self.net_names.get_by_right(name).copied() } } diff --git a/topola/src/layout.rs b/topola/src/layout.rs index 230d294..56ffdaa 100644 --- a/topola/src/layout.rs +++ b/topola/src/layout.rs @@ -8,6 +8,23 @@ use derive_getters::{Dissolve, Getters}; use stable_vec::StableVec; use undoredo::{ApplyDelta, Delta, FlushDelta, Recorder}; +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub struct NetId(usize); + +impl NetId { + /// Wrap a joint index in a newtype struct. + #[inline] + pub fn new(id: usize) -> Self { + Self(id) + } + + /// Returns the underlying index. + #[inline] + pub fn id(self) -> usize { + self.0 + } +} + #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub struct JointId(usize); @@ -30,6 +47,7 @@ pub struct Joint { pub position: [i64; 2], pub layer: usize, pub radius: u64, + pub net: NetId, } #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] @@ -54,6 +72,7 @@ pub struct Segment { pub endjoints: [JointId; 2], pub layer: usize, pub half_width: u64, + pub net: NetId, } #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] @@ -78,6 +97,7 @@ pub struct Via { pub endpoints: [JointId; 2], pub layer: usize, pub radius: u64, + pub net: NetId, } #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] @@ -101,6 +121,7 @@ impl PolygonId { pub struct Polygon { pub vertices: Vec<[i64; 2]>, pub layer: usize, + pub net: NetId, } #[derive(Clone, Debug, Getters)] diff --git a/topola/src/specctra.rs b/topola/src/specctra.rs index 8a7d8e3..0c57e1a 100644 --- a/topola/src/specctra.rs +++ b/topola/src/specctra.rs @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: MIT OR Apache-2.0 +use std::collections::BTreeMap; + use bimap::BiBTreeMap; use specctra::{ math::PointWithRotation, @@ -11,7 +13,7 @@ use specctra::{ use crate::{ Segment, board::Board, - layout::{Joint, Polygon}, + layout::{Joint, NetId, Polygon}, math::Vector2, }; @@ -40,7 +42,12 @@ impl Board { tmp.sort_unstable(); tmp.dedup(); - BiBTreeMap::from_iter(tmp.into_iter().cloned().enumerate()) + BiBTreeMap::from_iter( + tmp.into_iter() + .cloned() + .enumerate() + .map(|(i, v)| (NetId::new(i), v)), + ) }; let mut board = Board::with_names( @@ -60,14 +67,14 @@ impl Board { ); // Mapping of pin -> net prepared for adding pins. - let pin_nets = dsn + let pin_nets: BTreeMap = dsn .pcb .network .nets .iter() .filter_map(|net_pin_assignments| { // Resolve the id so we don't work with strings. - let net = board.net_id(&net_pin_assignments.name); + let net = board.net_id(&net_pin_assignments.name).unwrap(); net_pin_assignments.pins.as_ref().map(|pins| { // Take the list of pins @@ -76,7 +83,8 @@ impl Board { }) }) // Flatten the nested iters into a single stream of tuples. - .flatten(); + .flatten() + .collect(); // Add pins from components. for component in &dsn.pcb.placement.components { @@ -95,6 +103,8 @@ impl Board { }; for pin in &image.pins { + let pin_name = format!("{}-{}", place.name, pin.id); + let net = pin_nets.get(&pin_name).copied().unwrap(); let padstack = dsn.pcb.library.find_padstack_by_name(&pin.name).unwrap(); for shape in padstack.shapes.iter() { @@ -107,6 +117,7 @@ impl Board { pin.point_with_rotation(), (circle.diameter / 2.0) as u64, layer, + net, !place_side_is_front, ) } @@ -121,6 +132,7 @@ impl Board { rect.x2, rect.y2, layer, + net, !place_side_is_front, ) } @@ -133,6 +145,7 @@ impl Board { &path.coords, path.width, layer, + net, !place_side_is_front, ) } @@ -145,6 +158,7 @@ impl Board { &polygon.coords, polygon.width, layer, + net, !place_side_is_front, ) } @@ -155,7 +169,7 @@ impl Board { } for via in &dsn.pcb.wiring.vias { - let net = board.net_id(&via.net); + let net = board.net_id(&via.net).unwrap(); let padstack = dsn.pcb.library.find_padstack_by_name(&via.name).unwrap(); let get_layer = |board: &Board, name: &str| { @@ -172,6 +186,7 @@ impl Board { PointWithRotation::default(), (circle.diameter / 2.0) as u64, layer, + net, false, ) } @@ -186,6 +201,7 @@ impl Board { rect.x2, rect.y2, layer, + net, false, ) } @@ -198,6 +214,7 @@ impl Board { &path.coords, path.width, layer, + net, false, ) } @@ -210,6 +227,7 @@ impl Board { &polygon.coords, polygon.width, layer, + net, false, ) } @@ -219,7 +237,7 @@ impl Board { for wire in dsn.pcb.wiring.wires.iter() { let layer = board.layer_id(&wire.path.layer).unwrap(); - let net = board.net_id(&wire.net); + let net = board.net_id(&wire.net).unwrap(); Self::place_path( &mut board, @@ -228,6 +246,7 @@ impl Board { &wire.path.coords, wire.path.width, layer, + net, false, ); } @@ -241,11 +260,13 @@ impl Board { pin: PointWithRotation, radius: u64, layer: usize, + net: NetId, flip: bool, ) { board.add_joint(Joint { position: Self::pos(place, pin, 0.0, 0.0, flip), layer, + net, radius, }); } @@ -259,6 +280,7 @@ impl Board { x2: f64, y2: f64, layer: usize, + net: NetId, flip: bool, ) { board.add_polygon(Polygon { @@ -269,6 +291,7 @@ impl Board { Self::pos(place, pin, x1, y2, flip), ], layer, + net, }); } @@ -279,6 +302,7 @@ impl Board { coords: &[Point], width: f64, layer: usize, + net: NetId, flip: bool, ) { // Add the first coordinate in the wire path as a dot and save its index. @@ -287,6 +311,7 @@ impl Board { position: prev_pos, layer, radius: (width / 2.0) as u64, + net, }); // Iterate through path coords starting from the second. @@ -299,8 +324,9 @@ impl Board { let joint = board.add_joint(Joint { position: pos, - radius: (width / 2.0) as u64, layer, + radius: (width / 2.0) as u64, + net, }); // Add a seg between the current and previous coords. @@ -308,6 +334,7 @@ impl Board { endjoints: [prev_joint, joint], layer, half_width: (width / 2.0) as u64, + net, }); prev_pos = pos; @@ -322,13 +349,18 @@ impl Board { coords: &[Point], width: f64, layer: usize, + net: NetId, flip: bool, ) { let vertices: Vec<[i64; 2]> = coords .iter() .map(|coord| Self::pos(place, pin, coord.x, coord.y, flip)) .collect(); - board.add_polygon(Polygon { vertices, layer }); + board.add_polygon(Polygon { + vertices, + layer, + net, + }); } fn layer(board: &Board, layers: &[Layer], name: &str, front: bool) -> usize {