Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 6 additions & 106 deletions ruststep/src/parser/exchange/data.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
use crate::parser::{combinator::*, exchange::*, token::*};
use inflector::Inflector;
use nom::{branch::alt, Parser};
use serde::{de, forward_to_deserialize_any};

#[derive(Debug, Clone, PartialEq)]
pub struct DataSection {
pub meta: Vec<Parameter>,
pub entities: Vec<EntityInstance>,
}

#[derive(Debug, Clone, PartialEq)]
pub enum EntityInstance {
Simple { name: u64, record: Record },
Complex { name: u64, subsuper: Vec<Record> },
}

/// data_section = `DATA` \[ `(` [parameter_list] `)` \] `;` [entity_instance_list] `ENDSEC;` .
pub fn data_section(input: &str) -> ParseResult<DataSection> {
tuple_((
Expand All @@ -32,12 +36,6 @@ pub fn entity_instance_list(input: &str) -> ParseResult<Vec<EntityInstance>> {
many0_(entity_instance).parse(input)
}

#[derive(Debug, Clone, PartialEq)]
pub enum EntityInstance {
Simple { name: u64, record: Record },
Complex { name: u64, subsuper: Vec<Record> },
}

/// entity_instance = [simple_entity_instance] | [complex_entity_instance] .
pub fn entity_instance(input: &str) -> ParseResult<EntityInstance> {
alt((simple_entity_instance, complex_entity_instance)).parse(input)
Expand All @@ -62,41 +60,6 @@ pub fn complex_entity_instance(input: &str) -> ParseResult<EntityInstance> {
.parse(input)
}

/// A struct typed in EXPRESS schema
///
/// serde::Deserialize
/// -------------------
///
/// Different from [Parameter], this checks the target struct name:
///
/// ```
/// use nom::Finish;
/// use serde::Deserialize;
/// use ruststep::parser::exchange;
///
/// #[derive(Debug, Deserialize)]
/// struct MyStruct {
/// x: f64,
/// y: f64,
/// }
///
/// // `MyStruct` as Rust struct must be parsed from `MY_STRUCT` STEP record
/// let (_, record) = exchange::simple_record("MY_STRUCT(1.0, 2.0)").finish().unwrap();
/// let a: MyStruct = Deserialize::deserialize(&record).unwrap();
///
/// // Other type `YOUR_STRUCT` cannot be deserialized
/// // even if internal data `(f64, f64)` is matched.
/// let (_, record) = exchange::simple_record("YOUR_STRUCT(1.0, 2.0)").finish().unwrap();
/// let a: Result<MyStruct, _> = Deserialize::deserialize(&record);
/// assert!(a.is_err());
/// ```
///
#[derive(Debug, Clone, PartialEq)]
pub struct Record {
pub name: String,
pub parameters: Vec<Parameter>,
}

/// simple_record = [keyword] `(` \[ [parameter_list] \] `)` .
pub fn simple_record(input: &str) -> ParseResult<Record> {
tuple_((keyword, char_('('), opt_(parameter_list), char_(')')))
Expand All @@ -119,49 +82,9 @@ pub fn subsuper_record(input: &str) -> ParseResult<Vec<Record>> {
.parse(input)
}

impl<'de, 'record> de::Deserializer<'de> for &'record Record {
type Error = crate::error::Error;

fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
Err(de::Error::invalid_type(
de::Unexpected::Other("any"),
&self.name.as_str(),
))
}

fn deserialize_struct<V>(
self,
name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
if name != self.name.to_pascal_case() {
return Err(de::Error::invalid_type(
de::Unexpected::StructVariant,
&self.name.as_str(),
));
}
let seq = de::value::SeqDeserializer::new(self.parameters.iter());
visitor.visit_seq(seq)
}

forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map enum identifier ignored_any
}
}

#[cfg(test)]
mod tests {
use nom::Finish;
use serde::Deserialize;

#[test]
fn simple_recode1() {
Expand All @@ -180,27 +103,4 @@ mod tests {
dbg!(record);
assert_eq!(res, "");
}

#[derive(Debug, Deserialize)]
struct MyStruct {
x: f64,
y: f64,
}

#[test]
fn deserialize_record_to_struct() {
let (res, record) = super::simple_record("MY_STRUCT(1.0, 2.0)")
.finish()
.unwrap();
assert_eq!(res, "");
let a: MyStruct = Deserialize::deserialize(&record).unwrap();
dbg!(a);

let (res, record) = super::simple_record("YOUR_STRUCT(1.0, 2.0)")
.finish()
.unwrap();
assert_eq!(res, "");
let a: Result<MyStruct, _> = Deserialize::deserialize(&record);
assert!(a.is_err());
}
}
2 changes: 2 additions & 0 deletions ruststep/src/parser/exchange/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ mod anchor;
mod data;
mod header;
mod parameter;
mod record;
mod reference;

pub use anchor::*;
pub use data::*;
pub use header::*;
pub use parameter::*;
pub use record::*;
pub use reference::*;

use crate::parser::{combinator::*, token::*};
Expand Down
Loading