From aa0616840cba2cb209b9703294befe3d5149ceaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Cicho=C5=84?= Date: Sun, 16 Jun 2024 19:02:54 +0200 Subject: [PATCH] specctra: remove old file reader based on serde --- src/specctra/de.rs | 650 ----------------------------------------- src/specctra/design.rs | 12 +- src/specctra/mod.rs | 1 - 3 files changed, 6 insertions(+), 657 deletions(-) delete mode 100644 src/specctra/de.rs diff --git a/src/specctra/de.rs b/src/specctra/de.rs deleted file mode 100644 index af286e7..0000000 --- a/src/specctra/de.rs +++ /dev/null @@ -1,650 +0,0 @@ -use std::fmt; - -use serde::de::{self, DeserializeSeed, EnumAccess, SeqAccess, VariantAccess, Visitor}; -use serde::Deserialize; -use thiserror::Error; - -type Result = std::result::Result; - -#[derive(Error, Debug)] -pub enum DeError { - #[error("{0}")] - Custom(String), - #[error("unexpected EOF")] - Eof, - #[error("expected boolean value")] - ExpectedBool, - #[error("expected quoted string")] - ExpectedQuoted, - #[error("spaces in quoted strings weren't declared")] - SpaceInQuoted, - #[error("expected unquoted string")] - ExpectedUnquoted, - #[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), -} - -impl de::Error for DeError { - fn custom(msg: T) -> Self { - DeError::Custom(msg.to_string()) - } -} - -#[derive(Error, Debug)] -#[error("syntax error at {0}: {1}")] -pub struct SyntaxError(pub Context, pub DeError); - -#[derive(Debug)] -pub struct Context { - line: usize, - column: usize, -} - -impl fmt::Display for Context { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "line {0}, column {1}", self.line, self.column) - } -} - -pub struct Deserializer<'de> { - input: &'de str, - context: Context, - - string_quote: Option, - space_in_quoted_tokens: bool, - reconfig_incoming: Option, - - vec_type: Option<&'static str>, - next_option_empty_hint: bool, -} - -#[derive(PartialEq, Debug, Copy, Clone)] -enum ReconfigIncoming { - StringQuote, - SpaceAllowed, -} - -impl<'de> Deserializer<'de> { - fn from_str(input: &'de str) -> Self { - Self { - input, - context: Context { line: 1, column: 0 }, - - string_quote: None, - space_in_quoted_tokens: false, - reconfig_incoming: None, - - vec_type: None, - next_option_empty_hint: false, - } - } - - fn keyword_lookahead(&self) -> Option { - let mut iter = self.input.chars(); - if let Some('(') = iter.next() { - Some( - iter.take_while(|c| c != &' ' && c != &'\r' && c != &'\n') - .collect::(), - ) - } else { - None - } - } - - fn peek(&mut self) -> Result { - self.input.chars().next().ok_or(DeError::Eof) - } - - fn next(&mut self) -> Result { - let chr = self.peek()?; - self.input = &self.input[chr.len_utf8()..]; - if chr == '\n' { - self.context.line += 1; - self.context.column = 0; - } else { - self.context.column += 1; - } - Ok(chr) - } - - fn skip_ws(&mut self) { - while let Ok(chr) = self.peek() { - if chr != ' ' && chr != '\r' && chr != '\n' { - return; - } else { - self.next().unwrap(); - } - } - } - - fn parse_bool(&mut self) -> Result { - self.skip_ws(); - match &self.parse_unquoted() { - Ok(string) => match string.as_str() { - "on" => Ok(true), - "off" => Ok(false), - _ => Err(DeError::ExpectedBool), - }, - Err(_) => Err(DeError::ExpectedBool), - } - } - - 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() - } else { - self.parse_unquoted() - } - } - - fn parse_unquoted(&mut self) -> Result { - let mut string = String::new(); - loop { - let chr = self.peek()?; - if chr != ' ' && chr != '\r' && chr != '\n' && chr != '(' && chr != ')' { - string.push(self.next()?); // can't fail because of earlier peek - } else { - if string.len() > 0 { - return Ok(string); - } else { - return Err(DeError::ExpectedUnquoted); - } - } - } - } - - // method only called if parse_string sees a valid string quote - fn parse_quoted(&mut self) -> Result { - assert!(self.next().unwrap() == self.string_quote.unwrap()); - - let mut string = String::new(); - loop { - let chr = self.peek()?; - - // XXX this is silly - // not declaring that spaces are allowed in qyoted strings downgrades the format - // but there's no reason we shouldn't try to parse the file anyway, no ambiguity arises - // maybe this should log a warning and proceed? - if self.space_in_quoted_tokens != true && chr == ' ' { - return Err(DeError::SpaceInQuoted); - } - - if Some(chr) == self.string_quote { - self.next().unwrap(); - return Ok(string); - } else { - string.push(self.next()?); // can't fail because of earlier peek - } - } - } -} - -pub fn from_str<'a, T>(input: &'a str) -> std::result::Result -where - T: Deserialize<'a>, -{ - let mut deserializer = Deserializer::from_str(input); - let value = T::deserialize(&mut deserializer); - deserializer.skip_ws(); - value.map_err(|err| SyntaxError(deserializer.context, err)) -} - -impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { - type Error = DeError; - - fn deserialize_any(self, _visitor: V) -> Result - where - V: Visitor<'de>, - { - todo!(); - } - - fn deserialize_bool(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - 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 self.reconfig_incoming == Some(ReconfigIncoming::SpaceAllowed) { - self.space_in_quoted_tokens = value; - self.reconfig_incoming = None; - } - - visitor.visit_bool(value) - } - - fn deserialize_i8(self, _visitor: V) -> Result - where - V: Visitor<'de>, - { - todo!(); - } - fn deserialize_i16(self, _visitor: V) -> Result - where - V: Visitor<'de>, - { - todo!(); - } - fn deserialize_i32(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - self.skip_ws(); - let value = self.parse_unquoted()?; - - visitor.visit_i32(value.parse().unwrap()) - } - fn deserialize_i64(self, _visitor: V) -> Result - where - V: Visitor<'de>, - { - todo!(); - } - fn deserialize_u8(self, _visitor: V) -> Result - where - V: Visitor<'de>, - { - todo!(); - } - fn deserialize_u16(self, _visitor: V) -> Result - where - V: Visitor<'de>, - { - todo!(); - } - fn deserialize_u32(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - self.skip_ws(); - let value = self.parse_unquoted()?; - - visitor.visit_u32(value.parse().unwrap()) - } - fn deserialize_u64(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - 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>, - { - self.skip_ws(); - let value = self.parse_unquoted()?; - - visitor.visit_f32(value.parse().unwrap()) - } - fn deserialize_f64(self, _visitor: V) -> Result - where - V: Visitor<'de>, - { - todo!(); - } - fn deserialize_char(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - 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 self.reconfig_incoming == Some(ReconfigIncoming::StringQuote) { - self.string_quote = Some(chr); - self.reconfig_incoming = None; - } - - visitor.visit_char(chr) - } - - fn deserialize_str(self, _visitor: V) -> Result - where - V: Visitor<'de>, - { - todo!(); - } - - fn deserialize_string(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - self.skip_ws(); - let value = self.parse_string()?; - - visitor.visit_string(value) - } - - fn deserialize_bytes(self, _visitor: V) -> Result - where - V: Visitor<'de>, - { - todo!(); - } - - fn deserialize_byte_buf(self, _visitor: V) -> Result - where - V: Visitor<'de>, - { - todo!(); - } - - fn deserialize_option(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - if self.next_option_empty_hint { - visitor.visit_none() - } else { - visitor.visit_some(self) - } - } - - fn deserialize_unit(self, _visitor: V) -> Result - where - V: Visitor<'de>, - { - todo!(); - } - - fn deserialize_unit_struct(self, _name: &'static str, _visitor: V) -> Result - where - V: Visitor<'de>, - { - todo!(); - } - - fn deserialize_newtype_struct(self, _name: &'static str, _visitor: V) -> Result - where - V: Visitor<'de>, - { - todo!(); - } - - fn deserialize_seq(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - 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 - where - V: Visitor<'de>, - { - todo!(); - } - - fn deserialize_tuple_struct( - self, - _name: &'static str, - _len: usize, - _visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - todo!(); - } - - fn deserialize_map(self, _visitor: V) -> Result - where - V: Visitor<'de>, - { - todo!(); - } - - fn deserialize_struct( - self, - _name: &'static str, - fields: &'static [&'static str], - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - visitor.visit_seq(StructFields::new(self, fields)) - } - - fn deserialize_enum( - self, - name: &'static str, - _variants: &'static [&'static str], - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - self.skip_ws(); - if self.next()? != '(' { - return Err(DeError::ExpectedOpeningParen("an enum variant")); - } - - let value = visitor.visit_enum(Enum::new(self))?; - - self.skip_ws(); - if self.next()? != ')' { - return Err(DeError::ExpectedClosingParen(name)); - } - - Ok(value) - } - - fn deserialize_identifier(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - self.skip_ws(); - visitor.visit_string( - self.parse_string() - .map_err(|err| DeError::ExpectedKeyword)?, - ) - } - - fn deserialize_ignored_any(self, _visitor: V) -> Result - where - V: Visitor<'de>, - { - todo!(); - } -} - -struct Enum<'a, 'de: 'a> { - de: &'a mut Deserializer<'de>, -} - -impl<'a, 'de> Enum<'a, 'de> { - fn new(de: &'a mut Deserializer<'de>) -> Self { - Enum { de } - } -} - -impl<'de, 'a> EnumAccess<'de> for Enum<'a, 'de> { - type Error = DeError; - 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 = DeError; - - fn unit_variant(self) -> Result<()> { - todo!(); - } - - 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>, elem_type: &'static str) -> Self { - Self { de, elem_type } - } -} - -impl<'de, 'a> SeqAccess<'de> for ArrayIndices<'a, 'de> { - type Error = DeError; - - fn next_element_seed(&mut self, seed: S) -> Result> - where - S: DeserializeSeed<'de>, - { - self.de.skip_ws(); - if self.de.peek()? == ')' { - 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(DeError::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(DeError::ExpectedClosingParen(self.elem_type)) - } else { - Ok(Some(value)) - } - } else { - Ok(None) - } - } - } -} - -struct StructFields<'a, 'de: 'a> { - de: &'a mut Deserializer<'de>, - current_field: usize, - fields: &'static [&'static str], -} - -impl<'a, 'de> StructFields<'a, 'de> { - fn new(de: &'a mut Deserializer<'de>, fields: &'static [&'static str]) -> Self { - Self { - de, - current_field: 0, - fields, - } - } -} - -impl<'de, 'a> SeqAccess<'de> for StructFields<'a, 'de> { - type Error = DeError; - - fn next_element_seed(&mut self, seed: S) -> Result> - where - S: DeserializeSeed<'de>, - { - let field_name = self.fields[self.current_field]; - - self.de.skip_ws(); - - let ret = if field_name.ends_with("_anonymous") { - seed.deserialize(&mut *self.de).map(Some) - } else 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 { - 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(DeError::ExpectedClosingParen(field_name)) - } else { - Ok(Some(value)) - } - } else { - Err(DeError::WrongKeyword(field_name, parsed_keyword)) - } - } - }; - - self.current_field += 1; - ret - } -} diff --git a/src/specctra/design.rs b/src/specctra/design.rs index 2321f85..53e1be0 100644 --- a/src/specctra/design.rs +++ b/src/specctra/design.rs @@ -9,7 +9,7 @@ use crate::{ layout::{zone::SolidZoneWeight, Layout}, math::Circle, specctra::{ - de, + read, mesadata::SpecctraMesadata, structure::{self, Layer, Pcb, Shape, SpecctraFile}, }, @@ -20,7 +20,7 @@ pub enum LoadingError { #[error(transparent)] Io(#[from] std::io::Error), #[error(transparent)] - Syntax(#[from] de::SyntaxError), + Parse(#[from] read::ParseError), } #[derive(Debug)] @@ -32,9 +32,9 @@ impl SpecctraDesign { pub fn load_from_file(filename: &str) -> Result { let file = std::fs::File::open(filename)?; let reader = std::io::BufReader::new(file); - let mut list_reader = super::read::ListTokenizer::new(reader); + let mut list_reader = read::ListTokenizer::new(reader); - if let Ok(file) = list_reader.read_value::() { + if let Ok(file) = list_reader.read_value::() { //use super::structure::*; // (this entire if let block does not belong here) @@ -114,8 +114,8 @@ impl SpecctraDesign { .pcb; Ok(Self { pcb })*/ - let mut list_reader = super::read::ListTokenizer::new(contents.as_bytes()); - let dsn = list_reader.read_value::(); + let mut list_reader = read::ListTokenizer::new(contents.as_bytes()); + let dsn = list_reader.read_value::(); Ok(Self { pcb: dsn.unwrap().pcb, diff --git a/src/specctra/mod.rs b/src/specctra/mod.rs index 28b6830..58c4588 100644 --- a/src/specctra/mod.rs +++ b/src/specctra/mod.rs @@ -1,5 +1,4 @@ mod common; -mod de; pub mod design; pub mod mesadata; mod read;