aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenri Chataing <henrichataing@google.com>2023-11-14 02:36:53 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-11-14 02:36:53 +0000
commitd770ef02d402716726c2f4bc1874e0d1b80334dc (patch)
tree40b5fb74851bbe10e4eedcb94a663faf615c15bb
parent1968009054c3e6bed404d646672d4220f5666838 (diff)
parent9c933187bc08c8a943a6db66c4670aa956c8c738 (diff)
downloadpdl-compiler-d770ef02d402716726c2f4bc1874e0d1b80334dc.tar.gz
Upgrade pdl-compiler to 0.2.3 am: 9c933187bc
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/pdl-compiler/+/2828637 Change-Id: Ia0b30f8e15b6c144676dbc8ad8b82e5eeaa70e57 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--Android.bp8
-rw-r--r--Cargo.toml2
-rw-r--r--Cargo.toml.orig2
-rw-r--r--METADATA8
-rw-r--r--cargo2android_toplevel.bp3
-rw-r--r--patches/0001-Add-scripts-Android.bp.patch4
-rw-r--r--src/backends/intermediate.rs23
-rw-r--r--src/backends/rust.rs10
-rw-r--r--src/backends/rust/parser.rs41
-rw-r--r--src/backends/rust/serializer.rs14
-rw-r--r--src/backends/rust_no_allocation/mod.rs8
-rw-r--r--src/bin/generate-canonical-tests.rs1
-rw-r--r--src/lib.rs62
-rw-r--r--tests/generated/payload_with_size_modifier_big_endian.rs187
-rw-r--r--tests/generated/payload_with_size_modifier_little_endian.rs187
-rwxr-xr-xtests/run_rust_generator_tests.sh2
16 files changed, 506 insertions, 56 deletions
diff --git a/Android.bp b/Android.bp
index c23fce5..db9f603 100644
--- a/Android.bp
+++ b/Android.bp
@@ -7,7 +7,7 @@ rust_binary_host {
name: "generate_canonical_tests",
crate_name: "generate_canonical_tests",
cargo_env_compat: true,
- cargo_pkg_version: "0.2.2",
+ cargo_pkg_version: "0.2.3",
srcs: ["src/bin/generate-canonical-tests.rs"],
edition: "2021",
features: [
@@ -35,7 +35,7 @@ rust_library_host {
name: "libpdl_compiler",
crate_name: "pdl_compiler",
cargo_env_compat: true,
- cargo_pkg_version: "0.2.2",
+ cargo_pkg_version: "0.2.3",
srcs: ["src/lib.rs"],
edition: "2021",
features: [
@@ -62,7 +62,7 @@ rust_binary_host {
name: "pdlc",
crate_name: "pdlc",
cargo_env_compat: true,
- cargo_pkg_version: "0.2.2",
+ cargo_pkg_version: "0.2.3",
srcs: ["src/main.rs"],
edition: "2021",
features: [
@@ -296,7 +296,6 @@ genrule {
" --exclude-declaration PartialChild5_B" +
" --exclude-declaration PartialChild12_A" +
" --exclude-declaration PartialChild12_B" +
- " --exclude-declaration Packet_Payload_Field_SizeModifier" +
" --exclude-declaration Packet_Array_Field_UnsizedElement_SizeModifier" +
" --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier_" +
" --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier" +
@@ -321,7 +320,6 @@ genrule {
" --exclude-declaration Struct_Checksum_Field_FromStart" +
" --exclude-declaration Struct_Checksum_Field_FromEnd_" +
" --exclude-declaration Struct_Checksum_Field_FromEnd" +
- " --exclude-declaration Packet_Payload_Field_SizeModifier" +
" --exclude-declaration Packet_Array_Field_UnsizedElement_SizeModifier" +
" --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier_" +
" --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier" +
diff --git a/Cargo.toml b/Cargo.toml
index 411fd67..b0aa493 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,7 +12,7 @@
[package]
edition = "2021"
name = "pdl-compiler"
-version = "0.2.2"
+version = "0.2.3"
authors = [
"Henri Chataing <henrichataing@google.com>",
"David de Jesus Duarte <licorne@google.com>",
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index a50b93f..4d86b22 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
[package]
name = "pdl-compiler"
-version = "0.2.2"
+version = "0.2.3"
edition = "2021"
description = "Parser and serializer generator for protocol binary packets"
repository = "https://github.com/google/pdl/"
diff --git a/METADATA b/METADATA
index 720df9b..0680736 100644
--- a/METADATA
+++ b/METADATA
@@ -11,13 +11,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/pdl-compiler/pdl-compiler-0.1.6.crate"
+ value: "https://static.crates.io/crates/pdl-compiler/pdl-compiler-0.2.3.crate"
}
- version: "0.1.6"
+ version: "0.2.3"
license_type: NOTICE
last_upgrade_date {
year: 2023
- month: 8
- day: 12
+ month: 11
+ day: 13
}
}
diff --git a/cargo2android_toplevel.bp b/cargo2android_toplevel.bp
index 123dff1..76aee62 100644
--- a/cargo2android_toplevel.bp
+++ b/cargo2android_toplevel.bp
@@ -7,6 +7,7 @@ genrule_defaults {
"//system/nfc:__subpackages__",
"//external/uwb/src",
"//packages/modules/Bluetooth:__subpackages__",
+ "//tools/netsim:__subpackages__",
],
}
@@ -207,7 +208,6 @@ genrule {
" --exclude-declaration PartialChild5_B" +
" --exclude-declaration PartialChild12_A" +
" --exclude-declaration PartialChild12_B" +
- " --exclude-declaration Packet_Payload_Field_SizeModifier" +
" --exclude-declaration Packet_Array_Field_UnsizedElement_SizeModifier" +
" --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier_" +
" --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier" +
@@ -232,7 +232,6 @@ genrule {
" --exclude-declaration Struct_Checksum_Field_FromStart" +
" --exclude-declaration Struct_Checksum_Field_FromEnd_" +
" --exclude-declaration Struct_Checksum_Field_FromEnd" +
- " --exclude-declaration Packet_Payload_Field_SizeModifier" +
" --exclude-declaration Packet_Array_Field_UnsizedElement_SizeModifier" +
" --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier_" +
" --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier" +
diff --git a/patches/0001-Add-scripts-Android.bp.patch b/patches/0001-Add-scripts-Android.bp.patch
index b5f4f1f..30817f9 100644
--- a/patches/0001-Add-scripts-Android.bp.patch
+++ b/patches/0001-Add-scripts-Android.bp.patch
@@ -14,7 +14,7 @@ new file mode 100644
index 0000000..bb0932c
--- /dev/null
+++ b/scripts/Android.bp
-@@ -0,0 +1,43 @@
+@@ -0,0 +1,58 @@
+// Python generator.
+python_binary_host {
+ name: "pdl_python_generator",
@@ -73,6 +73,6 @@ index 0000000..bb0932c
+ host_supported: true,
+ vendor_available: true,
+}
---
+--
2.41.0.487.g6d72f3e995-goog
diff --git a/src/backends/intermediate.rs b/src/backends/intermediate.rs
index 9c3c231..4c92ae0 100644
--- a/src/backends/intermediate.rs
+++ b/src/backends/intermediate.rs
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use std::collections::{hash_map::Entry, HashMap};
+use std::collections::{btree_map::Entry, BTreeMap, HashMap};
use crate::ast;
use crate::parser;
@@ -23,8 +23,8 @@ pub struct Schema<'a> {
}
pub struct PacketOrStruct<'a> {
- pub computed_offsets: HashMap<ComputedOffsetId<'a>, ComputedOffset<'a>>,
- pub computed_values: HashMap<ComputedValueId<'a>, ComputedValue<'a>>,
+ pub computed_offsets: BTreeMap<ComputedOffsetId<'a>, ComputedOffset<'a>>,
+ pub computed_values: BTreeMap<ComputedValueId<'a>, ComputedValue<'a>>,
/// whether the parse of this packet needs to know its length,
/// or if the packet can determine its own length
pub length: PacketOrStructLength,
@@ -41,7 +41,7 @@ pub struct Enum<'a> {
pub width: usize,
}
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
pub enum ComputedValueId<'a> {
// needed for array fields + varlength structs - note that this is in OCTETS, not BITS
// this always works since array entries are either structs (which are byte-aligned) or integer-octet-width scalars
@@ -54,7 +54,7 @@ pub enum ComputedValueId<'a> {
Custom(u16),
}
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
pub enum ComputedOffsetId<'a> {
// these quantities are known by the runtime
HeaderStart,
@@ -69,6 +69,7 @@ pub enum ComputedOffsetId<'a> {
TrailerStart,
}
+#[derive(PartialEq, Eq, Debug, PartialOrd, Ord)]
pub enum ComputedValue<'a> {
Constant(usize),
CountStructsUpToSize {
@@ -90,7 +91,7 @@ pub enum ComputedValue<'a> {
},
}
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum ComputedOffset<'a> {
ConstantPlusOffsetInBits(ComputedOffsetId<'a>, i64),
SumWithOctets(ComputedOffsetId<'a>, ComputedValueId<'a>),
@@ -127,8 +128,8 @@ fn process_enum<'a>(schema: &mut Schema<'a>, id: &'a str, tags: &'a [ast::Tag],
schema.packets_and_structs.insert(
id,
PacketOrStruct {
- computed_offsets: HashMap::new(),
- computed_values: HashMap::new(),
+ computed_offsets: BTreeMap::new(),
+ computed_values: BTreeMap::new(),
length: PacketOrStructLength::Static(width),
},
);
@@ -148,8 +149,8 @@ fn compute_getters<'a>(
) -> PacketOrStruct<'a> {
let mut prev_pos_id = None;
let mut curr_pos_id = ComputedOffsetId::HeaderStart;
- let mut computed_values = HashMap::new();
- let mut computed_offsets = HashMap::new();
+ let mut computed_values = BTreeMap::new();
+ let mut computed_offsets = BTreeMap::new();
let mut cnt = 0;
@@ -518,7 +519,7 @@ fn compute_getters<'a>(
}
fn compute_length_to_goal(
- computed_offsets: &HashMap<ComputedOffsetId, ComputedOffset>,
+ computed_offsets: &BTreeMap<ComputedOffsetId, ComputedOffset>,
start: ComputedOffsetId,
goal: ComputedOffsetId,
) -> Option<i64> {
diff --git a/src/backends/rust.rs b/src/backends/rust.rs
index 5a6c921..6609482 100644
--- a/src/backends/rust.rs
+++ b/src/backends/rust.rs
@@ -1582,6 +1582,16 @@ mod tests {
"
);
+ test_pdl!(
+ payload_with_size_modifier,
+ "
+ packet Test {
+ _size_(_payload_): 8,
+ _payload_ : [+1],
+ }
+ "
+ );
+
// TODO(mgeisler): enable this test when we have an approach to
// struct fields with parents.
//
diff --git a/src/backends/rust/parser.rs b/src/backends/rust/parser.rs
index 8eaee06..8e76592 100644
--- a/src/backends/rust/parser.rs
+++ b/src/backends/rust/parser.rs
@@ -570,28 +570,8 @@ impl<'a> FieldParser<'a> {
let payload_size_field = self.decl.payload_size();
let offset_from_end = self.payload_field_offset_from_end();
- if size_modifier.is_some() {
- todo!(
- "Unsupported size modifier for {packet}: {size_modifier:?}",
- packet = self.packet_name
- );
- }
-
if self.shift != 0 {
- if payload_size_field.is_some() {
- panic!("Unexpected payload size for non byte aligned payload");
- }
-
- //let rounded_size = self.shift / 8 + if self.shift % 8 == 0 { 0 } else { 1 };
- //let padding_bits = 8 * rounded_size - self.shift;
- //let reserved_field =
- // ast::Field::Reserved { loc: ast::SourceRange::default(), width: padding_bits };
- //TODO: self.add_bit_field(&reserved_field); --
- // reserved_field does not live long enough.
-
- // TODO: consume span of rounded size
- } else {
- // TODO: consume span
+ todo!("Unexpected non byte aligned payload");
}
if let Some(ast::FieldDesc::Size { field_id, .. }) = &payload_size_field.map(|f| &f.desc) {
@@ -599,6 +579,25 @@ impl<'a> FieldParser<'a> {
// payload and update the span in case fields are placed
// after the payload.
let size_field = size_field_ident(field_id);
+ if let Some(size_modifier) = size_modifier {
+ let size_modifier = proc_macro2::Literal::usize_unsuffixed(
+ size_modifier.parse::<usize>().expect("failed to parse the size modifier"),
+ );
+ let packet_name = &self.packet_name;
+ // Push code to check that the size is greater than the size
+ // modifier. Required to safely substract the modifier from the
+ // size.
+ self.code.push(quote! {
+ if #size_field < #size_modifier {
+ return Err(Error::InvalidLengthError {
+ obj: #packet_name.to_string(),
+ wanted: #size_modifier,
+ got: #size_field,
+ });
+ }
+ let #size_field = #size_field - #size_modifier;
+ });
+ }
self.check_size(self.span, &quote!(#size_field ));
self.code.push(quote! {
let payload = &#span.get()[..#size_field];
diff --git a/src/backends/rust/serializer.rs b/src/backends/rust/serializer.rs
index 64bc567..b83f7c8 100644
--- a/src/backends/rust/serializer.rs
+++ b/src/backends/rust/serializer.rs
@@ -66,7 +66,7 @@ impl<'a> FieldSerializer<'a> {
self.add_typedef_field(id, type_id);
}
ast::FieldDesc::Payload { .. } | ast::FieldDesc::Body { .. } => {
- self.add_payload_field()
+ self.add_payload_field();
}
// Padding field handled in serialization of associated array field.
ast::FieldDesc::Padding { .. } => (),
@@ -225,6 +225,18 @@ impl<'a> FieldSerializer<'a> {
let field_size_name = format_ident!("{field_id}_size");
let array_size = match (&value_field.desc, value_field_decl.map(|decl| &decl.desc))
{
+ (ast::FieldDesc::Payload { size_modifier: Some(size_modifier) }, _) => {
+ let size_modifier = proc_macro2::Literal::usize_unsuffixed(
+ size_modifier
+ .parse::<usize>()
+ .expect("failed to parse the size modifier"),
+ );
+ if let ast::DeclDesc::Packet { .. } = &decl.desc {
+ quote! { (self.child.get_total_size() + #size_modifier) }
+ } else {
+ quote! { (self.payload.len() + #size_modifier) }
+ }
+ }
(ast::FieldDesc::Payload { .. } | ast::FieldDesc::Body { .. }, _) => {
if let ast::DeclDesc::Packet { .. } = &decl.desc {
quote! { self.child.get_total_size() }
diff --git a/src/backends/rust_no_allocation/mod.rs b/src/backends/rust_no_allocation/mod.rs
index 858526f..c98bc12 100644
--- a/src/backends/rust_no_allocation/mod.rs
+++ b/src/backends/rust_no_allocation/mod.rs
@@ -73,12 +73,8 @@ pub fn generate(file: &parser::ast::File, schema: &Schema) -> Result<String, Str
.map(|decl| generate_decl(decl, schema, &children))
.collect::<Result<TokenStream, _>>()?;
- out.push_str(
- &quote! {
- #declarations
- }
- .to_string(),
- );
+ let syntax_tree = syn::parse2(declarations).expect("Could not parse code");
+ out.push_str(&prettyplease::unparse(&syntax_tree));
Ok(out)
}
diff --git a/src/bin/generate-canonical-tests.rs b/src/bin/generate-canonical-tests.rs
index d044edf..1e18490 100644
--- a/src/bin/generate-canonical-tests.rs
+++ b/src/bin/generate-canonical-tests.rs
@@ -188,6 +188,7 @@ fn main() {
"Packet_Payload_Field_UnknownSize",
"Packet_Payload_Field_UnknownSize_Terminal",
"Packet_Payload_Field_VariableSize",
+ "Packet_Payload_Field_SizeModifier",
"Packet_Reserved_Field",
"Packet_Scalar_Field",
"Packet_Size_Field",
diff --git a/src/lib.rs b/src/lib.rs
index f9d4314..fe60df8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -20,3 +20,65 @@ pub mod backends;
pub mod parser;
#[cfg(test)]
pub mod test_utils;
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn rust_no_allocation_output_is_deterministic() {
+ // The generated code should be deterministic, to avoid unnecessary rebuilds during
+ // incremental builds.
+ let src = r#"
+little_endian_packets
+
+enum Enum1 : 8 {
+ ENUM_VARIANT_ONE = 0x01,
+ ENUM_VARIANT_TWO = 0x02,
+}
+
+packet Packet1 {
+ opcode : Enum1,
+ _payload_,
+}
+
+struct Struct1 {
+ handle : 16,
+}
+
+struct Struct2 {
+ _payload_
+}
+
+struct Struct3 {
+ handle : Struct1,
+ value : Struct2,
+}
+
+packet Packet2 : Packet1(opcode = ENUM_VARIANT_ONE) {
+ handle : Struct1,
+ value : Struct2,
+}
+"#
+ .to_owned();
+
+ let mut sources1 = ast::SourceDatabase::new();
+ let mut sources2 = ast::SourceDatabase::new();
+ let mut sources3 = ast::SourceDatabase::new();
+
+ let file1 = parser::parse_inline(&mut sources1, "foo", src.clone()).unwrap();
+ let file2 = parser::parse_inline(&mut sources2, "foo", src.clone()).unwrap();
+ let file3 = parser::parse_inline(&mut sources3, "foo", src).unwrap();
+
+ let schema1 = backends::intermediate::generate(&file1).unwrap();
+ let schema2 = backends::intermediate::generate(&file2).unwrap();
+ let schema3 = backends::intermediate::generate(&file3).unwrap();
+
+ let result1 = backends::rust_no_allocation::generate(&file1, &schema1).unwrap();
+ let result2 = backends::rust_no_allocation::generate(&file2, &schema2).unwrap();
+ let result3 = backends::rust_no_allocation::generate(&file3, &schema3).unwrap();
+
+ assert_eq!(result1, result2);
+ assert_eq!(result2, result3);
+ }
+}
diff --git a/tests/generated/payload_with_size_modifier_big_endian.rs b/tests/generated/payload_with_size_modifier_big_endian.rs
new file mode 100644
index 0000000..beec02b
--- /dev/null
+++ b/tests/generated/payload_with_size_modifier_big_endian.rs
@@ -0,0 +1,187 @@
+#![rustfmt::skip]
+/// @generated rust packets from test.
+use bytes::{Buf, BufMut, Bytes, BytesMut};
+use std::convert::{TryFrom, TryInto};
+use std::cell::Cell;
+use std::fmt;
+use pdl_runtime::{Error, Packet};
+type Result<T> = std::result::Result<T, Error>;
+/// Private prevents users from creating arbitrary scalar values
+/// in situations where the value needs to be validated.
+/// Users can freely deref the value, but only the backend
+/// may create it.
+#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Private<T>(T);
+impl<T> std::ops::Deref for Private<T> {
+ type Target = T;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum TestDataChild {
+ Payload(Bytes),
+ None,
+}
+impl TestDataChild {
+ fn get_total_size(&self) -> usize {
+ match self {
+ TestDataChild::Payload(bytes) => bytes.len(),
+ TestDataChild::None => 0,
+ }
+ }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum TestChild {
+ Payload(Bytes),
+ None,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct TestData {
+ child: TestDataChild,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Test {
+ #[cfg_attr(feature = "serde", serde(flatten))]
+ test: TestData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct TestBuilder {
+ pub payload: Option<Bytes>,
+}
+impl TestData {
+ fn conforms(bytes: &[u8]) -> bool {
+ bytes.len() >= 1
+ }
+ fn parse(bytes: &[u8]) -> Result<Self> {
+ let mut cell = Cell::new(bytes);
+ let packet = Self::parse_inner(&mut cell)?;
+ Ok(packet)
+ }
+ fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self> {
+ if bytes.get().remaining() < 1 {
+ return Err(Error::InvalidLengthError {
+ obj: "Test".to_string(),
+ wanted: 1,
+ got: bytes.get().remaining(),
+ });
+ }
+ let payload_size = bytes.get_mut().get_u8() as usize;
+ if payload_size < 1 {
+ return Err(Error::InvalidLengthError {
+ obj: "Test".to_string(),
+ wanted: 1,
+ got: payload_size,
+ });
+ }
+ let payload_size = payload_size - 1;
+ if bytes.get().remaining() < payload_size {
+ return Err(Error::InvalidLengthError {
+ obj: "Test".to_string(),
+ wanted: payload_size,
+ got: bytes.get().remaining(),
+ });
+ }
+ let payload = &bytes.get()[..payload_size];
+ bytes.get_mut().advance(payload_size);
+ let child = match () {
+ _ if !payload.is_empty() => {
+ TestDataChild::Payload(Bytes::copy_from_slice(payload))
+ }
+ _ => TestDataChild::None,
+ };
+ Ok(Self { child })
+ }
+ fn write_to(&self, buffer: &mut BytesMut) {
+ if (self.child.get_total_size() + 1) > 0xff {
+ panic!(
+ "Invalid length for {}::{}: {} > {}", "Test", "_payload_", (self.child
+ .get_total_size() + 1), 0xff
+ );
+ }
+ buffer.put_u8((self.child.get_total_size() + 1) as u8);
+ match &self.child {
+ TestDataChild::Payload(payload) => buffer.put_slice(payload),
+ TestDataChild::None => {}
+ }
+ }
+ fn get_total_size(&self) -> usize {
+ self.get_size()
+ }
+ fn get_size(&self) -> usize {
+ 1 + self.child.get_total_size()
+ }
+}
+impl Packet for Test {
+ fn to_bytes(self) -> Bytes {
+ let mut buffer = BytesMut::with_capacity(self.test.get_size());
+ self.test.write_to(&mut buffer);
+ buffer.freeze()
+ }
+ fn to_vec(self) -> Vec<u8> {
+ self.to_bytes().to_vec()
+ }
+}
+impl From<Test> for Bytes {
+ fn from(packet: Test) -> Self {
+ packet.to_bytes()
+ }
+}
+impl From<Test> for Vec<u8> {
+ fn from(packet: Test) -> Self {
+ packet.to_vec()
+ }
+}
+impl Test {
+ pub fn parse(bytes: &[u8]) -> Result<Self> {
+ let mut cell = Cell::new(bytes);
+ let packet = Self::parse_inner(&mut cell)?;
+ Ok(packet)
+ }
+ fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self> {
+ let data = TestData::parse_inner(&mut bytes)?;
+ Self::new(data)
+ }
+ pub fn specialize(&self) -> TestChild {
+ match &self.test.child {
+ TestDataChild::Payload(payload) => TestChild::Payload(payload.clone()),
+ TestDataChild::None => TestChild::None,
+ }
+ }
+ fn new(test: TestData) -> Result<Self> {
+ Ok(Self { test })
+ }
+ pub fn get_payload(&self) -> &[u8] {
+ match &self.test.child {
+ TestDataChild::Payload(bytes) => &bytes,
+ TestDataChild::None => &[],
+ }
+ }
+ fn write_to(&self, buffer: &mut BytesMut) {
+ self.test.write_to(buffer)
+ }
+ pub fn get_size(&self) -> usize {
+ self.test.get_size()
+ }
+}
+impl TestBuilder {
+ pub fn build(self) -> Test {
+ let test = TestData {
+ child: match self.payload {
+ None => TestDataChild::None,
+ Some(bytes) => TestDataChild::Payload(bytes),
+ },
+ };
+ Test::new(test).unwrap()
+ }
+}
+impl From<TestBuilder> for Test {
+ fn from(builder: TestBuilder) -> Test {
+ builder.build().into()
+ }
+}
diff --git a/tests/generated/payload_with_size_modifier_little_endian.rs b/tests/generated/payload_with_size_modifier_little_endian.rs
new file mode 100644
index 0000000..beec02b
--- /dev/null
+++ b/tests/generated/payload_with_size_modifier_little_endian.rs
@@ -0,0 +1,187 @@
+#![rustfmt::skip]
+/// @generated rust packets from test.
+use bytes::{Buf, BufMut, Bytes, BytesMut};
+use std::convert::{TryFrom, TryInto};
+use std::cell::Cell;
+use std::fmt;
+use pdl_runtime::{Error, Packet};
+type Result<T> = std::result::Result<T, Error>;
+/// Private prevents users from creating arbitrary scalar values
+/// in situations where the value needs to be validated.
+/// Users can freely deref the value, but only the backend
+/// may create it.
+#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Private<T>(T);
+impl<T> std::ops::Deref for Private<T> {
+ type Target = T;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum TestDataChild {
+ Payload(Bytes),
+ None,
+}
+impl TestDataChild {
+ fn get_total_size(&self) -> usize {
+ match self {
+ TestDataChild::Payload(bytes) => bytes.len(),
+ TestDataChild::None => 0,
+ }
+ }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum TestChild {
+ Payload(Bytes),
+ None,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct TestData {
+ child: TestDataChild,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Test {
+ #[cfg_attr(feature = "serde", serde(flatten))]
+ test: TestData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct TestBuilder {
+ pub payload: Option<Bytes>,
+}
+impl TestData {
+ fn conforms(bytes: &[u8]) -> bool {
+ bytes.len() >= 1
+ }
+ fn parse(bytes: &[u8]) -> Result<Self> {
+ let mut cell = Cell::new(bytes);
+ let packet = Self::parse_inner(&mut cell)?;
+ Ok(packet)
+ }
+ fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self> {
+ if bytes.get().remaining() < 1 {
+ return Err(Error::InvalidLengthError {
+ obj: "Test".to_string(),
+ wanted: 1,
+ got: bytes.get().remaining(),
+ });
+ }
+ let payload_size = bytes.get_mut().get_u8() as usize;
+ if payload_size < 1 {
+ return Err(Error::InvalidLengthError {
+ obj: "Test".to_string(),
+ wanted: 1,
+ got: payload_size,
+ });
+ }
+ let payload_size = payload_size - 1;
+ if bytes.get().remaining() < payload_size {
+ return Err(Error::InvalidLengthError {
+ obj: "Test".to_string(),
+ wanted: payload_size,
+ got: bytes.get().remaining(),
+ });
+ }
+ let payload = &bytes.get()[..payload_size];
+ bytes.get_mut().advance(payload_size);
+ let child = match () {
+ _ if !payload.is_empty() => {
+ TestDataChild::Payload(Bytes::copy_from_slice(payload))
+ }
+ _ => TestDataChild::None,
+ };
+ Ok(Self { child })
+ }
+ fn write_to(&self, buffer: &mut BytesMut) {
+ if (self.child.get_total_size() + 1) > 0xff {
+ panic!(
+ "Invalid length for {}::{}: {} > {}", "Test", "_payload_", (self.child
+ .get_total_size() + 1), 0xff
+ );
+ }
+ buffer.put_u8((self.child.get_total_size() + 1) as u8);
+ match &self.child {
+ TestDataChild::Payload(payload) => buffer.put_slice(payload),
+ TestDataChild::None => {}
+ }
+ }
+ fn get_total_size(&self) -> usize {
+ self.get_size()
+ }
+ fn get_size(&self) -> usize {
+ 1 + self.child.get_total_size()
+ }
+}
+impl Packet for Test {
+ fn to_bytes(self) -> Bytes {
+ let mut buffer = BytesMut::with_capacity(self.test.get_size());
+ self.test.write_to(&mut buffer);
+ buffer.freeze()
+ }
+ fn to_vec(self) -> Vec<u8> {
+ self.to_bytes().to_vec()
+ }
+}
+impl From<Test> for Bytes {
+ fn from(packet: Test) -> Self {
+ packet.to_bytes()
+ }
+}
+impl From<Test> for Vec<u8> {
+ fn from(packet: Test) -> Self {
+ packet.to_vec()
+ }
+}
+impl Test {
+ pub fn parse(bytes: &[u8]) -> Result<Self> {
+ let mut cell = Cell::new(bytes);
+ let packet = Self::parse_inner(&mut cell)?;
+ Ok(packet)
+ }
+ fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self> {
+ let data = TestData::parse_inner(&mut bytes)?;
+ Self::new(data)
+ }
+ pub fn specialize(&self) -> TestChild {
+ match &self.test.child {
+ TestDataChild::Payload(payload) => TestChild::Payload(payload.clone()),
+ TestDataChild::None => TestChild::None,
+ }
+ }
+ fn new(test: TestData) -> Result<Self> {
+ Ok(Self { test })
+ }
+ pub fn get_payload(&self) -> &[u8] {
+ match &self.test.child {
+ TestDataChild::Payload(bytes) => &bytes,
+ TestDataChild::None => &[],
+ }
+ }
+ fn write_to(&self, buffer: &mut BytesMut) {
+ self.test.write_to(buffer)
+ }
+ pub fn get_size(&self) -> usize {
+ self.test.get_size()
+ }
+}
+impl TestBuilder {
+ pub fn build(self) -> Test {
+ let test = TestData {
+ child: match self.payload {
+ None => TestDataChild::None,
+ Some(bytes) => TestDataChild::Payload(bytes),
+ },
+ };
+ Test::new(test).unwrap()
+ }
+}
+impl From<TestBuilder> for Test {
+ fn from(builder: TestBuilder) -> Test {
+ builder.build().into()
+ }
+}
diff --git a/tests/run_rust_generator_tests.sh b/tests/run_rust_generator_tests.sh
index 5e8ecf1..92e6f05 100755
--- a/tests/run_rust_generator_tests.sh
+++ b/tests/run_rust_generator_tests.sh
@@ -34,7 +34,6 @@ cargo run --bin pdlc -- \
--exclude-declaration PartialChild5_B \
--exclude-declaration PartialChild12_A \
--exclude-declaration PartialChild12_B \
- --exclude-declaration Packet_Payload_Field_SizeModifier \
--exclude-declaration Packet_Array_Field_UnsizedElement_SizeModifier \
--exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier_ \
--exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier \
@@ -53,7 +52,6 @@ cargo run --bin pdlc -- \
--exclude-declaration Struct_Checksum_Field_FromStart \
--exclude-declaration Struct_Checksum_Field_FromEnd_ \
--exclude-declaration Struct_Checksum_Field_FromEnd \
- --exclude-declaration Packet_Payload_Field_SizeModifier \
--exclude-declaration Packet_Array_Field_UnsizedElement_SizeModifier \
--exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier_ \
--exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier \