bitis 0.10.5

Bitwise serialization of messages defined in a data description language with interfaces for rust, python and c++.
Documentation
#![allow(dead_code, non_snake_case, nonstandard_style)]

use bitis_lib::*;

use pyo3::prelude::*;
use pyo3::exceptions::PyException;
use pyo3::types::{PyBytes};

use super::messages;

// Base function
fn do_val_from<T: ValFromInto<U>, U>(v: &U) -> T {
    T::val_from(v)
}

// *****************************************************************
// *****************************************************************
// Enums
{%+ for ce in d.enums ~%}
{%- if let Some(comment_impl) = ce.comment -%}
///{{comment_impl}}
{%- endif %}
#[pyclass]
#[derive(Debug, Clone)]
pub enum {{ ce.name }} {
{%- for cv in ce.values +%}
  {{ cv|pascal_case }},
{%- endfor %}
}
impl std::fmt::Display for {{ ce.name }} {
  fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    match self {
{%- for cv in ce.values +%}
      {{ ce.name }}::{{ cv|pascal_case }} => { write!(f, "{{ ce.name }}::{{ cv|pascal_case }}") }, {% endfor %}
    }
} }

impl ValFromInto<{{ ce.name }}> for messages::{{ ce.name }} {
  fn val_into(&self) -> {{ ce.name }} {
    match self.clone() {
{%- for cv in ce.values +%}
      messages::{{ ce.name }}::{{ cv|pascal_case }} => {{ ce.name }}::{{ cv|pascal_case }}, {% endfor %}
    }
  }
  fn val_from(v: &{{ ce.name }}) -> Self {
    match v {
{%- for cv in ce.values +%}
      {{ ce.name }}::{{ cv|pascal_case }} => messages::{{ ce.name }}::{{ cv|pascal_case }}, {% endfor %}
    }
  }
}
{%- endfor +%}

// *****************************************************************
// *****************************************************************
// *** Enums for oneof
{%+ for (_, coo) in d.oos %}
#[pyclass]
#[derive(Debug)]
#[allow(dead_code)]
pub enum {{ coo.name }} {
{%- for ca in coo.attributes +%}
  {% include "pyclasses_oo_attr.py.rs.jinja" %}
{%- endfor %}
}

#[pyclass(eq, eq_int)]
#[derive(Debug, PartialEq)]
pub enum {{ coo.name }}Enum {
{%- for ca in coo.attributes +%}
  {{ca.base.name|pascal_case}},
{%- endfor %}
}

#[pymethods]
impl {{ coo.name }} {
{%- for ca in coo.attributes +%}
  #[staticmethod]
  fn new_{{ca.base.name|snake_case}}({{ca.base.name|snake_case}}: {%+ if ca.is_msg || ca.is_oo +%}Py<{%- endif -%}
      {{ ca.base_type_str|safe }}{%- if ca.is_msg || ca.is_oo -%}>{% endif %}) -> PyResult<Py<Self>> {
    Ok(Python::with_gil(|_py| { Py::new(_py, Self::{{ca.base.name|pascal_case}}({{ca.base.name|snake_case}})) })?)
  }
{%- endfor %}
  fn __repr__(&self) -> String { format!("{}", self) }
}
impl {{ coo.name }} {
  pub fn to_rust(&self) -> messages::{{ coo.name }} {
    Python::with_gil(|_py| {
      match self { {%- for ca in coo.attributes -%}
        Self::{{ca.base.name|pascal_case}}(v) => messages::{{ coo.name }}::{{ca.base.name|pascal_case}}(do_val_from(v)),
{%+ endfor %}
      }
    })
  }
  pub fn from_rust_obj(d: &messages::{{ coo.name }}) -> PyResult<Self> {
    let r = Python::with_gil(|_py| {
      match d { {%- for ca in coo.attributes -%}
        messages::{{ coo.name }}::{{ca.base.name|pascal_case}}(v) => Self::{{ca.base.name|pascal_case}}(v.val_into()),
{% endfor %}
      }
    });
    Ok(r)
  }
}
impl std::fmt::Display for {{ coo.name }} {
  fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    match self { {%- for ca in coo.attributes -%}{%- if ca.is_msg || ca.is_oo +%}
      {{ coo.name }}::{{ca.base.name|pascal_case}}(v) => {
        Python::with_gil(|py| {
          write!(f, "{{ coo.name }}({{ca.base.name|pascal_case}}({})", v.borrow(py).__repr__()) }
        )},
{%- else +%}
      {{ coo.name }}::{{ca.base.name|pascal_case}}(v) => { write!(f, "{{ coo.name }}({{ca.base.name|pascal_case}}({}))", v) },
{%- endif -%}{%- endfor %}
    }
  }
}

impl ValFromInto<Py<{{coo.name}}>> for messages::{{coo.name}} {
  fn val_into(self: &Self) -> Py<{{coo.name}}> {
    Python::with_gil(|_py| { Py::new(_py, {{coo.name}}::from_rust_obj(self).unwrap()).unwrap() })
  }
  fn val_from(val: &Py<{{coo.name}}>) -> Self {
    Python::with_gil(|_py| { val.borrow(_py).to_rust() })
  }
}
{% endfor +%}

