simulink-rs 4.0.2

Simulink C to Rust library builder
Documentation
use super::{DeserializeImpl, List, Simulink, IO};

impl DeserializeImpl for IO {
    fn deserialize_impl(&self) -> String {
        format!(r#""{0}" => Ok(Field::{0})"#, self.name)
    }
}

impl DeserializeImpl for List {
    fn deserialize_impl(&self) -> String {
        self.iter()
            .map(|field| field.deserialize_impl())
            .collect::<Vec<String>>()
            .join(",\n")
    }
}

pub trait Visitor {
    fn visit_map(&self) -> String;
    fn visit_seq(&self) -> String;
}
impl Visitor for List {
    fn visit_seq(&self) -> String {
        let mut n = 0;
        let mut visit = vec![];
        for field in self.iter() {
            visit.push(if let Some(size) = field.size {
                n += size;
                format!(
                    r#"
let {0}: [f64; {1}] = seq
    .next_element::<Vec<{2}>>()?
    .ok_or_else(|| ::serde::de::Error::invalid_length({3}, &self))?
    .try_into()
    .map_err(|_| {{
        ::serde::de::Error::invalid_value(::serde::de::Unexpected::Seq, &self)
    }})?;
        "#,
                    field.name,
                    size,
                    field.dtype,
                    n - size
                )
            } else {
                n += 1;
                format!(
                    r#"
let {0} = seq
    .next_element::<{1}>()?
    .ok_or_else(|| ::serde::de::Error::invalid_length({2}, &self))?
    .try_into()
    .map_err(|_| {{
        ::serde::de::Error::invalid_value(::serde::de::Unexpected::Seq, &self)
    }})?;
        "#,
                    field.name,
                    field.dtype,
                    n - 1
                )
            });
        }
        visit.into_iter().collect()
    }
    fn visit_map(&self) -> String {
        let ((v1, v2), v3): ((Vec<_>, Vec<_>), Vec<_>) = self
            .iter()
            .map(|field| {
                let a = format!("let mut {0} = None;", field.name);
                let b = format!(
                    r#"
    Field::{0} => {{
        if {0}.is_some() {{
            return Err(::serde::de::Error::duplicate_field("{0}"));
        }}
        {0} = Some(map.next_value::<{1}>()?);
    }}
            "#,
                    field.name,
                    if field.size.is_none() {
                        field.dtype.clone()
                    } else {
                        format!("Vec<{}>", field.dtype)
                    }
                );
                let c = if let Some(size) = field.size {
                    format!(
                        r#"
    let {0}: [f64; {1}] = {0}
    .ok_or_else(|| ::serde::de::Error::missing_field("{0}"))?
    .try_into()
    .map_err(|_| {{
        ::serde::de::Error::invalid_value(::serde::de::Unexpected::Seq, &self)
    }})?;
                    "#,
                        field.name, size
                    )
                } else {
                    format!(
                        r#"
    let {0} = {0}.ok_or_else(|| ::serde::de::Error::missing_field("{0}"))?;                    
                "#,
                        field.name
                    )
                };
                ((a, b), c)
            })
            .unzip();
        format!(
            r#"
{0}
while let Some(key) = map.next_key::<Field>()? {{
    match key {{
{1}
    }}
}}
{2}
            "#,
            v1.join("\n"),
            v2.join("\n"),
            v3.join("\n"),
        )
    }
}

impl DeserializeImpl for Simulink {
    fn deserialize_impl(&self) -> String {
        let fields: Vec<_> = self
            .properties
            .iter()
            .map(|prop| format!("{}", prop.name))
            .collect();
        format!(
            r#"
impl<'de> ::serde::de::Deserialize<'de> for {sim} {{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: ::serde::de::Deserializer<'de>,
    {{
        const FIELDS: &'static [&'static str] = &[{fields_str}];

        enum Field {{
{fields}
        }}

        impl<'de> ::serde::de::Deserialize<'de> for Field {{
            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
            where
                D: ::serde::de::Deserializer<'de>,
            {{
                struct FieldVisitor;
                impl<'de> ::serde::de::Visitor<'de> for FieldVisitor {{
                    type Value = Field;
                    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {{
                        formatter.write_str("field identifier")
                    }}

                    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
                    where
                        E: ::serde::de::Error,
                    {{
                        match value {{
{fields_match},
_ => Err(::serde::de::Error::unknown_field(value, FIELDS)),
                        }}
                    }}
                }}
                deserializer.deserialize_identifier(FieldVisitor)
            }}
        }}

        struct SimulinkVisitor;
        impl<'de> ::serde::de::Visitor<'de> for SimulinkVisitor {{
            type Value = {sim};
            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {{
                formatter.write_str("struct {sim}")
            }}
            fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
            where
                V: ::serde::de::SeqAccess<'de>,
            {{
{seq_visitor}
Ok({sim} {{
    {fields}
}})
            }}
            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
            where
                A: ::serde::de::MapAccess<'de>,
            {{
{map_visitor}
Ok({sim} {{
    {fields}
}})
            }}
        }}
        deserializer.deserialize_struct("{sim}", FIELDS, SimulinkVisitor)
    }}
}}
                "#,
            sim = self.name,
            fields = fields.join(",\n"),
            fields_str = fields
                .iter()
                .map(|field| format!(r#""{field}""#))
                .collect::<Vec<String>>()
                .join(", "),
            fields_match = self.properties.deserialize_impl(),
            seq_visitor = self.properties.visit_seq(),
            map_visitor = self.properties.visit_map(),
        )
    }
}