Snap for 11097608 from 57276d0c72f294b4bb3ad2eba51683488261cedf to 24Q1-release

Change-Id: I94b550fdc1d2a80eb499afc2780db26cef43af7c
diff --git a/Android.bp b/Android.bp
index c23fce5..db9f603 100644
--- a/Android.bp
+++ b/Android.bp
@@ -7,7 +7,7 @@
     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 @@
     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 @@
     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 @@
         " --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 @@
         " --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 <[email protected]>",
     "David de Jesus Duarte <[email protected]>",
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 @@
   }
   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 @@
         "//system/nfc:__subpackages__",
         "//external/uwb/src",
         "//packages/modules/Bluetooth:__subpackages__",
+        "//tools/netsim:__subpackages__",
     ],
 }
 
@@ -207,7 +208,6 @@
         " --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 @@
         " --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 @@
 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 @@
 +    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 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 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 @@
     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 @@
     TrailerStart,
 }
 
+#[derive(PartialEq, Eq, Debug, PartialOrd, Ord)]
 pub enum ComputedValue<'a> {
     Constant(usize),
     CountStructsUpToSize {
@@ -90,7 +91,7 @@
     },
 }
 
-#[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 @@
     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 @@
 ) -> 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_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 @@
         "
     );
 
+    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 @@
         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 @@
             // 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 @@
                 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 @@
                 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 @@
         .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 @@
             "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 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 @@
     --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 @@
     --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 \