Skip to content

Commit c99c4c2

Browse files
committed
- add: custom encoder and decoder for main struct and restricted types
1 parent 5e252df commit c99c4c2

File tree

1 file changed

+195
-9
lines changed

1 file changed

+195
-9
lines changed

generator/src/codegen/rust/codegen_source.rs

Lines changed: 195 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use ::flat_ast::*;
22
use std::io::{Result, Write};
33
use ::heck::*;
44
use std::collections::HashMap;
5+
use flat_ast::RestrictionContent::{Enumeration, Length, MaxValue, MinValue};
56

67
pub (crate) struct CodeSourceGenerator<'a, W: Write + 'a> {
78
writer: &'a mut ::writer::Writer<W>,
@@ -32,7 +33,9 @@ impl<'a, W: Write> CodeSourceGenerator<'a, W> {
3233
pub fn generate(&mut self, packet: &Packet) -> Result<()> {
3334
let version = self.version.clone();
3435
cg!(self, "/* Generated with IDL v{} */\n", version);
35-
cg!(self, r#"use bincode::{{Encode, Decode}};"#);
36+
cg!(self, r#"use bincode::{{Encode, Decode, enc::Encoder, de::Decoder, error::DecodeError}};"#);
37+
cg!(self, r#"use bincode::de::read::Reader;"#);
38+
cg!(self, r#"use bincode::enc::write::Writer;"#);
3639
cg!(self, r#"use crate::packet::PacketPayload;"#);
3740

3841
let mut iserialize: HashMap<String, String> = HashMap::new();
@@ -70,7 +73,7 @@ impl<'a, W: Write> CodeSourceGenerator<'a, W> {
7073

7174
cg!(self);
7275

73-
cg!(self, r#"#[derive(Debug, Encode, Decode)]"#);
76+
cg!(self, r#"#[derive(Debug)]"#);
7477
cg!(self, "pub struct {} {{", packet.class_name().to_upper_camel_case());
7578
self.indent();
7679
for content in packet.contents() {
@@ -85,6 +88,62 @@ impl<'a, W: Write> CodeSourceGenerator<'a, W> {
8588

8689
cg!(self);
8790
cg!(self, "impl PacketPayload for {} {{}}", packet.class_name().to_upper_camel_case());
91+
cg!(self);
92+
cg!(self, "impl Encode for {} {{", packet.class_name().to_upper_camel_case());
93+
self.indent();
94+
cg!(self, "fn encode<E: Encoder>(&self, encoder: &mut E) -> std::result::Result<(), bincode::error::EncodeError> {{");
95+
self.indent();
96+
for content in packet.contents() {
97+
use self::PacketContent::*;
98+
match content {
99+
Element(ref elem) => {
100+
let name = rename_if_reserved(elem.name());
101+
cg!(self, "self.{}.encode(encoder)?;", name);
102+
},
103+
_ => {}
104+
};
105+
}
106+
cg!(self, "Ok(())");
107+
self.dedent();
108+
cg!(self, "}}");
109+
self.dedent();
110+
cg!(self, "}}");
111+
112+
cg!(self);
113+
cg!(self, "impl Decode for {} {{", packet.class_name().to_upper_camel_case());
114+
self.indent();
115+
cg!(self, "fn decode<D: Decoder>(decoder: &mut D) -> std::result::Result<Self, bincode::error::DecodeError> {{");
116+
self.indent();
117+
for content in packet.contents() {
118+
use self::PacketContent::*;
119+
match content {
120+
Element(ref elem) => {
121+
let name = rename_if_reserved(elem.name());
122+
let trimmed_type = elem.type_().trim().to_string();
123+
let rust_type = iserialize.get(elem.type_().trim()).unwrap_or_else(|| {
124+
debug!(r#"Type "{}" not found, outputting anyway"#, elem.type_());
125+
&trimmed_type
126+
});
127+
cg!(self, "let {} = {}::decode(decoder)?;", name, rust_type);
128+
},
129+
_ => {}
130+
};
131+
}
132+
cg!(self, "Ok({} {{", packet.class_name().to_upper_camel_case());
133+
for content in packet.contents() {
134+
use self::PacketContent::*;
135+
match content {
136+
Element(ref elem) => {
137+
cg!(self, "{},", rename_if_reserved(elem.name()));
138+
},
139+
_ => {}
140+
};
141+
}
142+
cg!(self, "}})");
143+
self.dedent();
144+
cg!(self, "}}");
145+
self.dedent();
146+
cg!(self, "}}");
88147

89148

90149
Ok(())
@@ -216,7 +275,7 @@ impl<'a, W: Write> CodeSourceGenerator<'a, W> {
216275
// };
217276
let name = rename_if_reserved(elem.name());
218277
// cg!(self, "{}: {}{}{},", elem.name(), type_, bits, default);
219-
cg!(self, "{}: {}{},", name, type_, bits);
278+
cg!(self, "pub(crate) {}: {}{},", name, type_, bits);
220279
Ok(())
221280
}
222281

@@ -235,8 +294,8 @@ impl<'a, W: Write> CodeSourceGenerator<'a, W> {
235294

236295
if is_enum {
237296
cg!(self, r#"#[repr({})]"#, rust_type);
238-
cg!(self, r#"#[derive(Debug, Encode, Decode)]"#);
239-
cg!(self, "enum {} {{", name.to_upper_camel_case());
297+
cg!(self, r#"#[derive(Debug, Clone)]"#);
298+
cg!(self, "pub(crate) enum {} {{", name.to_upper_camel_case());
240299
self.indent();
241300
for content in restrict.contents() {
242301
if let Enumeration(en) = content {
@@ -245,14 +304,142 @@ impl<'a, W: Write> CodeSourceGenerator<'a, W> {
245304
}
246305
}
247306
} else {
248-
cg!(self, r#"#[derive(Debug, Encode, Decode)]"#);
249-
cg!(self, "struct {} {{", name.to_upper_camel_case());
307+
cg!(self, r#"#[derive(Debug)]"#);
308+
cg!(self, "pub struct {} {{", name.to_upper_camel_case());
250309
self.indent();
251-
cg!(self, "{}: {},", name.to_string().to_snake_case(), rust_type);
310+
cg!(self, "pub(crate) {}: {},", name.to_string().to_snake_case(), rust_type);
252311
}
253312

254313
self.dedent();
255314
cg!(self, "}}");
315+
316+
cg!(self);
317+
self.restrict_encode(&restrict, name, iserialize)?;
318+
cg!(self);
319+
self.restrict_decode(&restrict, name, iserialize)?;
320+
Ok(())
321+
}
322+
323+
fn restrict_encode(&mut self, restrict: &Restriction, name: &str, iserialize: &HashMap<String, String>) -> Result<()> {
324+
let is_enum = restrict.contents().iter().find(|content| match content {
325+
Enumeration(_) => true,
326+
_ => false
327+
}).is_some();
328+
let trimmed_type = restrict.base().trim().to_string();
329+
let rust_type = iserialize.get(restrict.base().trim()).unwrap_or_else(|| {
330+
debug!(r#"Type "{}" not found, outputting anyway"#, restrict.base());
331+
&trimmed_type
332+
});
333+
334+
cg!(self, "impl Encode for {} {{", name.to_upper_camel_case());
335+
self.indent();
336+
cg!(self, "fn encode<E: Encoder>(&self, encoder: &mut E) -> std::result::Result<(), bincode::error::EncodeError> {{");
337+
self.indent();
338+
if is_enum {
339+
cg!(self, "encoder.writer().write(&[self.clone() as u8]).map_err(Into::into)");
340+
} else {
341+
let data = name.to_string().to_snake_case();
342+
cg!(self, "let bytes = self.{}.as_bytes();", data);
343+
for content in restrict.contents() {
344+
match content {
345+
Length(l) => {
346+
cg!(self, "let fixed_length = {};", l);
347+
cg!(self, "if bytes.len() > fixed_length {{");
348+
self.indent();
349+
cg!(self, "return Err(bincode::error::EncodeError::OtherString(format!(");
350+
cg!(self, "\"{} length exceeds fixed size: {{}} > {{}}\", bytes.len(), fixed_length)));", data);
351+
self.dedent();
352+
cg!(self, "}}");
353+
cg!(self, "encoder.writer().write(bytes)?;");
354+
cg!(self, "encoder.writer().write(&vec![0; fixed_length - bytes.len()])?;");
355+
cg!(self, "Ok(())");
356+
},
357+
MinValue(v) => {
358+
359+
},
360+
MaxValue(v) => {
361+
362+
},
363+
_ => panic!("enumeration in restrict when there shouldn't be one")
364+
}
365+
}
366+
}
367+
self.dedent();
368+
cg!(self, "}}");
369+
self.dedent();
370+
cg!(self, "}}");
371+
372+
Ok(())
373+
}
374+
375+
fn restrict_decode(&mut self, restrict: &Restriction, name: &str, iserialize: &HashMap<String, String>) -> Result<()> {
376+
let is_enum = restrict.contents().iter().find(|content| match content {
377+
Enumeration(_) => true,
378+
_ => false
379+
}).is_some();
380+
let trimmed_type = restrict.base().trim().to_string();
381+
let rust_type = iserialize.get(restrict.base().trim()).unwrap_or_else(|| {
382+
debug!(r#"Type "{}" not found, outputting anyway"#, restrict.base());
383+
&trimmed_type
384+
});
385+
386+
cg!(self, "impl Decode for {} {{", name.to_upper_camel_case());
387+
self.indent();
388+
cg!(self, "fn decode<D: Decoder>(decoder: &mut D) -> std::result::Result<Self, bincode::error::DecodeError> {{");
389+
self.indent();
390+
if is_enum {
391+
cg!(self, "let value = {}::decode(decoder)?;", rust_type);
392+
cg!(self, "match value {{");
393+
self.indent();
394+
for content in restrict.contents() {
395+
if let Enumeration(en) = content {
396+
cg!(self, "{} => Ok({}::{}),", en.id(), name.to_upper_camel_case(), en.value().to_upper_camel_case());
397+
}
398+
}
399+
cg!(self, "_ => Err(bincode::error::DecodeError::OtherString(format!(\"Invalid value for {}: {{}}\", value))),", name.to_upper_camel_case());
400+
self.dedent();
401+
cg!(self, "}}");
402+
} else {
403+
let data = name.to_string().to_snake_case();
404+
let mut fixed_length = 64;
405+
let mut minValueCheck = String::new();
406+
let mut maxValueCheck = String::new();
407+
for content in restrict.contents() {
408+
match content {
409+
Length(l) => {
410+
fixed_length = *l;
411+
},
412+
MinValue(v) => {
413+
minValueCheck = format!("if {} < {} {{Err(bincode::error::DecodeError::OtherString(format!(\"Invalid value for {}: {{}} < {{}}\", {}, {})))}}", data, v, data, data, v).into();
414+
},
415+
MaxValue(v) => {
416+
maxValueCheck = format!("if {} > {} {{Err(bincode::error::DecodeError::OtherString(format!(\"Invalid value for {}: {{}} > {{}}\", {}, {})))}}", data, v, data, data, v).into();
417+
},
418+
_ => panic!("enumeration in restrict when there shouldn't be one")
419+
}
420+
}
421+
422+
if rust_type == "String" {
423+
cg!(self, "let mut buffer = vec![0u8; {}];", fixed_length);
424+
cg!(self, "decoder.reader().read(&mut buffer)?;");
425+
cg!(self, "let {} = {}::from_utf8(buffer)", data, rust_type);
426+
cg!(self, ".map_err(|e| DecodeError::OtherString(format!(\"Invalid UTF-8: {{}}\", e)))?");
427+
cg!(self, ".trim_end_matches('\\0')");
428+
cg!(self, ".to_string();");
429+
} else {
430+
cg!(self, "let {} = {}::decode(buffer)?;", data, rust_type);
431+
432+
cg!(self, "{}", minValueCheck);
433+
434+
cg!(self, "{}", maxValueCheck);
435+
}
436+
cg!(self, "Ok({} {{ {} }})", name.to_upper_camel_case(), data);
437+
}
438+
self.dedent();
439+
cg!(self, "}}");
440+
self.dedent();
441+
cg!(self, "}}");
442+
256443
Ok(())
257444
}
258445
}
@@ -273,4 +460,3 @@ fn rename_if_reserved(name: &str) -> String {
273460
name.to_string().to_snake_case()
274461
}
275462
}
276-

0 commit comments

Comments
 (0)