// *****************************************************************
// *****************************************************************
// *** Messages
{% for cm in d.msgs ~%}
{%- if let Some(comment_impl) = cm.comment -%}
///{{comment_impl}}
{%- endif %}
#[pyclass]
#[derive(Debug)]
pub struct {{cm.name}} {
// lala
{% if let Some(p) = cm.parent -%}// parent: {{ p }}{%- endif -%}
{% for ca in cm.attributes +%}
{%- if let Some(comment_impl) = ca.base.comment -%}
//{{comment_impl}}
{%- endif -%}
{# !ca.is_py_wrapped #}
{%- if !ca.is_oo +%}  #[pyo3(get, set)]
{%+ endif +%}  pub {{ca.base.name}}: {% include "pyclasses_attr.py.rs.jinja" %}
{% endfor -%}
}
#[pymethods]
impl {{cm.name}} {
  #[new]  #[allow(non_snake_case)]
  pub fn __new__(
{%- for ca in cm.attributes +%} {{ca.base.name}}: {% include "pyclasses_attr.py.rs.jinja" %}{%- endfor -%}) -> Self {
    Self{ {%- for ca in cm.attributes +%} {{ca.base.name}}: {{ca.base.name}}.into(),{%- endfor +%} }
  }
  #[staticmethod]
  pub fn default() -> PyResult<Self> { Self::from_rust_obj(&Default::default()) }

  pub fn serialize(&self, py: Python) -> (PyObject, u64, u64) {
    let msg = self.to_rust();
    let r = serialize(&msg);
    (PyBytes::new(py, &r.0).into(), r.1.total_bits, r.1.total_bytes)
  }
  #[staticmethod]
  pub fn deserialize(_py: Python, data: Bound<'_, PyBytes>) -> PyResult<Self> {
    let dv: Vec<u8> = data.extract()?;
    let v = match deserialize::<messages::{{cm.name}}>(&dv) {
      Some(v) => v, None => return Err(PyErr::new::<PyException, _>("Error when deserializing {{cm.name}}"))
    };
    Self::from_rust_obj(&v.0)
  }
  pub fn __repr__(&self) -> String {
    format!("{}", self)
  }
{% for ca in cm.attributes +%}{% if ca.is_oo %}{%- if let Some(coo) = d.oos.get(ca.rust_type_str) +%}
  #[getter]
  pub fn {{ca.base.name|snake_case}}_oo(&self) -> {{ca.rust_type_str}}Enum {
    match self.{{ca.base.name|snake_case}}.get() {
{%- for caa in coo.attributes +%}
      {{ca.rust_type_str}}::{{caa.base.name|pascal_case}}(_) => {{ca.rust_type_str}}Enum::{{caa.base.name|pascal_case}},
{%- endfor +%}
  } }
{%- for caa in coo.attributes +%}
  #[getter({{ca.base.name|snake_case}}_{{caa.base.name|snake_case}})]
  fn {{ca.base.name|snake_case}}_get_{{caa.base.name|snake_case}}(&self) -> Option<{%- if !caa.is_enum -%}&{%- endif -%}
    {%- if caa.is_msg || caa.is_oo -%}Py<{%endif%}{{caa.base_type_str|safe}}{%- if caa.is_msg || caa.is_oo -%}>{%endif%}> {
    match self.{{ca.base.name|snake_case}}.get() {
      {{ca.rust_type_str}}::{{caa.base.name|pascal_case}}(v) => Some(v{%- if caa.is_enum -%}.clone(){%- endif -%}), _ => None
  } }
  #[setter({{ca.base.name|snake_case}}_{{caa.base.name|snake_case}})]
  fn {{ca.base.name|snake_case}}_set_{{caa.base.name|snake_case}}(&mut self, v: {%- if caa.is_msg || caa.is_oo -%}
    Py<{%endif%}{{caa.base_type_str|safe}}{%- if caa.is_msg || caa.is_oo -%}>{%endif%}) -> PyResult<()> {
    Python::with_gil(|py| {
      self.{{ca.base.name|snake_case}} = Py::new(py, {{ca.rust_type_str}}::{{caa.base.name|pascal_case}}(v))?;
      Ok(())
    })
  }
{%- endfor -%}{%+ endif -%}{%+ endif -%}{%- endfor %}
}
impl {{cm.name}} {
  pub fn to_rust(&self) -> messages::{{cm.name}} {
    Python::with_gil(|_py| {
      messages::{{cm.name}}{ {%- for ca in cm.attributes +%} {{ca.base.name}}: do_val_from(&self.{{ca.base.name}}), {%- endfor -%}}
    })
  }
  pub fn from_rust_obj(_d: &messages::{{cm.name}}) -> PyResult<Self> {
    let r = Python::with_gil(|_py| { Self{ {%- for ca in cm.attributes +%} {{ca.base.name}}: _d.{{ca.base.name}}.val_into(), {%- endfor -%}} });
    Ok(r)
  }
}
impl std::fmt::Display for {{cm.name}} {
  fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    Python::with_gil(|_py| {
      let t = self.to_rust();
      write!(f, "{}", t)
    })
  }
}
impl ValFromInto<Py<{{cm.name}}>> for messages::{{cm.name}} {
  fn val_into(self: &Self) -> Py<{{cm.name}}> {
    Python::with_gil(|_py| { Py::new(_py, {{cm.name}}::from_rust_obj(self).unwrap()).unwrap() })
  }
  fn val_from(val: &Py<{{cm.name}}>) -> Self {
    Python::with_gil(|_py| { val.borrow(_py).to_rust() })
  }
}

{% endfor %}