-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- add: start of code generator for rust
- fix: unable to add new generator due to generator not being boxed
- Loading branch information
Showing
6 changed files
with
234 additions
and
7 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
[package] | ||
name = "packet_generator" | ||
version = "0.2.0" | ||
version = "0.2.2" | ||
authors = ["L3nn0x <[email protected]>"] | ||
|
||
[dependencies] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
use ::flat_ast::*; | ||
use std::io::{Result, Write}; | ||
use ::heck::*; | ||
use std::collections::HashSet; | ||
|
||
pub (crate) struct CodeSourceGenerator<'a, W: Write + 'a> { | ||
writer: &'a mut ::writer::Writer<W>, | ||
version: String | ||
} | ||
|
||
impl<'a, W: Write> CodeSourceGenerator<'a, W> { | ||
pub fn new(writer: &'a mut ::writer::Writer<W>, version: String) -> Self { | ||
Self { | ||
writer, | ||
version | ||
} | ||
} | ||
|
||
fn indent(&mut self) { | ||
self.writer.indent(); | ||
} | ||
|
||
fn dedent(&mut self) { | ||
self.writer.dedent(); | ||
} | ||
|
||
fn write(&mut self, val: impl AsRef<str>) -> Result<&mut Self> { | ||
self.writer.write(val)?; | ||
Ok(self) | ||
} | ||
|
||
pub fn generate(&mut self, packet: &Packet) -> Result<()> { | ||
let version = self.version.clone(); | ||
cg!(self, "/* Generated with IDL v{} */\n", version); | ||
cg!(self); | ||
cg!(self, r#"use bincode::{{Encode, Decode}};"#); | ||
cg!(self); | ||
|
||
|
||
cg!(self, r#"#[derive(Debug, Encode, Decode)]"#); | ||
|
||
let iserialize = packet.contents().iter().filter_map(|elem| { | ||
if PacketContent::is_type(elem) { | ||
PacketContent::type_from_name(elem) | ||
} else { | ||
match elem { | ||
PacketContent::Element(ref e) => { | ||
match e.type_().as_ref() { | ||
"int8_t" => Some("i8".to_string()), | ||
"uint8_t" => Some("u8".to_string()), | ||
"int16_t" => Some("i16".to_string()), | ||
"uint16_t" => Some("u16".to_string()), | ||
"int32_t" => Some("i32".to_string()), | ||
"uint32_t" => Some("u32".to_string()), | ||
"int64_t" => Some("i64".to_string()), | ||
"uint64_t" => Some("u64".to_string()), | ||
"char" => Some("u8".to_string()), | ||
"float" => Some("f32".to_string()), | ||
"double" => Some("f64".to_string()), | ||
"std::string" => Some("String".to_string()), | ||
_ => Some(e.type_().to_string()) | ||
} | ||
}, | ||
_ => None | ||
} | ||
} | ||
}).collect::<::std::collections::HashSet<String>>(); | ||
|
||
// Need to drop out the struct | ||
cg!(self, "pub struct {} {{", packet.class_name()); | ||
self.indent(); | ||
for content in packet.contents() { | ||
use self::PacketContent::*; | ||
match content { | ||
Element(ref elem) => self.element(elem)?, | ||
_ => {} | ||
}; | ||
} | ||
self.dedent(); | ||
cg!(self, "}}"); | ||
|
||
|
||
Ok(()) | ||
} | ||
|
||
fn doc(&mut self, doc: &Option<String>) -> Result<()> { | ||
match doc { | ||
None => (), | ||
Some(doc) => { | ||
for line in doc.lines() { | ||
match line.trim() { | ||
"" => (), | ||
line => { | ||
cg!(self, "// {}", line); | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
Ok(()) | ||
} | ||
|
||
fn element(&mut self, elem: &Element) -> Result<()> { | ||
self.doc(elem.doc())?; | ||
|
||
if let Some(bitset) = elem.bitset() { | ||
if bitset.start == 0 { | ||
cg!(self, "{}: [bool; {}],", bitset.name, bitset.size); | ||
} | ||
return Ok(()); | ||
} | ||
|
||
let (type_, bits) = if let Some(ref o) = elem.occurs() { | ||
use ::flat_ast::Occurs::*; | ||
let type_ = match o { | ||
Unbounded => format!("Vec<{}>", elem.type_()), | ||
Num(n) => format!("[{}; {}]", elem.type_(), n) | ||
}; | ||
(type_, "".to_string()) | ||
} else { | ||
let bits = elem.bits().map_or_else(|| "".to_string(), |b| format!(" : {}", b)); | ||
(elem.type_().to_owned(), bits) | ||
}; | ||
let default = match elem.init() { | ||
self::ElementInitValue::Default(d) => " = ".to_string() + d, | ||
_ => "".to_string() | ||
}; | ||
cg!(self, "{}: {}{}{},", elem.name(), type_, bits, default); | ||
Ok(()) | ||
} | ||
} | ||
|
||
fn clean_base(base: &str) -> String { | ||
if base.contains("::") { | ||
base.split("::").skip(1).collect() | ||
} else { | ||
base.to_string() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
use std::fs::File; | ||
use std::path::PathBuf; | ||
use codegen::Codegen; | ||
use ::{flat_ast, writer}; | ||
|
||
mod codegen_source; | ||
|
||
pub struct Generator { | ||
output: PathBuf | ||
} | ||
|
||
impl Generator { | ||
pub fn new(args: &RustArgs) -> Self { | ||
Self{ | ||
output: args.output_folder.clone().into() | ||
} | ||
} | ||
} | ||
|
||
impl Codegen for Generator { | ||
fn generate(&mut self, version: &str, packet: &flat_ast::Packet) -> Result<(), failure::Error> { | ||
let source_output = File::create(self.output.to_str().unwrap().to_owned() + &format!("/{}.rs", packet.filename()))?; | ||
debug!("source {:?}", source_output); | ||
let mut writer = writer::Writer::new(source_output); | ||
let mut codegen = codegen_source::CodeSourceGenerator::new(&mut writer, version.to_string()); | ||
codegen.generate(&packet)?; | ||
Ok(()) | ||
} | ||
} | ||
|
||
#[derive(clap::Args, Debug)] | ||
#[command(name="rust")] | ||
pub struct RustArgs { | ||
#[arg(long)] | ||
output_folder: String | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::{flat_ast::Packet, writer::Writer}; | ||
use super::{codegen_source}; | ||
|
||
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_source::CodeSourceGenerator::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()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters