From 6bbbc368c63dfeefb5987d955d24940ed823570d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Cicho=C5=84?= Date: Fri, 8 Mar 2024 05:06:00 +0100 Subject: [PATCH] dsn: refactor the parser/serializer to allow enums This cleans up and defines new types in structure.rs as well. --- src/bin/topola-sdl2-demo/main.rs | 2 + src/dsn/de.rs | 356 +++++++++++++++---------------- src/dsn/design.rs | 77 +++---- src/dsn/rules.rs | 12 +- src/dsn/structure.rs | 199 +++++++---------- 5 files changed, 304 insertions(+), 342 deletions(-) diff --git a/src/bin/topola-sdl2-demo/main.rs b/src/bin/topola-sdl2-demo/main.rs index 48d2196..67c805c 100644 --- a/src/bin/topola-sdl2-demo/main.rs +++ b/src/bin/topola-sdl2-demo/main.rs @@ -246,6 +246,8 @@ fn main() -> Result<(), anyhow::Error> { ((4, 3), 15.0), ]), }));*/ + + //let design = DsnDesign::load_from_file("tests/data/prerouted_lm317_breakout/prerouted_lm317_breakout.dsn")?; let design = DsnDesign::load_from_file("tests/data/test/test.dsn")?; //dbg!(&design); let layout = design.make_layout(); diff --git a/src/dsn/de.rs b/src/dsn/de.rs index 80df094..7cdaeb9 100644 --- a/src/dsn/de.rs +++ b/src/dsn/de.rs @@ -1,6 +1,6 @@ use std::fmt; -use serde::de::{self, DeserializeSeed, SeqAccess, Visitor}; +use serde::de::{self, DeserializeSeed, SeqAccess, EnumAccess, VariantAccess, Visitor}; use serde::Deserialize; use thiserror::Error; @@ -20,10 +20,12 @@ pub enum DsnDeError { SpaceInQuoted, #[error("expected unquoted string")] ExpectedUnquoted, - #[error("expected opening parenthesis")] - ExpectedOpeningParen, - #[error("expected closing parenthesis")] - ExpectedClosingParen, + #[error("expected opening parenthesis for {0}")] + ExpectedOpeningParen(&'static str), + #[error("expected closing parenthesis for {0}")] + ExpectedClosingParen(&'static str), + #[error("expected a keyword")] + ExpectedKeyword, #[error("wrong keyword: expected {0}, got {1}")] WrongKeyword(&'static str, String), } @@ -54,8 +56,8 @@ pub struct Deserializer<'de> { space_in_quoted_tokens: bool, reconfig_incoming: Option, + vec_type: Option<&'static str>, next_option_empty_hint: bool, - last_deserialized_type: Option<&'static str>, } #[derive(PartialEq, Debug, Copy, Clone)] @@ -74,20 +76,20 @@ impl<'de> Deserializer<'de> { space_in_quoted_tokens: false, reconfig_incoming: None, + vec_type: None, next_option_empty_hint: false, - last_deserialized_type: None, } } - fn next_name_lookahead(&self) -> Option { + fn keyword_lookahead(&self) -> Option { let mut iter = self.input.chars(); - if iter.next() != Some('(') { - None - } else { - Some( - iter.take_while(|c| c != &' ' && c != &'\r' && c != &'\n') - .collect::(), + if let Some('(') = iter.next() { + Some(iter + .take_while(|c| c != &' ' && c != &'\r' && c != &'\n') + .collect::() ) + } else { + None } } @@ -97,7 +99,7 @@ impl<'de> Deserializer<'de> { fn next(&mut self) -> Result { let chr = self.peek()?; - self.input = &self.input[1..]; + self.input = &self.input[chr.len_utf8()..]; if chr == '\n' { self.context.line += 1; self.context.column = 0; @@ -115,11 +117,11 @@ impl<'de> Deserializer<'de> { self.next().unwrap(); } } - return; } fn parse_bool(&mut self) -> Result { - match &self.parse_identifier() { + self.skip_ws(); + match &self.parse_unquoted() { Ok(string) => match string.as_str() { "on" => Ok(true), "off" => Ok(false), @@ -129,11 +131,13 @@ impl<'de> Deserializer<'de> { } } - fn parse_identifier(&mut self) -> Result { + fn parse_keyword(&mut self) -> Result { + self.skip_ws(); self.parse_unquoted() } fn parse_string(&mut self) -> Result { + self.skip_ws(); let chr = self.peek()?; if self.string_quote == Some(chr) { self.parse_quoted() @@ -184,7 +188,7 @@ impl<'de> Deserializer<'de> { } } -/*pub fn from_str<'a, T>(input: &'a str) -> Result +pub fn from_str<'a, T>(input: &'a str) -> Result where T: Deserialize<'a>, { @@ -195,7 +199,7 @@ where dbg!(deserializer.input); }*/ Ok(t) -}*/ +} impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { type Error = DsnDeError; @@ -211,17 +215,17 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { where V: Visitor<'de>, { - let value = self.parse_bool()?; self.skip_ws(); + let value = self.parse_bool()?; - // if the struct deserializer set a variable saying the incoming value should reconfigure a specific variable in the parser - // we do so and clear the flag + // If the struct deserializer set a variable saying the incoming value + // should reconfigure a specific variable in the parser we do so and + // clear the flag. if self.reconfig_incoming == Some(ReconfigIncoming::SpaceAllowed) { self.space_in_quoted_tokens = value; self.reconfig_incoming = None; } - self.last_deserialized_type = Some(""); visitor.visit_bool(value) } @@ -241,10 +245,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { where V: Visitor<'de>, { - let value = self.parse_unquoted()?; self.skip_ws(); + let value = self.parse_unquoted()?; - self.last_deserialized_type = Some(""); visitor.visit_i32(value.parse().unwrap()) } fn deserialize_i64(self, _visitor: V) -> Result @@ -269,26 +272,27 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { where V: Visitor<'de>, { - let value = self.parse_unquoted()?; self.skip_ws(); + let value = self.parse_unquoted()?; - self.last_deserialized_type = Some(""); visitor.visit_u32(value.parse().unwrap()) } - fn deserialize_u64(self, _visitor: V) -> Result + fn deserialize_u64(self, visitor: V) -> Result where V: Visitor<'de>, { - todo!(); + self.skip_ws(); + let value = self.parse_unquoted()?; + + visitor.visit_u64(value.parse().unwrap()) } fn deserialize_f32(self, visitor: V) -> Result where V: Visitor<'de>, { - let value = self.parse_unquoted()?; self.skip_ws(); + let value = self.parse_unquoted()?; - self.last_deserialized_type = Some(""); visitor.visit_f32(value.parse().unwrap()) } fn deserialize_f64(self, _visitor: V) -> Result @@ -301,17 +305,17 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { where V: Visitor<'de>, { - let chr = self.next()?; self.skip_ws(); + let chr = self.next()?; - // if the struct deserializer set a variable saying the incoming value should reconfigure a specific variable in the parser - // we do so and clear the flag + // If the struct deserializer set a variable saying the incoming value + // should reconfigure a specific variable in the parser we do so and + // clear the flag. if self.reconfig_incoming == Some(ReconfigIncoming::StringQuote) { self.string_quote = Some(chr); self.reconfig_incoming = None; } - self.last_deserialized_type = Some(""); visitor.visit_char(chr) } @@ -326,11 +330,10 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { where V: Visitor<'de>, { - let string = self.parse_string()?; self.skip_ws(); + let value = self.parse_string()?; - self.last_deserialized_type = Some(""); - visitor.visit_string(string) + visitor.visit_string(value) } fn deserialize_bytes(self, _visitor: V) -> Result @@ -365,75 +368,29 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { todo!(); } - fn deserialize_unit_struct(self, name: &'static str, visitor: V) -> Result + fn deserialize_unit_struct(self, _name: &'static str, _visitor: V) -> Result where V: Visitor<'de>, { - if self.next()? != '(' { - return Err(DsnDeError::ExpectedOpeningParen); - } - self.skip_ws(); - - let parsed_keyword = self.parse_identifier()?; - - if parsed_keyword != name { - return Err(DsnDeError::WrongKeyword(name, parsed_keyword)); - } - self.skip_ws(); - - if self.next()? != ')' { - return Err(DsnDeError::ExpectedClosingParen); - } - self.skip_ws(); - - self.last_deserialized_type = Some(name); - - visitor.visit_unit() + todo!(); } - fn deserialize_newtype_struct(self, name: &'static str, visitor: V) -> Result + fn deserialize_newtype_struct(self, _name: &'static str, _visitor: V) -> Result where V: Visitor<'de>, { - if self.next()? != '(' { - return Err(DsnDeError::ExpectedOpeningParen); - } - self.skip_ws(); - - let parsed_keyword = self.parse_identifier()?; - - if parsed_keyword != name { - return Err(DsnDeError::WrongKeyword(name, parsed_keyword)); - } - self.skip_ws(); - - // if what we're deserializing is a directive to update parser configuration - // set a variable so the deserializer for the following value can update the relevant config - // (the variable is reset to None by the bool/char deserializer when it updates the config) - self.reconfig_incoming = match name { - "string_quote" => Some(ReconfigIncoming::StringQuote), - "space_in_quoted_tokens" => Some(ReconfigIncoming::SpaceAllowed), - _ => None, - }; - - let value = visitor.visit_seq(NewtypeStructFields::new(self))?; - - if self.next()? != ')' { - return Err(DsnDeError::ExpectedClosingParen); - } - self.skip_ws(); - - self.last_deserialized_type = Some(name); - - Ok(value) + todo!(); } fn deserialize_seq(self, visitor: V) -> Result where V: Visitor<'de>, { - self.last_deserialized_type = None; - visitor.visit_seq(ArrayIndices::new(self)) + let elem_type = self.vec_type.expect( + "fields of type Vec<_> need to have names suffixed with _vec" + ); + + visitor.visit_seq(ArrayIndices::new(self, elem_type)) } fn deserialize_tuple(self, _len: usize, _visitor: V) -> Result @@ -464,55 +421,46 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { fn deserialize_struct( self, - name: &'static str, + _name: &'static str, fields: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { - if self.next()? != '(' { - return Err(DsnDeError::ExpectedOpeningParen); - } - self.skip_ws(); - - let parsed_keyword = self.parse_identifier()?; - - if parsed_keyword != name { - return Err(DsnDeError::WrongKeyword(name, parsed_keyword)); - } - self.skip_ws(); - - let value = visitor.visit_seq(StructFields::new(self, fields))?; - - if self.next()? != ')' { - return Err(DsnDeError::ExpectedClosingParen); - } - self.skip_ws(); - - // a hint for the array deserializer - self.last_deserialized_type = Some(name); - - Ok(value) + visitor.visit_seq(StructFields::new(self, fields)) } fn deserialize_enum( self, - _name: &'static str, + name: &'static str, _variants: &'static [&'static str], - _visitor: V, + visitor: V, ) -> Result where V: Visitor<'de>, { - todo!(); + self.skip_ws(); + if self.next()? != '(' { + return Err(DsnDeError::ExpectedOpeningParen("an enum variant")); + } + + let value = visitor.visit_enum(Enum::new(self))?; + + self.skip_ws(); + if self.next()? != ')' { + return Err(DsnDeError::ExpectedClosingParen(name)); + } + + Ok(value) } fn deserialize_identifier(self, visitor: V) -> Result where V: Visitor<'de>, { - visitor.visit_string(self.parse_string()?) + self.skip_ws(); + visitor.visit_string(self.parse_string().map_err(|err| DsnDeError::ExpectedKeyword)?) } fn deserialize_ignored_any(self, _visitor: V) -> Result @@ -523,38 +471,69 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { } } -struct NewtypeStructFields<'a, 'de: 'a> { +struct Enum<'a, 'de: 'a> { de: &'a mut Deserializer<'de>, } -impl<'a, 'de> NewtypeStructFields<'a, 'de> { +impl<'a, 'de> Enum<'a, 'de> { fn new(de: &'a mut Deserializer<'de>) -> Self { - Self { de } + Enum { de } } } -impl<'de, 'a> SeqAccess<'de> for NewtypeStructFields<'a, 'de> { +impl<'de, 'a> EnumAccess<'de> for Enum<'a, 'de> { + type Error = DsnDeError; + type Variant = Self; + + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant)> + where + V: DeserializeSeed<'de>, + { + seed.deserialize(&mut *self.de).map(|value| (value, self)) + } +} + +impl<'de, 'a> VariantAccess<'de> for Enum<'a, 'de> { type Error = DsnDeError; - fn next_element_seed(&mut self, seed: S) -> Result> - where - S: DeserializeSeed<'de>, - { - if self.de.peek()? == ')' { - return Ok(None); - } + fn unit_variant(self) -> Result<()> { + todo!(); + } - seed.deserialize(&mut *self.de).map(Some) + fn newtype_variant_seed(self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + seed.deserialize(self.de) + } + + fn tuple_variant(self, _len: usize, _visitor: V) -> Result + where + V: Visitor<'de>, + { + todo!(); + } + + fn struct_variant( + self, + _fields: &'static [&'static str], + _visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + todo!(); } } struct ArrayIndices<'a, 'de: 'a> { de: &'a mut Deserializer<'de>, + elem_type: &'static str, } impl<'a, 'de> ArrayIndices<'a, 'de> { - fn new(de: &'a mut Deserializer<'de>) -> Self { - Self { de } + fn new(de: &'a mut Deserializer<'de>, elem_type: &'static str) -> Self { + Self { de, elem_type } } } @@ -565,22 +544,35 @@ impl<'de, 'a> SeqAccess<'de> for ArrayIndices<'a, 'de> { where S: DeserializeSeed<'de>, { + self.de.skip_ws(); if self.de.peek()? == ')' { return Ok(None); } - if let Some(prev) = self.de.last_deserialized_type { - if let Some(lookahead) = self.de.next_name_lookahead() { - if prev != lookahead { - // the next struct is of different type from the array contents - // that means the array implicitly ended - // and we're looking at a field following the array instead - return Ok(None); + if self.de.peek()? != '(' { + // anonymous field + seed.deserialize(&mut *self.de).map(Some) + } else { + let lookahead = self.de.keyword_lookahead().ok_or( + DsnDeError::ExpectedOpeningParen(self.elem_type) + )?; + if lookahead == self.elem_type { + // cannot fail, consuming the lookahead + self.de.next().unwrap(); + self.de.parse_keyword().unwrap(); + + let value = seed.deserialize(&mut *self.de)?; + + self.de.skip_ws(); + if self.de.next()? != ')' { + Err(DsnDeError::ExpectedClosingParen(self.elem_type)) + } else { + Ok(Some(value)) } + } else { + Ok(None) } } - - seed.deserialize(&mut *self.de).map(Some) } } @@ -607,43 +599,49 @@ impl<'de, 'a> SeqAccess<'de> for StructFields<'a, 'de> { where S: DeserializeSeed<'de>, { - if self.de.peek()? == ')' { - if self.current_field < self.fields.len() { - // We're short a field (or multiple), - // but the trailing field(s) might be optional and implicitly absent. - // In that case we prepare a hint for deserialize_option to emit None: - self.de.next_option_empty_hint = true; - // and we tell serde to deserialize a field that may or may not be there: - self.current_field += 1; - return seed.deserialize(&mut *self.de).map(Some); - // If it was a non-optional that was missing for real, - // then even though our bet here was wrong (and we just lied to serde) - // the deserializer we handed off to will see the same closing paren - // (that we reacted to just now) and still return a sensible error. - } else { - return Ok(None); - } - } + let field_name = self.fields[self.current_field]; - // check if the next field is "named" - // (saved as `(fieldname value)`) - if let Some(lookahead) = self.de.next_name_lookahead() { - if lookahead != self.fields[self.current_field] { - if lookahead + "s" != self.fields[self.current_field] { - self.de.next_option_empty_hint = true; - } else { - self.de.next_option_empty_hint = false; - } - } else { - self.de.next_option_empty_hint = false; - } + self.de.skip_ws(); + + let ret = if field_name.ends_with("_vec") { + self.de.vec_type = field_name.strip_suffix("_vec"); + let value = seed.deserialize(&mut *self.de).map(Some); + self.de.vec_type = None; + + value } else { - // optional fields must be "named" - // if we see something else assume empty option - self.de.next_option_empty_hint = true; - } + if self.de.peek()? != '(' { + // anonymous field, cannot be optional + self.de.next_option_empty_hint = true; + let value = seed.deserialize(&mut *self.de).map(Some); + self.de.next_option_empty_hint = false; + value + } else { + self.de.next()?; // consume the '(' + + let parsed_keyword = self.de.parse_keyword()?; + if parsed_keyword == field_name { + if field_name == "string_quote" { + self.de.reconfig_incoming = Some(ReconfigIncoming::StringQuote); + } else if field_name == "space_in_quoted_tokens" { + self.de.reconfig_incoming = Some(ReconfigIncoming::SpaceAllowed); + } + + let value = seed.deserialize(&mut *self.de)?; + + self.de.skip_ws(); + if self.de.next()? != ')' { + Err(DsnDeError::ExpectedClosingParen(field_name)) + } else { + Ok(Some(value)) + } + } else { + Err(DsnDeError::WrongKeyword(field_name, parsed_keyword)) + } + } + }; self.current_field += 1; - seed.deserialize(&mut *self.de).map(Some) + ret } } diff --git a/src/dsn/design.rs b/src/dsn/design.rs index d94a95b..5e56ccc 100644 --- a/src/dsn/design.rs +++ b/src/dsn/design.rs @@ -11,7 +11,7 @@ use crate::{ use super::{ de::{Deserializer, DsnContext, DsnDeError}, rules::Rules, - structure::Pcb, + structure::{DsnFile, Pcb, Shape}, }; #[derive(Error, Debug)] @@ -34,8 +34,8 @@ impl DsnDesign { let contents = std::fs::read_to_string(filename).unwrap(); // TODO: remove unwrap. //let pcb = from_str::(&contents).map_err(|err| DsnError())?; let mut deserializer = Deserializer::from_str(&contents); - let pcb = Pcb::deserialize(&mut deserializer) - .map_err(|err| DsnError(deserializer.context, err))?; + let pcb = DsnFile::deserialize(&mut deserializer) + .map_err(|err| DsnError(deserializer.context, err))?.pcb; let rules = Rules::from_pcb(&pcb); @@ -46,50 +46,51 @@ impl DsnDesign { let mut layout = Layout::new(&self.rules); // mapping of pin id -> net id prepared for adding pins - let pin_nets = if let Some(nets) = self.pcb.network.nets.as_ref() { - HashMap::::from_iter( - nets.iter() - .map(|net| { - // resolve the id so we don't work with strings - let net_id = self.rules.net_ids.get(&net.name).unwrap(); + let pin_nets = HashMap::::from_iter( + self.pcb.network.net_vec + .iter() + .map(|net| { + // resolve the id so we don't work with strings + let net_id = self.rules.net_ids.get(&net.name).unwrap(); - // take the list of pins - // and for each pin id output (pin id, net id) - net.pins.ids.iter().map(|id| (id.clone(), *net_id)) - }) - // flatten the nested iters into a single stream of tuples - .flatten(), - ) - } else { - HashMap::::new() - }; + // take the list of pins + // and for each pin id output (pin id, net id) + net.pins.names.iter().map(|id| (id.clone(), *net_id)) + }) + // flatten the nested iters into a single stream of tuples + .flatten(), + ); // add pins from components - //self.pcb.placement.components.iter().map(|component| { - for component in &self.pcb.placement.components { - for place in &component.places { + for component in &self.pcb.placement.component_vec { + for place in &component.place_vec { let image = self .pcb .library - .images + .image_vec .iter() .find(|image| image.name == component.name) .unwrap(); - for pin in &image.pins { + for pin in &image.pin_vec { let pin_name = format!("{}-{}", place.name, pin.id); let net_id = pin_nets.get(&pin_name).unwrap(); let padstack = &self .pcb .library - .padstacks + .padstack_vec .iter() .find(|padstack| padstack.name == pin.name) .unwrap(); // no layer support yet, pick the first one - let circle = &padstack.shapes[0].0; + let circle = match &padstack.shape_vec[0] { + Shape::Circle(circle) => circle, + Shape::Rect(_) => todo!(), + Shape::Path(_) => todo!(), + Shape::Polygon(_) => todo!(), + }; let circle = Circle { pos: (place.x as f64 / 100.0, -place.y as f64 / 100.0).into(), r: circle.diameter as f64 / 200.0, @@ -104,28 +105,32 @@ impl DsnDesign { } } } - //}) // add vias to layout and save indices of dots in the order they appear in the file let _dot_indices: Vec<_> = self .pcb .wiring - .vias + .via_vec .iter() .map(|via| { - let net_id = self.rules.net_ids.get(&via.net.0).unwrap(); + let net_id = self.rules.net_ids.get(&via.net).unwrap(); // find the padstack referenced by this via placement let padstack = &self .pcb .library - .padstacks + .padstack_vec .iter() .find(|padstack| padstack.name == via.name) .unwrap(); // no layer support yet, pick the first one - let circle = &padstack.shapes[0].0; + let circle = match &padstack.shape_vec[0] { + Shape::Circle(circle) => circle, + Shape::Rect(_) => todo!(), + Shape::Path(_) => todo!(), + Shape::Polygon(_) => todo!(), + }; let circle = Circle { pos: (via.x as f64 / 100.0, -via.y as f64 / 100.0).into(), r: circle.diameter as f64 / 200.0, @@ -140,8 +145,8 @@ impl DsnDesign { }) .collect(); - for wire in self.pcb.wiring.wires.iter() { - let net_id = self.rules.net_ids.get(&wire.net.0).unwrap(); + for wire in self.pcb.wiring.wire_vec.iter() { + let net_id = self.rules.net_ids.get(&wire.net).unwrap(); // add the first coordinate in the wire path as a dot and save its index let mut prev_index = layout @@ -149,8 +154,8 @@ impl DsnDesign { net: *net_id as i64, circle: Circle { pos: ( - wire.path.coords[0].x as f64 / 100.0, - -wire.path.coords[0].y as f64 / 100.0, + wire.path.coord_vec[0].x as f64 / 100.0, + -wire.path.coord_vec[0].y as f64 / 100.0, ) .into(), r: wire.path.width as f64 / 200.0, @@ -159,7 +164,7 @@ impl DsnDesign { .unwrap(); // iterate through path coords starting from the second - for coord in wire.path.coords.iter().skip(1) { + for coord in wire.path.coord_vec.iter().skip(1) { let index = layout .add_fixed_dot(FixedDotWeight { net: *net_id as i64, diff --git a/src/dsn/rules.rs b/src/dsn/rules.rs index c390058..50ed3f6 100644 --- a/src/dsn/rules.rs +++ b/src/dsn/rules.rs @@ -13,8 +13,8 @@ pub struct Rule { impl Rule { fn from_dsn(rule: &super::structure::Rule) -> Self { Self { - width: rule.width.0 as f64 / 100.0, - clearance: rule.clearances[0].value as f64 / 100.0, // picks the generic clearance only for now + width: rule.width as f64 / 100.0, + clearance: rule.clearance_vec[0].value as f64 / 100.0, // picks the generic clearance only for now } } } @@ -36,9 +36,9 @@ impl Rules { // keeping this as a separate iter pass because it might be moved into a different struct later? let net_ids = HashMap::from_iter( pcb.network - .classes + .class_vec .iter() - .flat_map(|class| &class.nets) + .flat_map(|class| &class.net_vec) .enumerate() .map(|(id, net)| (net.clone(), id as i64)), ); @@ -46,10 +46,10 @@ impl Rules { let mut net_id_classes = HashMap::new(); let class_rules = HashMap::from_iter( pcb.network - .classes + .class_vec .iter() .inspect(|class| { - for net in &class.nets { + for net in &class.net_vec { let net_id = net_ids.get(net).unwrap(); net_id_classes.insert(*net_id, class.name.clone()); } diff --git a/src/dsn/structure.rs b/src/dsn/structure.rs index 6f397a0..ba9a8db 100644 --- a/src/dsn/structure.rs +++ b/src/dsn/structure.rs @@ -1,12 +1,16 @@ use serde::{de::Error, Deserialize, Deserializer}; #[derive(Deserialize, Debug)] -#[serde(rename = "pcb")] +pub struct DsnFile { + pub pcb: Pcb, +} + +#[derive(Deserialize, Debug)] pub struct Pcb { pub name: String, pub parser: Parser, pub resolution: Resolution, - pub unit: Option, + pub unit: String, pub structure: Structure, pub placement: Placement, pub library: Library, @@ -15,183 +19,141 @@ pub struct Pcb { } #[derive(Deserialize, Debug)] -#[serde(rename = "parser")] pub struct Parser { - pub string_quote: Option, - pub space_in_quoted_tokens: SpaceAllowed, - pub host_cad: Option, - pub host_version: Option, + pub string_quote: Option, + pub space_in_quoted_tokens: Option, + pub host_cad: Option, + pub host_version: Option, } -#[derive(Deserialize, Debug, Clone, Copy, PartialEq)] -#[serde(rename = "string_quote")] -pub struct StringQuote(pub char); - -#[derive(Deserialize, Debug, Clone, Copy, PartialEq)] -#[serde(rename = "space_in_quoted_tokens")] -pub struct SpaceAllowed(pub bool); - #[derive(Deserialize, Debug)] -#[serde(rename = "host_cad")] -pub struct HostCad(pub String); - -#[derive(Deserialize, Debug)] -#[serde(rename = "host_version")] -pub struct HostVersion(pub String); - -#[derive(Deserialize, Debug)] -#[serde(rename = "resolution")] pub struct Resolution { pub unit: String, pub value: u32, } #[derive(Deserialize, Debug)] -#[serde(rename = "unit")] -pub struct Unit(pub String); - -#[derive(Deserialize, Debug)] -#[serde(rename = "structure")] pub struct Structure { - pub layers: Vec, + pub layer_vec: Vec, pub boundary: Boundary, - pub plane: Vec, - pub vias: Vias, + pub plane_vec: Vec, + pub via: ViaNames, pub rule: Rule, } #[derive(Deserialize, Debug)] -#[serde(rename = "layer")] pub struct Layer { pub name: String, - pub r#type: Type, + pub r#type: String, pub property: Property, } #[derive(Deserialize, Debug)] -#[serde(rename = "property")] -pub struct Property(Index); +pub struct Property { + pub index: usize, +} #[derive(Deserialize, Debug)] -#[serde(rename = "index")] -pub struct Index(pub u32); +pub struct Boundary { + pub path: Path, +} #[derive(Deserialize, Debug)] -#[serde(rename = "boundary")] -pub struct Boundary(pub Path); - -#[derive(Deserialize, Debug)] -#[serde(rename = "plane")] pub struct Plane { - net: String, - shape: Polygon, + pub net: String, + pub polygon: Polygon, } #[derive(Deserialize, Debug)] -#[serde(rename = "via")] -pub struct Vias { - vias: Vec, +pub struct ViaNames { + pub name_vec: Vec, } #[derive(Deserialize, Debug)] -#[serde(rename = "placement")] pub struct Placement { - pub components: Vec, + pub component_vec: Vec, } #[derive(Deserialize, Debug)] -#[serde(rename = "component")] pub struct Component { pub name: String, - pub places: Vec, + pub place_vec: Vec, } #[derive(Deserialize, Debug)] -#[serde(rename = "place")] pub struct Place { pub name: String, pub x: f32, pub y: f32, pub side: String, pub rotation: f32, - pub PN: Option, + pub PN: Option, } #[derive(Deserialize, Debug)] -#[serde(rename = "PN")] -pub struct PN { - pub name: String, -} - -#[derive(Deserialize, Debug)] -#[serde(rename = "library")] pub struct Library { - pub images: Vec, - pub padstacks: Vec, + pub image_vec: Vec, + pub padstack_vec: Vec, } #[derive(Deserialize, Debug)] -#[serde(rename = "image")] pub struct Image { pub name: String, - pub outlines: Vec, - pub pins: Vec, + pub outline_vec: Vec, + pub pin_vec: Vec, } #[derive(Deserialize, Debug)] -#[serde(rename = "outline")] pub struct Outline { pub path: Path, } #[derive(Deserialize, Debug)] -#[serde(rename = "pin")] pub struct Pin { pub name: String, - pub rotate: Option, + pub rotate: Option, pub id: String, pub x: f32, pub y: f32, } #[derive(Deserialize, Debug)] -#[serde(rename = "rotate")] pub struct Rotate { pub angle: f32, } #[derive(Deserialize, Debug)] -#[serde(rename = "padstack")] pub struct Padstack { pub name: String, - pub shapes: Vec, - pub attach: Attach, + pub shape_vec: Vec, + pub attach: bool, } #[derive(Deserialize, Debug)] -#[serde(rename = "shape")] -pub struct Shape(pub Circle); +pub enum Shape { + #[serde(rename = "circle")] + Circle(Circle), + #[serde(rename = "rect")] + Rect(Rect), + #[serde(rename = "path")] + Path(Path), + #[serde(rename = "polygon")] + Polygon(Polygon), +} #[derive(Deserialize, Debug)] -#[serde(rename = "circle")] pub struct Circle { pub layer: String, pub diameter: u32, } #[derive(Deserialize, Debug)] -#[serde(rename = "attach")] -pub struct Attach(pub bool); - -#[derive(Deserialize, Debug)] -#[serde(rename = "network")] pub struct Network { - pub nets: Option>, - pub classes: Vec, + pub net_vec: Vec, + pub class_vec: Vec, } #[derive(Deserialize, Debug)] -#[serde(rename = "net")] // dsn names this "net", but it's a structure unrelated to "net" in wiring or elsewhere pub struct NetPinAssignments { pub name: String, @@ -199,57 +161,53 @@ pub struct NetPinAssignments { } #[derive(Deserialize, Debug)] -#[serde(rename = "pins")] pub struct Pins { - pub ids: Vec, + pub names: Vec, } #[derive(Deserialize, Debug)] -#[serde(rename = "class")] pub struct Class { pub name: String, - pub nets: Vec, + pub net_vec: Vec, pub circuit: Circuit, pub rule: Rule, } #[derive(Deserialize, Debug)] -#[serde(rename = "circuit")] -pub struct Circuit(pub UseVia); +pub struct Circuit { + pub use_via: UseVia, +} #[derive(Deserialize, Debug)] -#[serde(rename = "use_via")] pub struct UseVia { pub name: String, } #[derive(Deserialize, Debug)] -#[serde(rename = "wiring")] pub struct Wiring { - pub wires: Vec, - pub vias: Vec, + pub wire_vec: Vec, + pub via_vec: Vec, } #[derive(Deserialize, Debug)] -#[serde(rename = "wire")] pub struct Wire { pub path: Path, - pub net: Net, - pub r#type: Type, + pub net: String, + pub r#type: String, } // structs that appear in multiple places -#[derive(Deserialize, Debug)] -#[serde(rename = "type")] -pub struct Type(pub String); - +// This type isn't deserialized as is. Instead, Vec is converted from +// what's effectively Vec (with even length) in the file. +// Use #[serde(deserialize_with = "de_points")]. #[derive(Debug)] pub struct Point { pub x: f32, pub y: f32, } +// Used to deserialize Vec. fn de_points<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, @@ -257,7 +215,10 @@ where Vec::::deserialize(deserializer)? .chunks(2) .map(|pair| { + // 0th index is guaranteed to exist by `.chunks()` + // (it ends iteration instead of emitting an empty Vec) let x = pair[0]; + // but if the file is malformed we may get an odd number of floats let y = *pair.get(1).ok_or(Error::custom( "expected paired x y coordinates, list ended at x", ))?; @@ -268,51 +229,47 @@ where } #[derive(Deserialize, Debug)] -#[serde(rename = "polygon")] pub struct Polygon { pub layer: String, pub width: f32, #[serde(deserialize_with = "de_points")] - pub coords: Vec, + pub coord_vec: Vec, } #[derive(Deserialize, Debug)] -#[serde(rename = "path")] pub struct Path { pub layer: String, pub width: f32, #[serde(deserialize_with = "de_points")] - pub coords: Vec, + pub coord_vec: Vec, +} + +#[derive(Deserialize, Debug)] +pub struct Rect { + pub layer: String, + pub x1: f32, + pub y1: f32, + pub x2: f32, + pub y2: f32, } #[derive(Deserialize, Debug)] -#[serde(rename = "via")] pub struct Via { pub name: String, pub x: i32, pub y: i32, - pub net: Net, - pub r#type: Type, + pub net: String, + pub r#type: String, } #[derive(Deserialize, Debug)] -#[serde(rename = "rule")] pub struct Rule { - pub width: Width, - pub clearances: Vec, + pub width: f32, + pub clearance_vec: Vec, } #[derive(Deserialize, Debug)] -#[serde(rename = "net")] -pub struct Net(pub String); - -#[derive(Deserialize, Debug)] -#[serde(rename = "width")] -pub struct Width(pub f32); - -#[derive(Deserialize, Debug)] -#[serde(rename = "clearance")] pub struct Clearance { pub value: f32, - pub r#type: Option, + pub r#type: Option, }