mirror of https://codeberg.org/topola/topola.git
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:
parent
8a56a16528
commit
6bbbc368c6
|
|
@ -246,6 +246,8 @@ fn main() -> Result<(), anyhow::Error> {
|
||||||
((4, 3), 15.0),
|
((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")?;
|
let design = DsnDesign::load_from_file("tests/data/test/test.dsn")?;
|
||||||
//dbg!(&design);
|
//dbg!(&design);
|
||||||
let layout = design.make_layout();
|
let layout = design.make_layout();
|
||||||
|
|
|
||||||
356
src/dsn/de.rs
356
src/dsn/de.rs
|
|
@ -1,6 +1,6 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use serde::de::{self, DeserializeSeed, SeqAccess, Visitor};
|
use serde::de::{self, DeserializeSeed, SeqAccess, EnumAccess, VariantAccess, Visitor};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
|
@ -20,10 +20,12 @@ pub enum DsnDeError {
|
||||||
SpaceInQuoted,
|
SpaceInQuoted,
|
||||||
#[error("expected unquoted string")]
|
#[error("expected unquoted string")]
|
||||||
ExpectedUnquoted,
|
ExpectedUnquoted,
|
||||||
#[error("expected opening parenthesis")]
|
#[error("expected opening parenthesis for {0}")]
|
||||||
ExpectedOpeningParen,
|
ExpectedOpeningParen(&'static str),
|
||||||
#[error("expected closing parenthesis")]
|
#[error("expected closing parenthesis for {0}")]
|
||||||
ExpectedClosingParen,
|
ExpectedClosingParen(&'static str),
|
||||||
|
#[error("expected a keyword")]
|
||||||
|
ExpectedKeyword,
|
||||||
#[error("wrong keyword: expected {0}, got {1}")]
|
#[error("wrong keyword: expected {0}, got {1}")]
|
||||||
WrongKeyword(&'static str, String),
|
WrongKeyword(&'static str, String),
|
||||||
}
|
}
|
||||||
|
|
@ -54,8 +56,8 @@ pub struct Deserializer<'de> {
|
||||||
space_in_quoted_tokens: bool,
|
space_in_quoted_tokens: bool,
|
||||||
reconfig_incoming: Option<ReconfigIncoming>,
|
reconfig_incoming: Option<ReconfigIncoming>,
|
||||||
|
|
||||||
|
vec_type: Option<&'static str>,
|
||||||
next_option_empty_hint: bool,
|
next_option_empty_hint: bool,
|
||||||
last_deserialized_type: Option<&'static str>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||||
|
|
@ -74,20 +76,20 @@ impl<'de> Deserializer<'de> {
|
||||||
space_in_quoted_tokens: false,
|
space_in_quoted_tokens: false,
|
||||||
reconfig_incoming: None,
|
reconfig_incoming: None,
|
||||||
|
|
||||||
|
vec_type: None,
|
||||||
next_option_empty_hint: false,
|
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();
|
let mut iter = self.input.chars();
|
||||||
if iter.next() != Some('(') {
|
if let Some('(') = iter.next() {
|
||||||
None
|
Some(iter
|
||||||
} else {
|
.take_while(|c| c != &' ' && c != &'\r' && c != &'\n')
|
||||||
Some(
|
.collect::<String>()
|
||||||
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> {
|
fn next(&mut self) -> Result<char> {
|
||||||
let chr = self.peek()?;
|
let chr = self.peek()?;
|
||||||
self.input = &self.input[1..];
|
self.input = &self.input[chr.len_utf8()..];
|
||||||
if chr == '\n' {
|
if chr == '\n' {
|
||||||
self.context.line += 1;
|
self.context.line += 1;
|
||||||
self.context.column = 0;
|
self.context.column = 0;
|
||||||
|
|
@ -115,11 +117,11 @@ impl<'de> Deserializer<'de> {
|
||||||
self.next().unwrap();
|
self.next().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_bool(&mut self) -> Result<bool> {
|
fn parse_bool(&mut self) -> Result<bool> {
|
||||||
match &self.parse_identifier() {
|
self.skip_ws();
|
||||||
|
match &self.parse_unquoted() {
|
||||||
Ok(string) => match string.as_str() {
|
Ok(string) => match string.as_str() {
|
||||||
"on" => Ok(true),
|
"on" => Ok(true),
|
||||||
"off" => Ok(false),
|
"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()
|
self.parse_unquoted()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_string(&mut self) -> Result<String> {
|
fn parse_string(&mut self) -> Result<String> {
|
||||||
|
self.skip_ws();
|
||||||
let chr = self.peek()?;
|
let chr = self.peek()?;
|
||||||
if self.string_quote == Some(chr) {
|
if self.string_quote == Some(chr) {
|
||||||
self.parse_quoted()
|
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
|
where
|
||||||
T: Deserialize<'a>,
|
T: Deserialize<'a>,
|
||||||
{
|
{
|
||||||
|
|
@ -195,7 +199,7 @@ where
|
||||||
dbg!(deserializer.input);
|
dbg!(deserializer.input);
|
||||||
}*/
|
}*/
|
||||||
Ok(t)
|
Ok(t)
|
||||||
}*/
|
}
|
||||||
|
|
||||||
impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
type Error = DsnDeError;
|
type Error = DsnDeError;
|
||||||
|
|
@ -211,17 +215,17 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
let value = self.parse_bool()?;
|
|
||||||
self.skip_ws();
|
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
|
// If the struct deserializer set a variable saying the incoming value
|
||||||
// we do so and clear the flag
|
// should reconfigure a specific variable in the parser we do so and
|
||||||
|
// clear the flag.
|
||||||
if self.reconfig_incoming == Some(ReconfigIncoming::SpaceAllowed) {
|
if self.reconfig_incoming == Some(ReconfigIncoming::SpaceAllowed) {
|
||||||
self.space_in_quoted_tokens = value;
|
self.space_in_quoted_tokens = value;
|
||||||
self.reconfig_incoming = None;
|
self.reconfig_incoming = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.last_deserialized_type = Some("");
|
|
||||||
visitor.visit_bool(value)
|
visitor.visit_bool(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -241,10 +245,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
let value = self.parse_unquoted()?;
|
|
||||||
self.skip_ws();
|
self.skip_ws();
|
||||||
|
let value = self.parse_unquoted()?;
|
||||||
|
|
||||||
self.last_deserialized_type = Some("");
|
|
||||||
visitor.visit_i32(value.parse().unwrap())
|
visitor.visit_i32(value.parse().unwrap())
|
||||||
}
|
}
|
||||||
fn deserialize_i64<V>(self, _visitor: V) -> Result<V::Value>
|
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
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
let value = self.parse_unquoted()?;
|
|
||||||
self.skip_ws();
|
self.skip_ws();
|
||||||
|
let value = self.parse_unquoted()?;
|
||||||
|
|
||||||
self.last_deserialized_type = Some("");
|
|
||||||
visitor.visit_u32(value.parse().unwrap())
|
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
|
where
|
||||||
V: Visitor<'de>,
|
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>
|
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
let value = self.parse_unquoted()?;
|
|
||||||
self.skip_ws();
|
self.skip_ws();
|
||||||
|
let value = self.parse_unquoted()?;
|
||||||
|
|
||||||
self.last_deserialized_type = Some("");
|
|
||||||
visitor.visit_f32(value.parse().unwrap())
|
visitor.visit_f32(value.parse().unwrap())
|
||||||
}
|
}
|
||||||
fn deserialize_f64<V>(self, _visitor: V) -> Result<V::Value>
|
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
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
let chr = self.next()?;
|
|
||||||
self.skip_ws();
|
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
|
// If the struct deserializer set a variable saying the incoming value
|
||||||
// we do so and clear the flag
|
// should reconfigure a specific variable in the parser we do so and
|
||||||
|
// clear the flag.
|
||||||
if self.reconfig_incoming == Some(ReconfigIncoming::StringQuote) {
|
if self.reconfig_incoming == Some(ReconfigIncoming::StringQuote) {
|
||||||
self.string_quote = Some(chr);
|
self.string_quote = Some(chr);
|
||||||
self.reconfig_incoming = None;
|
self.reconfig_incoming = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.last_deserialized_type = Some("");
|
|
||||||
visitor.visit_char(chr)
|
visitor.visit_char(chr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -326,11 +330,10 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
let string = self.parse_string()?;
|
|
||||||
self.skip_ws();
|
self.skip_ws();
|
||||||
|
let value = self.parse_string()?;
|
||||||
|
|
||||||
self.last_deserialized_type = Some("");
|
visitor.visit_string(value)
|
||||||
visitor.visit_string(string)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::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!();
|
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
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
if self.next()? != '(' {
|
todo!();
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
if self.next()? != '(' {
|
todo!();
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
|
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
self.last_deserialized_type = None;
|
let elem_type = self.vec_type.expect(
|
||||||
visitor.visit_seq(ArrayIndices::new(self))
|
"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>
|
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>(
|
fn deserialize_struct<V>(
|
||||||
self,
|
self,
|
||||||
name: &'static str,
|
_name: &'static str,
|
||||||
fields: &'static [&'static str],
|
fields: &'static [&'static str],
|
||||||
visitor: V,
|
visitor: V,
|
||||||
) -> Result<V::Value>
|
) -> Result<V::Value>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
if self.next()? != '(' {
|
visitor.visit_seq(StructFields::new(self, fields))
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_enum<V>(
|
fn deserialize_enum<V>(
|
||||||
self,
|
self,
|
||||||
_name: &'static str,
|
name: &'static str,
|
||||||
_variants: &'static [&'static str],
|
_variants: &'static [&'static str],
|
||||||
_visitor: V,
|
visitor: V,
|
||||||
) -> Result<V::Value>
|
) -> Result<V::Value>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
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>
|
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
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>
|
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>,
|
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 {
|
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;
|
type Error = DsnDeError;
|
||||||
|
|
||||||
fn next_element_seed<S>(&mut self, seed: S) -> Result<Option<S::Value>>
|
fn unit_variant(self) -> Result<()> {
|
||||||
where
|
todo!();
|
||||||
S: DeserializeSeed<'de>,
|
}
|
||||||
{
|
|
||||||
if self.de.peek()? == ')' {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
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> {
|
struct ArrayIndices<'a, 'de: 'a> {
|
||||||
de: &'a mut Deserializer<'de>,
|
de: &'a mut Deserializer<'de>,
|
||||||
|
elem_type: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'de> ArrayIndices<'a, 'de> {
|
impl<'a, 'de> ArrayIndices<'a, 'de> {
|
||||||
fn new(de: &'a mut Deserializer<'de>) -> Self {
|
fn new(de: &'a mut Deserializer<'de>, elem_type: &'static str) -> Self {
|
||||||
Self { de }
|
Self { de, elem_type }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -565,22 +544,35 @@ impl<'de, 'a> SeqAccess<'de> for ArrayIndices<'a, 'de> {
|
||||||
where
|
where
|
||||||
S: DeserializeSeed<'de>,
|
S: DeserializeSeed<'de>,
|
||||||
{
|
{
|
||||||
|
self.de.skip_ws();
|
||||||
if self.de.peek()? == ')' {
|
if self.de.peek()? == ')' {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(prev) = self.de.last_deserialized_type {
|
if self.de.peek()? != '(' {
|
||||||
if let Some(lookahead) = self.de.next_name_lookahead() {
|
// anonymous field
|
||||||
if prev != lookahead {
|
seed.deserialize(&mut *self.de).map(Some)
|
||||||
// the next struct is of different type from the array contents
|
} else {
|
||||||
// that means the array implicitly ended
|
let lookahead = self.de.keyword_lookahead().ok_or(
|
||||||
// and we're looking at a field following the array instead
|
DsnDeError::ExpectedOpeningParen(self.elem_type)
|
||||||
return Ok(None);
|
)?;
|
||||||
|
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
|
where
|
||||||
S: DeserializeSeed<'de>,
|
S: DeserializeSeed<'de>,
|
||||||
{
|
{
|
||||||
if self.de.peek()? == ')' {
|
let field_name = self.fields[self.current_field];
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if the next field is "named"
|
self.de.skip_ws();
|
||||||
// (saved as `(fieldname value)`)
|
|
||||||
if let Some(lookahead) = self.de.next_name_lookahead() {
|
let ret = if field_name.ends_with("_vec") {
|
||||||
if lookahead != self.fields[self.current_field] {
|
self.de.vec_type = field_name.strip_suffix("_vec");
|
||||||
if lookahead + "s" != self.fields[self.current_field] {
|
let value = seed.deserialize(&mut *self.de).map(Some);
|
||||||
self.de.next_option_empty_hint = true;
|
self.de.vec_type = None;
|
||||||
} else {
|
|
||||||
self.de.next_option_empty_hint = false;
|
value
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.de.next_option_empty_hint = false;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// optional fields must be "named"
|
if self.de.peek()? != '(' {
|
||||||
// if we see something else assume empty option
|
// anonymous field, cannot be optional
|
||||||
self.de.next_option_empty_hint = true;
|
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;
|
self.current_field += 1;
|
||||||
seed.deserialize(&mut *self.de).map(Some)
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use crate::{
|
||||||
use super::{
|
use super::{
|
||||||
de::{Deserializer, DsnContext, DsnDeError},
|
de::{Deserializer, DsnContext, DsnDeError},
|
||||||
rules::Rules,
|
rules::Rules,
|
||||||
structure::Pcb,
|
structure::{DsnFile, Pcb, Shape},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
|
|
@ -34,8 +34,8 @@ impl DsnDesign {
|
||||||
let contents = std::fs::read_to_string(filename).unwrap(); // TODO: remove unwrap.
|
let contents = std::fs::read_to_string(filename).unwrap(); // TODO: remove unwrap.
|
||||||
//let pcb = from_str::<Pcb>(&contents).map_err(|err| DsnError())?;
|
//let pcb = from_str::<Pcb>(&contents).map_err(|err| DsnError())?;
|
||||||
let mut deserializer = Deserializer::from_str(&contents);
|
let mut deserializer = Deserializer::from_str(&contents);
|
||||||
let pcb = Pcb::deserialize(&mut deserializer)
|
let pcb = DsnFile::deserialize(&mut deserializer)
|
||||||
.map_err(|err| DsnError(deserializer.context, err))?;
|
.map_err(|err| DsnError(deserializer.context, err))?.pcb;
|
||||||
|
|
||||||
let rules = Rules::from_pcb(&pcb);
|
let rules = Rules::from_pcb(&pcb);
|
||||||
|
|
||||||
|
|
@ -46,50 +46,51 @@ impl DsnDesign {
|
||||||
let mut layout = Layout::new(&self.rules);
|
let mut layout = Layout::new(&self.rules);
|
||||||
|
|
||||||
// mapping of pin id -> net id prepared for adding pins
|
// mapping of pin id -> net id prepared for adding pins
|
||||||
let pin_nets = if let Some(nets) = self.pcb.network.nets.as_ref() {
|
let pin_nets = HashMap::<String, i64>::from_iter(
|
||||||
HashMap::<String, i64>::from_iter(
|
self.pcb.network.net_vec
|
||||||
nets.iter()
|
.iter()
|
||||||
.map(|net| {
|
.map(|net| {
|
||||||
// resolve the id so we don't work with strings
|
// resolve the id so we don't work with strings
|
||||||
let net_id = self.rules.net_ids.get(&net.name).unwrap();
|
let net_id = self.rules.net_ids.get(&net.name).unwrap();
|
||||||
|
|
||||||
// take the list of pins
|
// take the list of pins
|
||||||
// and for each pin id output (pin id, net id)
|
// and for each pin id output (pin id, net id)
|
||||||
net.pins.ids.iter().map(|id| (id.clone(), *net_id))
|
net.pins.names.iter().map(|id| (id.clone(), *net_id))
|
||||||
})
|
})
|
||||||
// flatten the nested iters into a single stream of tuples
|
// flatten the nested iters into a single stream of tuples
|
||||||
.flatten(),
|
.flatten(),
|
||||||
)
|
);
|
||||||
} else {
|
|
||||||
HashMap::<String, i64>::new()
|
|
||||||
};
|
|
||||||
|
|
||||||
// add pins from components
|
// add pins from components
|
||||||
//self.pcb.placement.components.iter().map(|component| {
|
for component in &self.pcb.placement.component_vec {
|
||||||
for component in &self.pcb.placement.components {
|
for place in &component.place_vec {
|
||||||
for place in &component.places {
|
|
||||||
let image = self
|
let image = self
|
||||||
.pcb
|
.pcb
|
||||||
.library
|
.library
|
||||||
.images
|
.image_vec
|
||||||
.iter()
|
.iter()
|
||||||
.find(|image| image.name == component.name)
|
.find(|image| image.name == component.name)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
for pin in &image.pins {
|
for pin in &image.pin_vec {
|
||||||
let pin_name = format!("{}-{}", place.name, pin.id);
|
let pin_name = format!("{}-{}", place.name, pin.id);
|
||||||
let net_id = pin_nets.get(&pin_name).unwrap();
|
let net_id = pin_nets.get(&pin_name).unwrap();
|
||||||
|
|
||||||
let padstack = &self
|
let padstack = &self
|
||||||
.pcb
|
.pcb
|
||||||
.library
|
.library
|
||||||
.padstacks
|
.padstack_vec
|
||||||
.iter()
|
.iter()
|
||||||
.find(|padstack| padstack.name == pin.name)
|
.find(|padstack| padstack.name == pin.name)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// no layer support yet, pick the first one
|
// 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 {
|
let circle = Circle {
|
||||||
pos: (place.x as f64 / 100.0, -place.y as f64 / 100.0).into(),
|
pos: (place.x as f64 / 100.0, -place.y as f64 / 100.0).into(),
|
||||||
r: circle.diameter as f64 / 200.0,
|
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
|
// add vias to layout and save indices of dots in the order they appear in the file
|
||||||
let _dot_indices: Vec<_> = self
|
let _dot_indices: Vec<_> = self
|
||||||
.pcb
|
.pcb
|
||||||
.wiring
|
.wiring
|
||||||
.vias
|
.via_vec
|
||||||
.iter()
|
.iter()
|
||||||
.map(|via| {
|
.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
|
// find the padstack referenced by this via placement
|
||||||
let padstack = &self
|
let padstack = &self
|
||||||
.pcb
|
.pcb
|
||||||
.library
|
.library
|
||||||
.padstacks
|
.padstack_vec
|
||||||
.iter()
|
.iter()
|
||||||
.find(|padstack| padstack.name == via.name)
|
.find(|padstack| padstack.name == via.name)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// no layer support yet, pick the first one
|
// 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 {
|
let circle = Circle {
|
||||||
pos: (via.x as f64 / 100.0, -via.y as f64 / 100.0).into(),
|
pos: (via.x as f64 / 100.0, -via.y as f64 / 100.0).into(),
|
||||||
r: circle.diameter as f64 / 200.0,
|
r: circle.diameter as f64 / 200.0,
|
||||||
|
|
@ -140,8 +145,8 @@ impl DsnDesign {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
for wire in self.pcb.wiring.wires.iter() {
|
for wire in self.pcb.wiring.wire_vec.iter() {
|
||||||
let net_id = self.rules.net_ids.get(&wire.net.0).unwrap();
|
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
|
// add the first coordinate in the wire path as a dot and save its index
|
||||||
let mut prev_index = layout
|
let mut prev_index = layout
|
||||||
|
|
@ -149,8 +154,8 @@ impl DsnDesign {
|
||||||
net: *net_id as i64,
|
net: *net_id as i64,
|
||||||
circle: Circle {
|
circle: Circle {
|
||||||
pos: (
|
pos: (
|
||||||
wire.path.coords[0].x as f64 / 100.0,
|
wire.path.coord_vec[0].x as f64 / 100.0,
|
||||||
-wire.path.coords[0].y as f64 / 100.0,
|
-wire.path.coord_vec[0].y as f64 / 100.0,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
r: wire.path.width as f64 / 200.0,
|
r: wire.path.width as f64 / 200.0,
|
||||||
|
|
@ -159,7 +164,7 @@ impl DsnDesign {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// iterate through path coords starting from the second
|
// 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
|
let index = layout
|
||||||
.add_fixed_dot(FixedDotWeight {
|
.add_fixed_dot(FixedDotWeight {
|
||||||
net: *net_id as i64,
|
net: *net_id as i64,
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ pub struct Rule {
|
||||||
impl Rule {
|
impl Rule {
|
||||||
fn from_dsn(rule: &super::structure::Rule) -> Self {
|
fn from_dsn(rule: &super::structure::Rule) -> Self {
|
||||||
Self {
|
Self {
|
||||||
width: rule.width.0 as f64 / 100.0,
|
width: rule.width as f64 / 100.0,
|
||||||
clearance: rule.clearances[0].value as f64 / 100.0, // picks the generic clearance only for now
|
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?
|
// keeping this as a separate iter pass because it might be moved into a different struct later?
|
||||||
let net_ids = HashMap::from_iter(
|
let net_ids = HashMap::from_iter(
|
||||||
pcb.network
|
pcb.network
|
||||||
.classes
|
.class_vec
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|class| &class.nets)
|
.flat_map(|class| &class.net_vec)
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(id, net)| (net.clone(), id as i64)),
|
.map(|(id, net)| (net.clone(), id as i64)),
|
||||||
);
|
);
|
||||||
|
|
@ -46,10 +46,10 @@ impl Rules {
|
||||||
let mut net_id_classes = HashMap::new();
|
let mut net_id_classes = HashMap::new();
|
||||||
let class_rules = HashMap::from_iter(
|
let class_rules = HashMap::from_iter(
|
||||||
pcb.network
|
pcb.network
|
||||||
.classes
|
.class_vec
|
||||||
.iter()
|
.iter()
|
||||||
.inspect(|class| {
|
.inspect(|class| {
|
||||||
for net in &class.nets {
|
for net in &class.net_vec {
|
||||||
let net_id = net_ids.get(net).unwrap();
|
let net_id = net_ids.get(net).unwrap();
|
||||||
net_id_classes.insert(*net_id, class.name.clone());
|
net_id_classes.insert(*net_id, class.name.clone());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,16 @@
|
||||||
use serde::{de::Error, Deserialize, Deserializer};
|
use serde::{de::Error, Deserialize, Deserializer};
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "pcb")]
|
pub struct DsnFile {
|
||||||
|
pub pcb: Pcb,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct Pcb {
|
pub struct Pcb {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub parser: Parser,
|
pub parser: Parser,
|
||||||
pub resolution: Resolution,
|
pub resolution: Resolution,
|
||||||
pub unit: Option<Unit>,
|
pub unit: String,
|
||||||
pub structure: Structure,
|
pub structure: Structure,
|
||||||
pub placement: Placement,
|
pub placement: Placement,
|
||||||
pub library: Library,
|
pub library: Library,
|
||||||
|
|
@ -15,183 +19,141 @@ pub struct Pcb {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "parser")]
|
|
||||||
pub struct Parser {
|
pub struct Parser {
|
||||||
pub string_quote: Option<StringQuote>,
|
pub string_quote: Option<char>,
|
||||||
pub space_in_quoted_tokens: SpaceAllowed,
|
pub space_in_quoted_tokens: Option<bool>,
|
||||||
pub host_cad: Option<HostCad>,
|
pub host_cad: Option<String>,
|
||||||
pub host_version: Option<HostVersion>,
|
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)]
|
#[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 struct Resolution {
|
||||||
pub unit: String,
|
pub unit: String,
|
||||||
pub value: u32,
|
pub value: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "unit")]
|
|
||||||
pub struct Unit(pub String);
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
#[serde(rename = "structure")]
|
|
||||||
pub struct Structure {
|
pub struct Structure {
|
||||||
pub layers: Vec<Layer>,
|
pub layer_vec: Vec<Layer>,
|
||||||
pub boundary: Boundary,
|
pub boundary: Boundary,
|
||||||
pub plane: Vec<Plane>,
|
pub plane_vec: Vec<Plane>,
|
||||||
pub vias: Vias,
|
pub via: ViaNames,
|
||||||
pub rule: Rule,
|
pub rule: Rule,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "layer")]
|
|
||||||
pub struct Layer {
|
pub struct Layer {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub r#type: Type,
|
pub r#type: String,
|
||||||
pub property: Property,
|
pub property: Property,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "property")]
|
pub struct Property {
|
||||||
pub struct Property(Index);
|
pub index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "index")]
|
pub struct Boundary {
|
||||||
pub struct Index(pub u32);
|
pub path: Path,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "boundary")]
|
|
||||||
pub struct Boundary(pub Path);
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
#[serde(rename = "plane")]
|
|
||||||
pub struct Plane {
|
pub struct Plane {
|
||||||
net: String,
|
pub net: String,
|
||||||
shape: Polygon,
|
pub polygon: Polygon,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "via")]
|
pub struct ViaNames {
|
||||||
pub struct Vias {
|
pub name_vec: Vec<String>,
|
||||||
vias: Vec<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "placement")]
|
|
||||||
pub struct Placement {
|
pub struct Placement {
|
||||||
pub components: Vec<Component>,
|
pub component_vec: Vec<Component>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "component")]
|
|
||||||
pub struct Component {
|
pub struct Component {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub places: Vec<Place>,
|
pub place_vec: Vec<Place>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "place")]
|
|
||||||
pub struct Place {
|
pub struct Place {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub x: f32,
|
pub x: f32,
|
||||||
pub y: f32,
|
pub y: f32,
|
||||||
pub side: String,
|
pub side: String,
|
||||||
pub rotation: f32,
|
pub rotation: f32,
|
||||||
pub PN: Option<PN>,
|
pub PN: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "PN")]
|
|
||||||
pub struct PN {
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
#[serde(rename = "library")]
|
|
||||||
pub struct Library {
|
pub struct Library {
|
||||||
pub images: Vec<Image>,
|
pub image_vec: Vec<Image>,
|
||||||
pub padstacks: Vec<Padstack>,
|
pub padstack_vec: Vec<Padstack>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "image")]
|
|
||||||
pub struct Image {
|
pub struct Image {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub outlines: Vec<Outline>,
|
pub outline_vec: Vec<Outline>,
|
||||||
pub pins: Vec<Pin>,
|
pub pin_vec: Vec<Pin>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "outline")]
|
|
||||||
pub struct Outline {
|
pub struct Outline {
|
||||||
pub path: Path,
|
pub path: Path,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "pin")]
|
|
||||||
pub struct Pin {
|
pub struct Pin {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub rotate: Option<Rotate>,
|
pub rotate: Option<f32>,
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub x: f32,
|
pub x: f32,
|
||||||
pub y: f32,
|
pub y: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "rotate")]
|
|
||||||
pub struct Rotate {
|
pub struct Rotate {
|
||||||
pub angle: f32,
|
pub angle: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "padstack")]
|
|
||||||
pub struct Padstack {
|
pub struct Padstack {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub shapes: Vec<Shape>,
|
pub shape_vec: Vec<Shape>,
|
||||||
pub attach: Attach,
|
pub attach: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "shape")]
|
pub enum Shape {
|
||||||
pub struct Shape(pub Circle);
|
#[serde(rename = "circle")]
|
||||||
|
Circle(Circle),
|
||||||
|
#[serde(rename = "rect")]
|
||||||
|
Rect(Rect),
|
||||||
|
#[serde(rename = "path")]
|
||||||
|
Path(Path),
|
||||||
|
#[serde(rename = "polygon")]
|
||||||
|
Polygon(Polygon),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "circle")]
|
|
||||||
pub struct Circle {
|
pub struct Circle {
|
||||||
pub layer: String,
|
pub layer: String,
|
||||||
pub diameter: u32,
|
pub diameter: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "attach")]
|
|
||||||
pub struct Attach(pub bool);
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
#[serde(rename = "network")]
|
|
||||||
pub struct Network {
|
pub struct Network {
|
||||||
pub nets: Option<Vec<NetPinAssignments>>,
|
pub net_vec: Vec<NetPinAssignments>,
|
||||||
pub classes: Vec<Class>,
|
pub class_vec: Vec<Class>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "net")]
|
|
||||||
// dsn names this "net", but it's a structure unrelated to "net" in wiring or elsewhere
|
// dsn names this "net", but it's a structure unrelated to "net" in wiring or elsewhere
|
||||||
pub struct NetPinAssignments {
|
pub struct NetPinAssignments {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
@ -199,57 +161,53 @@ pub struct NetPinAssignments {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "pins")]
|
|
||||||
pub struct Pins {
|
pub struct Pins {
|
||||||
pub ids: Vec<String>,
|
pub names: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "class")]
|
|
||||||
pub struct Class {
|
pub struct Class {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub nets: Vec<String>,
|
pub net_vec: Vec<String>,
|
||||||
pub circuit: Circuit,
|
pub circuit: Circuit,
|
||||||
pub rule: Rule,
|
pub rule: Rule,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "circuit")]
|
pub struct Circuit {
|
||||||
pub struct Circuit(pub UseVia);
|
pub use_via: UseVia,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "use_via")]
|
|
||||||
pub struct UseVia {
|
pub struct UseVia {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "wiring")]
|
|
||||||
pub struct Wiring {
|
pub struct Wiring {
|
||||||
pub wires: Vec<Wire>,
|
pub wire_vec: Vec<Wire>,
|
||||||
pub vias: Vec<Via>,
|
pub via_vec: Vec<Via>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "wire")]
|
|
||||||
pub struct Wire {
|
pub struct Wire {
|
||||||
pub path: Path,
|
pub path: Path,
|
||||||
pub net: Net,
|
pub net: String,
|
||||||
pub r#type: Type,
|
pub r#type: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
// structs that appear in multiple places
|
// structs that appear in multiple places
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
// This type isn't deserialized as is. Instead, Vec<Point> is converted from
|
||||||
#[serde(rename = "type")]
|
// what's effectively Vec<f32> (with even length) in the file.
|
||||||
pub struct Type(pub String);
|
// Use #[serde(deserialize_with = "de_points")].
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Point {
|
pub struct Point {
|
||||||
pub x: f32,
|
pub x: f32,
|
||||||
pub y: f32,
|
pub y: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used to deserialize Vec<Point>.
|
||||||
fn de_points<'de, D>(deserializer: D) -> Result<Vec<Point>, D::Error>
|
fn de_points<'de, D>(deserializer: D) -> Result<Vec<Point>, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
|
|
@ -257,7 +215,10 @@ where
|
||||||
Vec::<f32>::deserialize(deserializer)?
|
Vec::<f32>::deserialize(deserializer)?
|
||||||
.chunks(2)
|
.chunks(2)
|
||||||
.map(|pair| {
|
.map(|pair| {
|
||||||
|
// 0th index is guaranteed to exist by `.chunks()`
|
||||||
|
// (it ends iteration instead of emitting an empty Vec)
|
||||||
let x = pair[0];
|
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(
|
let y = *pair.get(1).ok_or(Error::custom(
|
||||||
"expected paired x y coordinates, list ended at x",
|
"expected paired x y coordinates, list ended at x",
|
||||||
))?;
|
))?;
|
||||||
|
|
@ -268,51 +229,47 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "polygon")]
|
|
||||||
pub struct Polygon {
|
pub struct Polygon {
|
||||||
pub layer: String,
|
pub layer: String,
|
||||||
pub width: f32,
|
pub width: f32,
|
||||||
#[serde(deserialize_with = "de_points")]
|
#[serde(deserialize_with = "de_points")]
|
||||||
pub coords: Vec<Point>,
|
pub coord_vec: Vec<Point>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "path")]
|
|
||||||
pub struct Path {
|
pub struct Path {
|
||||||
pub layer: String,
|
pub layer: String,
|
||||||
pub width: f32,
|
pub width: f32,
|
||||||
#[serde(deserialize_with = "de_points")]
|
#[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)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "via")]
|
|
||||||
pub struct Via {
|
pub struct Via {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
pub y: i32,
|
pub y: i32,
|
||||||
pub net: Net,
|
pub net: String,
|
||||||
pub r#type: Type,
|
pub r#type: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename = "rule")]
|
|
||||||
pub struct Rule {
|
pub struct Rule {
|
||||||
pub width: Width,
|
pub width: f32,
|
||||||
pub clearances: Vec<Clearance>,
|
pub clearance_vec: Vec<Clearance>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[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 struct Clearance {
|
||||||
pub value: f32,
|
pub value: f32,
|
||||||
pub r#type: Option<Type>,
|
pub r#type: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue