Skip to content

Commit

Permalink
Merge pull request #18 from dev-osrose/json
Browse files Browse the repository at this point in the history
JSON serializer for packets
  • Loading branch information
RavenX8 authored Jun 13, 2021
2 parents 094a552 + c556fd2 commit 317bb82
Show file tree
Hide file tree
Showing 7 changed files with 456 additions and 9 deletions.
63 changes: 63 additions & 0 deletions generator/src/codegen/codegen_header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand Down Expand Up @@ -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<String>) -> Result<()> {
match doc {
None => (),
Expand Down
150 changes: 150 additions & 0 deletions generator/src/codegen/codegen_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}

Expand Down
50 changes: 49 additions & 1 deletion generator/src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,52 @@ mod macros {
}
}
pub mod codegen_header;
pub mod codegen_source;
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<usize> {
self.output += std::str::from_utf8(buf).unwrap();
Ok(buf.len())
}

fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}

impl Into<String> for StringWriter {
fn into(self) -> String {
self.output
}
}

fn call_header(packet: &Packet) -> std::io::Result<String> {
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());
}
}
5 changes: 5 additions & 0 deletions generator/src/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ impl<T: Write> Writer<T> {
}
}

#[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" ")?;
Expand Down
Loading

0 comments on commit 317bb82

Please sign in to comment.