diff --git a/generator/src/codegen/codegen_header.rs b/generator/src/codegen/codegen_header.rs index f1195ed..fa6bdfe 100644 --- a/generator/src/codegen/codegen_header.rs +++ b/generator/src/codegen/codegen_header.rs @@ -35,6 +35,11 @@ impl<'a, W: Write> CodeHeaderGenerator<'a, W> { self.doc(packet.doc())?; cg!(self); cg!(self, r#"#include "packetfactory.h""#); + cg!(self); + cg!(self, "#ifndef JSON_USE_IMPLICIT_CONVERSIONS"); + cg!(self, "#define JSON_USE_IMPLICIT_CONVERSIONS 0"); + cg!(self, "#include \"json.hpp\""); + cg!(self, "#endif"); for content in packet.contents() { use self::PacketContent::*; @@ -126,10 +131,68 @@ namespace Packet {{ self.dedent(); cg!(self, "}};"); cg!(self); + + for content in packet.contents() { + use self::PacketContent::*; + match content { + Simple(s) => { + self.simple_type_to_json(packet.class_name(), s)?; + self.simple_type_from_json(packet.class_name(), s)?; + }, + _ => {} + } + } + + cg!(self); + + for content in packet.contents() { + use self::PacketContent::*; + match content { + Complex(c) => { + self.complex_type_to_json(packet.class_name(), c)?; + self.complex_type_from_json(packet.class_name(), c)?; + }, + _ => {} + } + } + + self.packet_to_json(packet)?; + cg!(self); + self.packet_from_json(packet)?; cg!(self, "}}\n}}"); Ok(()) } + fn packet_to_json(&mut self, packet: &Packet) -> Result<()> { + cg!(self, "void to_json(nlohmann::json& j, const {}& data);", packet.class_name()); + Ok(()) + } + + fn packet_from_json(&mut self, _packet: &Packet) -> Result<()> { + Ok(()) + } + + fn simple_type_to_json(&mut self, packet_name: &str, element: &SimpleType) -> Result<()> { + cg!(self, "void to_json(nlohmann::json& j, const {}::{}& data);", packet_name, element.name()); + Ok(()) + } + + fn simple_type_from_json(&mut self, _packet_name: &str, _element: &SimpleType) -> Result<()> { + Ok(()) + } + + fn complex_type_to_json(&mut self, packet_name: &str, element: &ComplexType) -> Result<()> { + if element.inline() == true { + return Ok(()); + } + cg!(self, "void to_json(nlohmann::json& j, const {}::{}& data);", packet_name, element.name()); + Ok(()) + } + + fn complex_type_from_json(&mut self, _packet_name: &str, _element: &ComplexType) -> Result<()> { + Ok(()) + } + fn doc(&mut self, doc: &Option) -> Result<()> { match doc { None => (), diff --git a/generator/src/codegen/codegen_source.rs b/generator/src/codegen/codegen_source.rs index 690ce60..61e45b6 100644 --- a/generator/src/codegen/codegen_source.rs +++ b/generator/src/codegen/codegen_source.rs @@ -269,6 +269,156 @@ impl<'a, W: Write> CodeSourceGenerator<'a, W> { self.dedent(); cg!(self, "}}"); cg!(self); + cg!(self); + + for content in packet.contents() { + use self::PacketContent::*; + match content { + Simple(s) => { + self.simple_type_to_json(packet.class_name(), s)?; + self.simple_type_from_json(packet.class_name(), s)?; + }, + _ => {} + } + } + + cg!(self); + + for content in packet.contents() { + use self::PacketContent::*; + match content { + Complex(c) => { + self.complex_type_to_json(packet.class_name(), c)?; + self.complex_type_from_json(packet.class_name(), c)?; + }, + _ => {} + } + } + + self.packet_to_json(packet)?; + cg!(self); + self.packet_from_json(packet)?; + Ok(()) + } + + fn packet_to_json(&mut self, packet: &Packet) -> Result<()> { + cg!(self, "void RoseCommon::Packet::to_json(nlohmann::json& j, const {}& data) {{", packet.class_name()); + self.indent(); + cg!(self, "j = nlohmann::json{{"); + self.indent(); + cg!(self, "{{ \"metadata\", {{ {{ \"packet\", \"{}\" }}, {{ \"size\", data.get_size() }} }} }},", packet.type_()); + cg!(self, "{{ \"fields\", {{"); + self.indent(); + for content in packet.contents() { + use self::PacketContent::*; + match content { + Element(e) => { + let bitfield = if e.bitset().is_some() { + " == 1" + } else { + "" + }; + cg!(self, "{{ \"{0}\", data.get_{0}(){1} }},", e.name(), bitfield); + } + _ => {} + } + } + self.dedent(); + cg!(self, "}} }}"); + self.dedent(); + cg!(self, "}};"); + self.dedent(); + cg!(self, "}}"); + Ok(()) + } + + fn packet_from_json(&mut self, _packet: &Packet) -> Result<()> { + Ok(()) + } + + fn simple_type_to_json(&mut self, packet_name:&str, element: &SimpleType) -> Result<()> { + cg!(self, "void RoseCommon::Packet::to_json(nlohmann::json& j, const {}::{}& data) {{", packet_name, element.name()); + self.indent(); + cg!(self, "j = nlohmann::json{{"); + self.indent(); + for content in element.contents() { + match content { + SimpleTypeContent::Restriction(res) => { + use self::RestrictionContent::*; + let is_enum = res.contents().iter().find(|content| match content { + Enumeration(_) => true, + _ => false + }).is_some(); + if is_enum { + cg!(self, "{{ \"value\", static_cast<{}>(data) }},", res.base()); + } else { + cg!(self, "{{ \"value\", data.operator {}() }},", res.base()); + } + } + } + } + self.dedent(); + cg!(self, "}};"); + self.dedent(); + cg!(self, "}}"); + Ok(()) + } + + fn simple_type_from_json(&mut self, _packet_name: &str, _element: &SimpleType) -> Result<()> { + Ok(()) + } + + fn complex_type_to_json(&mut self, packet_name: &str, element: &ComplexType) -> Result<()> { + if element.inline() == true { + return Ok(()); + } + cg!(self, "void RoseCommon::Packet::to_json(nlohmann::json& j, const {}::{}& data) {{", packet_name, element.name()); + self.indent(); + use ::flat_ast::ComplexTypeContent::*; + cg!(self, "j = nlohmann::json{{"); + self.indent(); + match element.content() { + Seq(ref s) => { + for elem in s.elements() { + let bitfield = if elem.bitset().is_some() { + " == 1" + } else { + "" + }; + cg!(self, "{{ \"{0}\", data.get_{0}(){1} }},", elem.name(), bitfield); + } + }, + Choice(ref c) => { + for elem in c.elements() { + if let Some(ref seq) = c.inline_seqs().get(elem.name()) { + for e in seq.elements() { + let bitfield = if e.bitset().is_some() { + " == 1" + } else { + "" + }; + cg!(self, "{{ \"{0}\", data.get_{0}(){1} }},", e.name(), bitfield); + } + } else { + let bitfield = if elem.bitset().is_some() { + " == 1" + } else { + "" + }; + cg!(self, "{{ \"{0}\", data.get_{0}(){1} }},", elem.name(), bitfield); + } + } + }, + Empty => {} + } + self.dedent(); + cg!(self, "}};"); + self.dedent(); + cg!(self, "}}"); + Ok(()) + } + + fn complex_type_from_json(&mut self, _packet_name: &str, _element: &ComplexType) -> Result<()> { Ok(()) } diff --git a/generator/src/codegen/mod.rs b/generator/src/codegen/mod.rs index 5999f54..29b1d2d 100644 --- a/generator/src/codegen/mod.rs +++ b/generator/src/codegen/mod.rs @@ -8,4 +8,52 @@ mod macros { } } pub mod codegen_header; -pub mod codegen_source; \ No newline at end of file +pub mod codegen_source; + +#[cfg(test)] +mod tests { + use crate::{flat_ast::Packet, writer::Writer}; + use super::{codegen_header}; + + struct StringWriter { + output: String + } + + impl StringWriter { + fn new() -> Self { + Self { output: String::new() } + } + } + + impl std::io::Write for StringWriter { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.output += std::str::from_utf8(buf).unwrap(); + Ok(buf.len()) + } + + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } + } + + impl Into for StringWriter { + fn into(self) -> String { + self.output + } + } + + fn call_header(packet: &Packet) -> std::io::Result { + let writer = StringWriter::new(); + let mut writer = Writer::new(writer); + let mut codegen = codegen_header::CodeHeaderGenerator::new(&mut writer, "0".to_string()); + codegen.generate(packet)?; + Ok(writer.into().into()) + } + + #[test] + fn empty_packet() { + let packet = Packet::new("PAKCS_PACKET".to_owned(), None); + let result = call_header(&packet); + assert!(result.is_ok()); + } +} \ No newline at end of file diff --git a/generator/src/writer.rs b/generator/src/writer.rs index a6e71ed..5a3b1a6 100644 --- a/generator/src/writer.rs +++ b/generator/src/writer.rs @@ -13,6 +13,11 @@ impl Writer { } } + #[cfg(test)] + pub fn into(self) -> T { + self.writer + } + fn pad(&mut self) -> Result<&mut Self> { for _ in 0..self.indent { self.writer.write(b" ")?; diff --git a/srv_test.cpp b/srv_test.cpp index 6c898dd..7cdd665 100644 --- a/srv_test.cpp +++ b/srv_test.cpp @@ -3,6 +3,43 @@ using namespace RoseCommon; using namespace RoseCommon::Packet; +SrvTest::Bbb::Bbb() : is_valid(false) {} + +SrvTest::Bbb::Bbb(std::string data) : bbb(data), is_valid(false) { + bool valid = true; + if (bbb.size() > 3) { + bbb.resize(3); + valid &= true; + } else { + valid &= true; + } + is_valid = valid; +} + +bool SrvTest::Bbb::read(CRoseReader& reader) { + bool valid = true; + if (!reader.get_string(bbb, 3)) { + return false; + } else { + valid &= true; + } + is_valid = valid; + return true; +} + +bool SrvTest::Bbb::write(CRoseBasePolicy& writer) const { + if (!writer.set_string(bbb, 3)) { + return false; + } + return true; +} + +constexpr size_t SrvTest::Bbb::size() { + size_t size = 0; + size += 3; // bbb + return size; +} + SrvTest::Pote& SrvTest::Pote::set_a(const uint8_t a) { this->data.a = a; @@ -108,19 +145,28 @@ SrvTest::SrvTest(CRoseReader reader) : CRosePacket(reader) { set_server_packet(); if (!reader.get_bitset(bitset1)) { - return false; + return; } if (!reader.get_uint32_t(c)) { - return false; + return; } if (!reader.get_bitset(bitset2)) { - return false; + return; } if (!reader.get_iserialize(pote)) { - return false; + return; } if (!reader.get_iserialize(pote2)) { - return false; + return; + } + uint8_t x_temp; + if (!reader.get_uint8_t(x_temp)) { + return; + } + x = static_cast(x_temp); + + if (!reader.get_iserialize(y)) { + return; } } @@ -256,7 +302,25 @@ SrvTest::Pote2 SrvTest::get_pote2() const { return pote2; } -SrvTest SrvTest::create(const uint32_t& a, const uint32_t& b, const uint32_t& c, const uint32_t& d, const uint32_t& e, const uint32_t& f, const uint32_t& g, const uint32_t& h, const SrvTest::Pote& pote, const SrvTest::Pote2& pote2) { +SrvTest& SrvTest::set_x(const SrvTest::Aaa x) { + this->x = x; + return *this; +} + +SrvTest::Aaa SrvTest::get_x() const { + return x; +} + +SrvTest& SrvTest::set_y(const SrvTest::Bbb y) { + this->y = y; + return *this; +} + +SrvTest::Bbb SrvTest::get_y() const { + return y; +} + +SrvTest SrvTest::create(const uint32_t& a, const uint32_t& b, const uint32_t& c, const uint32_t& d, const uint32_t& e, const uint32_t& f, const uint32_t& g, const uint32_t& h, const SrvTest::Pote& pote, const SrvTest::Pote2& pote2, const SrvTest::Aaa& x, const SrvTest::Bbb& y) { SrvTest packet; packet.set_a(a); packet.set_b(b); @@ -268,6 +332,8 @@ SrvTest SrvTest::create(const uint32_t& a, const uint32_t& b, const uint32_t& c, packet.set_h(h); packet.set_pote(pote); packet.set_pote2(pote2); + packet.set_x(x); + packet.set_y(y); return packet; } @@ -297,6 +363,12 @@ bool SrvTest::pack(CRoseBasePolicy& writer) const { if (!writer.set_iserialize(pote2)) { return false; } + if (!writer.set_uint8_t(x)) { + return false; + } + if (!writer.set_iserialize(y)) { + return false; + } return true; } @@ -307,6 +379,53 @@ constexpr size_t SrvTest::size() { size += 48 / 8; // bitset2 size += Pote::size(); // pote size += Pote2::size(); // pote2 + size += sizeof(Aaa); // x + size += Bbb::size(); // y return size; } + +void RoseCommon::Packet::to_json(nlohmann::json& j, const SrvTest::Aaa& data) { + j = nlohmann::json{ + { "value", static_cast(data) }, + }; +} +void RoseCommon::Packet::to_json(nlohmann::json& j, const SrvTest::Bbb& data) { + j = nlohmann::json{ + { "value", data.operator std::string() }, + }; +} + +void RoseCommon::Packet::to_json(nlohmann::json& j, const SrvTest::Pote& data) { + j = nlohmann::json{ + { "a", data.get_a() }, + { "b", data.get_b() }, + { "c", data.get_c() }, + }; +} +void RoseCommon::Packet::to_json(nlohmann::json& j, const SrvTest::Pote2& data) { + j = nlohmann::json{ + { "a", data.get_a() == 1 }, + { "b", data.get_b() == 1 }, + }; +} +void RoseCommon::Packet::to_json(nlohmann::json& j, const SrvTest& data) { + j = nlohmann::json{ + { "metadata", { "packet", "PAKWC_TEST" }, { "size", data.get_size() } }, + { "fields", { + { "a", data.get_a() == 1 }, + { "b", data.get_b() == 1 }, + { "c", data.get_c() }, + { "d", data.get_d() == 1 }, + { "e", data.get_e() == 1 }, + { "f", data.get_f() == 1 }, + { "g", data.get_g() == 1 }, + { "h", data.get_h() == 1 }, + { "pote", data.get_pote() }, + { "pote2", data.get_pote2() }, + { "x", data.get_x() }, + { "y", data.get_y() }, + } } + }; +} + diff --git a/srv_test.h b/srv_test.h index 4f7e971..eda313e 100644 --- a/srv_test.h +++ b/srv_test.h @@ -1,9 +1,14 @@ #pragma once -/* Generated with IDL v0.1.4 */ +/* Generated with IDL v0.1.5 */ #include "packetfactory.h" + +#ifndef JSON_USE_IMPLICIT_CONVERSIONS +#define JSON_USE_IMPLICIT_CONVERSIONS 0 +#include "json.hpp" +#endif #include namespace RoseCommon { @@ -21,6 +26,34 @@ class SrvTest : public CRosePacket { static constexpr size_t size(); + enum Aaa : uint8_t { + ABC = 0, + DEF = 1, + GHI = 2, + }; + + struct Bbb : public ISerialize { + Bbb(); + Bbb(std::string); + Bbb(const Bbb&) = default; + Bbb(Bbb&&) = default; + Bbb& operator=(const Bbb&) = default; + Bbb& operator=(Bbb&&) = default; + virtual ~Bbb() = default; + + static constexpr size_t size(); + + operator std::string() const { return bbb; } + bool isValid() const { return is_valid; } + + virtual bool read(CRoseReader&) override; + virtual bool write(CRoseBasePolicy&) const override; + + private: + std::string bbb; + bool is_valid; + }; + struct Pote : public ISerialize { virtual bool read(CRoseReader&) override; virtual bool write(CRoseBasePolicy&) const override; @@ -80,9 +113,13 @@ class SrvTest : public CRosePacket { Pote get_pote() const; SrvTest& set_pote2(const Pote2); Pote2 get_pote2() const; + SrvTest& set_x(const Aaa); + Aaa get_x() const; + SrvTest& set_y(const Bbb); + Bbb get_y() const; - static SrvTest create(const uint32_t& a, const uint32_t& b, const uint32_t& c, const uint32_t& d, const uint32_t& e, const uint32_t& f, const uint32_t& g, const uint32_t& h, const Pote& pote, const Pote2& pote2); + static SrvTest create(const uint32_t& a, const uint32_t& b, const uint32_t& c, const uint32_t& d, const uint32_t& e, const uint32_t& f, const uint32_t& g, const uint32_t& h, const Pote& pote, const Pote2& pote2, const Aaa& x, const Bbb& y); static SrvTest create(const uint8_t* buffer); static std::unique_ptr allocate(const uint8_t* buffer); @@ -95,7 +132,16 @@ class SrvTest : public CRosePacket { std::bitset<48> bitset2; Pote pote; Pote2 pote2; + Aaa x; + Bbb y; }; +void to_json(nlohmann::json& j, const SrvTest::Aaa& data); +void to_json(nlohmann::json& j, const SrvTest::Bbb& data); + +void to_json(nlohmann::json& j, const SrvTest::Pote& data); +void to_json(nlohmann::json& j, const SrvTest::Pote2& data); +void to_json(nlohmann::json& j, const SrvTest& data); + } } diff --git a/test.xml b/test.xml index a850062..f06af10 100644 --- a/test.xml +++ b/test.xml @@ -9,6 +9,8 @@ + + @@ -26,4 +28,18 @@ + + + + + + + + + + + + + +