dsn: refactor the parser/serializer to allow enums

This cleans up and defines new types in structure.rs as well.
This commit is contained in:
Tomasz Cichoń 2024-03-08 05:06:00 +01:00
parent 8a56a16528
commit 6bbbc368c6
5 changed files with 304 additions and 342 deletions

View File

@ -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();

View File

@ -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<ReconfigIncoming>,
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<String> {
fn keyword_lookahead(&self) -> Option<String> {
let mut iter = self.input.chars();
if iter.next() != Some('(') {
None
} else {
Some(
iter.take_while(|c| c != &' ' && c != &'\r' && c != &'\n')
.collect::<String>(),
if let Some('(') = iter.next() {
Some(iter
.take_while(|c| c != &' ' && c != &'\r' && c != &'\n')
.collect::<String>()
)
} else {
None
}
}
@ -97,7 +99,7 @@ impl<'de> Deserializer<'de> {
fn next(&mut self) -> Result<char> {
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<bool> {
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<String> {
fn parse_keyword(&mut self) -> Result<String> {
self.skip_ws();
self.parse_unquoted()
}
fn parse_string(&mut self) -> Result<String> {
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<T>
pub fn from_str<'a, T>(input: &'a str) -> Result<T>
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<V>(self, _visitor: V) -> Result<V::Value>
@ -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<V>(self, _visitor: V) -> Result<V::Value>
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
todo!();
self.skip_ws();
let value = self.parse_unquoted()?;
visitor.visit_u64(value.parse().unwrap())
}
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
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<V>(self, _visitor: V) -> Result<V::Value>
@ -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<V>(self, _visitor: V) -> Result<V::Value>
@ -365,75 +368,29 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
todo!();
}
fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
fn deserialize_unit_struct<V>(self, _name: &'static str, _visitor: V) -> Result<V::Value>
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<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
fn deserialize_newtype_struct<V>(self, _name: &'static str, _visitor: V) -> Result<V::Value>
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<V>(self, visitor: V) -> Result<V::Value>
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<V>(self, _len: usize, _visitor: V) -> Result<V::Value>
@ -464,55 +421,46 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
fn deserialize_struct<V>(
self,
name: &'static str,
_name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
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<V>(
self,
_name: &'static str,
name: &'static str,
_variants: &'static [&'static str],
_visitor: V,
visitor: V,
) -> Result<V::Value>
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<V>(self, visitor: V) -> Result<V::Value>
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<V>(self, _visitor: V) -> Result<V::Value>
@ -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<V>(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<S>(&mut self, seed: S) -> Result<Option<S::Value>>
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<T>(self, seed: T) -> Result<T::Value>
where
T: DeserializeSeed<'de>,
{
seed.deserialize(self.de)
}
fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
todo!();
}
fn struct_variant<V>(
self,
_fields: &'static [&'static str],
_visitor: V,
) -> Result<V::Value>
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
}
}

View File

@ -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::<Pcb>(&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::<String, i64>::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::<String, i64>::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::<String, i64>::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,

View File

@ -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());
}

View File

@ -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<Unit>,
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<StringQuote>,
pub space_in_quoted_tokens: SpaceAllowed,
pub host_cad: Option<HostCad>,
pub host_version: Option<HostVersion>,
pub string_quote: Option<char>,
pub space_in_quoted_tokens: Option<bool>,
pub host_cad: Option<String>,
pub host_version: Option<String>,
}
#[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<Layer>,
pub layer_vec: Vec<Layer>,
pub boundary: Boundary,
pub plane: Vec<Plane>,
pub vias: Vias,
pub plane_vec: Vec<Plane>,
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<String>,
pub struct ViaNames {
pub name_vec: Vec<String>,
}
#[derive(Deserialize, Debug)]
#[serde(rename = "placement")]
pub struct Placement {
pub components: Vec<Component>,
pub component_vec: Vec<Component>,
}
#[derive(Deserialize, Debug)]
#[serde(rename = "component")]
pub struct Component {
pub name: String,
pub places: Vec<Place>,
pub place_vec: Vec<Place>,
}
#[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<PN>,
pub PN: Option<String>,
}
#[derive(Deserialize, Debug)]
#[serde(rename = "PN")]
pub struct PN {
pub name: String,
}
#[derive(Deserialize, Debug)]
#[serde(rename = "library")]
pub struct Library {
pub images: Vec<Image>,
pub padstacks: Vec<Padstack>,
pub image_vec: Vec<Image>,
pub padstack_vec: Vec<Padstack>,
}
#[derive(Deserialize, Debug)]
#[serde(rename = "image")]
pub struct Image {
pub name: String,
pub outlines: Vec<Outline>,
pub pins: Vec<Pin>,
pub outline_vec: Vec<Outline>,
pub pin_vec: Vec<Pin>,
}
#[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<Rotate>,
pub rotate: Option<f32>,
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<Shape>,
pub attach: Attach,
pub shape_vec: Vec<Shape>,
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<Vec<NetPinAssignments>>,
pub classes: Vec<Class>,
pub net_vec: Vec<NetPinAssignments>,
pub class_vec: Vec<Class>,
}
#[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<String>,
pub names: Vec<String>,
}
#[derive(Deserialize, Debug)]
#[serde(rename = "class")]
pub struct Class {
pub name: String,
pub nets: Vec<String>,
pub net_vec: Vec<String>,
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<Wire>,
pub vias: Vec<Via>,
pub wire_vec: Vec<Wire>,
pub via_vec: Vec<Via>,
}
#[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<Point> is converted from
// what's effectively Vec<f32> (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<Point>.
fn de_points<'de, D>(deserializer: D) -> Result<Vec<Point>, D::Error>
where
D: Deserializer<'de>,
@ -257,7 +215,10 @@ where
Vec::<f32>::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<Point>,
pub coord_vec: Vec<Point>,
}
#[derive(Deserialize, Debug)]
#[serde(rename = "path")]
pub struct Path {
pub layer: String,
pub width: f32,
#[serde(deserialize_with = "de_points")]
pub coords: Vec<Point>,
pub coord_vec: Vec<Point>,
}
#[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<Clearance>,
pub width: f32,
pub clearance_vec: Vec<Clearance>,
}
#[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<Type>,
pub r#type: Option<String>,
}