Upgrade pdl-compiler to 0.3.0 am: 866fc0d84e

Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/pdl-compiler/+/3108746

Change-Id: I60256d59e577363bdf8f7a26c6533df3990c5394
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index fb68fdd..cb25ea3 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
 {
   "git": {
-    "sha1": "79fcfdf26cf927144ddde1ecf83d0716441c5e45"
+    "sha1": "4dbe66da6a922c64436a8f3a00a4ab1f0ebafbb6"
   },
-  "path_in_vcs": ""
+  "path_in_vcs": "pdl-compiler"
 }
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 335643b..1708971 100644
--- a/Android.bp
+++ b/Android.bp
@@ -3,39 +3,11 @@
 // because the changes will be overridden on upgrade.
 // Content before the first "rust_*" or "genrule" module is preserved.
 
-rust_binary_host {
-    name: "generate_canonical_tests",
-    crate_name: "generate_canonical_tests",
-    cargo_env_compat: true,
-    cargo_pkg_version: "0.2.3",
-    crate_root: "src/bin/generate-canonical-tests.rs",
-    edition: "2021",
-    features: [
-        "default",
-        "serde",
-    ],
-    rustlibs: [
-        "libargh",
-        "libcodespan_reporting",
-        "libheck",
-        "libpdl_compiler",
-        "libpest",
-        "libprettyplease",
-        "libproc_macro2",
-        "libquote",
-        "libserde",
-        "libserde_json",
-        "libsyn",
-    ],
-    proc_macros: ["libpest_derive"],
-    compile_multilib: "first",
-}
-
 rust_library_host {
     name: "libpdl_compiler",
     crate_name: "pdl_compiler",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.2.3",
+    cargo_pkg_version: "0.3.0",
     crate_root: "src/lib.rs",
     edition: "2021",
     features: [
@@ -62,7 +34,7 @@
     name: "pdlc",
     crate_name: "pdlc",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.2.3",
+    cargo_pkg_version: "0.3.0",
     crate_root: "src/main.rs",
     edition: "2021",
     features: [
@@ -100,6 +72,20 @@
     ],
 }
 
+// Defaults for legacy rust backend generation.
+genrule_defaults {
+    name: "pdl_rust_legacy_generator_defaults",
+    cmd: "$(location :pdlc) --output-format rust_legacy $(in) > $(out)",
+    tools: [":pdlc"],
+    defaults_visibility: [
+        "//system/nfc:__subpackages__",
+        "//external/rust/pica",
+        "//external/uwb/src",
+        "//packages/modules/Bluetooth:__subpackages__",
+        "//tools/netsim:__subpackages__",
+    ],
+}
+
 // Defaults for rust_noalloc backend generation.
 genrule_defaults {
     name: "pdl_rust_noalloc_generator_defaults",
@@ -128,79 +114,7 @@
 filegroup {
     name: "pdl_generated_files",
     srcs: [
-        "tests/generated/custom_field_declaration_big_endian.rs",
-        "tests/generated/custom_field_declaration_little_endian.rs",
-        "tests/generated/enum_declaration_big_endian.rs",
-        "tests/generated/enum_declaration_little_endian.rs",
-        "tests/generated/packet_decl_8bit_enum_array_big_endian.rs",
-        "tests/generated/packet_decl_8bit_enum_array_little_endian.rs",
-        "tests/generated/packet_decl_8bit_enum_big_endian.rs",
-        "tests/generated/packet_decl_8bit_enum_little_endian.rs",
-        "tests/generated/packet_decl_8bit_scalar_array_big_endian.rs",
-        "tests/generated/packet_decl_8bit_scalar_array_little_endian.rs",
-        "tests/generated/packet_decl_8bit_scalar_big_endian.rs",
-        "tests/generated/packet_decl_8bit_scalar_little_endian.rs",
-        "tests/generated/packet_decl_24bit_enum_array_big_endian.rs",
-        "tests/generated/packet_decl_24bit_enum_array_little_endian.rs",
-        "tests/generated/packet_decl_24bit_enum_big_endian.rs",
-        "tests/generated/packet_decl_24bit_enum_little_endian.rs",
-        "tests/generated/packet_decl_24bit_scalar_array_big_endian.rs",
-        "tests/generated/packet_decl_24bit_scalar_array_little_endian.rs",
-        "tests/generated/packet_decl_24bit_scalar_big_endian.rs",
-        "tests/generated/packet_decl_24bit_scalar_little_endian.rs",
-        "tests/generated/packet_decl_64bit_enum_array_big_endian.rs",
-        "tests/generated/packet_decl_64bit_enum_array_little_endian.rs",
-        "tests/generated/packet_decl_64bit_enum_big_endian.rs",
-        "tests/generated/packet_decl_64bit_enum_little_endian.rs",
-        "tests/generated/packet_decl_64bit_scalar_array_big_endian.rs",
-        "tests/generated/packet_decl_64bit_scalar_array_little_endian.rs",
-        "tests/generated/packet_decl_64bit_scalar_big_endian.rs",
-        "tests/generated/packet_decl_64bit_scalar_little_endian.rs",
-        "tests/generated/packet_decl_array_dynamic_count_big_endian.rs",
-        "tests/generated/packet_decl_array_dynamic_count_little_endian.rs",
-        "tests/generated/packet_decl_array_dynamic_size_big_endian.rs",
-        "tests/generated/packet_decl_array_dynamic_size_little_endian.rs",
-        "tests/generated/packet_decl_array_unknown_element_width_dynamic_count_big_endian.rs",
-        "tests/generated/packet_decl_array_unknown_element_width_dynamic_count_little_endian.rs",
-        "tests/generated/packet_decl_array_unknown_element_width_dynamic_size_big_endian.rs",
-        "tests/generated/packet_decl_array_unknown_element_width_dynamic_size_little_endian.rs",
-        "tests/generated/packet_decl_array_with_padding_big_endian.rs",
-        "tests/generated/packet_decl_array_with_padding_little_endian.rs",
-        "tests/generated/packet_decl_child_packets_big_endian.rs",
-        "tests/generated/packet_decl_child_packets_little_endian.rs",
-        "tests/generated/packet_decl_complex_scalars_big_endian.rs",
-        "tests/generated/packet_decl_complex_scalars_little_endian.rs",
-        "tests/generated/packet_decl_custom_field_big_endian.rs",
-        "tests/generated/packet_decl_custom_field_little_endian.rs",
-        "tests/generated/packet_decl_empty_big_endian.rs",
-        "tests/generated/packet_decl_empty_little_endian.rs",
-        "tests/generated/packet_decl_fixed_enum_field_big_endian.rs",
-        "tests/generated/packet_decl_fixed_enum_field_little_endian.rs",
-        "tests/generated/packet_decl_fixed_scalar_field_big_endian.rs",
-        "tests/generated/packet_decl_fixed_scalar_field_little_endian.rs",
-        "tests/generated/packet_decl_grand_children_big_endian.rs",
-        "tests/generated/packet_decl_grand_children_little_endian.rs",
-        "tests/generated/packet_decl_mask_scalar_value_big_endian.rs",
-        "tests/generated/packet_decl_mask_scalar_value_little_endian.rs",
-        "tests/generated/packet_decl_mixed_scalars_enums_big_endian.rs",
-        "tests/generated/packet_decl_mixed_scalars_enums_little_endian.rs",
-        "tests/generated/packet_decl_parent_with_alias_child_big_endian.rs",
-        "tests/generated/packet_decl_parent_with_alias_child_little_endian.rs",
-        "tests/generated/packet_decl_parent_with_no_payload_big_endian.rs",
-        "tests/generated/packet_decl_parent_with_no_payload_little_endian.rs",
-        "tests/generated/packet_decl_payload_field_unknown_size_big_endian.rs",
-        "tests/generated/packet_decl_payload_field_unknown_size_little_endian.rs",
-        "tests/generated/packet_decl_payload_field_unknown_size_terminal_big_endian.rs",
-        "tests/generated/packet_decl_payload_field_unknown_size_terminal_little_endian.rs",
-        "tests/generated/packet_decl_payload_field_variable_size_big_endian.rs",
-        "tests/generated/packet_decl_payload_field_variable_size_little_endian.rs",
-        "tests/generated/packet_decl_reserved_field_big_endian.rs",
-        "tests/generated/packet_decl_reserved_field_little_endian.rs",
-        "tests/generated/packet_decl_simple_scalars_big_endian.rs",
-        "tests/generated/packet_decl_simple_scalars_little_endian.rs",
-        "tests/generated/preamble.rs",
-        "tests/generated/struct_decl_complex_scalars_big_endian.rs",
-        "tests/generated/struct_decl_complex_scalars_little_endian.rs",
+        "tests/generated/rust/**/*.rs",
     ],
 }
 
@@ -242,10 +156,16 @@
 rust_test_host {
     name: "pdl_generated_files_compile",
     srcs: [":pdl_generated_files_compile_rs"],
+    features: ["serde"],
+    rustlibs: [
+        "libbytes",
+        "libserde",
+        "libtempfile",
+        "libpdl_runtime",
+    ],
     test_suites: ["general-tests"],
     clippy_lints: "none",
     lints: "none",
-    defaults: ["pdl_backend_defaults"],
 }
 
 // The generators support more features for LE packets than for BE
@@ -274,10 +194,8 @@
     out: ["be_test_file.pdl"],
 }
 
-// Generate the Rust parser+serializer backends.
 genrule {
-    name: "pdl_le_backend",
-    tools: [":pdlc"],
+    name: "pdl_rust_generator_tests_le_src",
     cmd: "$(location :pdlc)" +
         " --output-format rust" +
         " --exclude-declaration UnsizedCustomField" +
@@ -300,14 +218,18 @@
         " --exclude-declaration Packet_Array_Field_UnsizedElement_SizeModifier" +
         " --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier_" +
         " --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier" +
-        " $(in) > $(out)",
-    srcs: ["tests/canonical/le_test_file.pdl"],
-    out: ["le_backend.rs"],
+        " $(location tests/canonical/le_test_file.pdl) > $(out);" +
+        "$(location :pdlc) $(location tests/canonical/le_test_vectors.json) --output-format rust --tests >> $(out)",
+    srcs: [
+        "tests/canonical/le_test_file.pdl",
+        "tests/canonical/le_test_vectors.json",
+    ],
+    out: ["le_canonical.rs"],
+    tools: [":pdlc"],
 }
 
 genrule {
-    name: "pdl_be_backend",
-    tools: [":pdlc"],
+    name: "pdl_rust_generator_tests_be_src",
     cmd: "$(location :pdlc)" +
         " --output-format rust" +
         " --exclude-declaration UnsizedCustomField" +
@@ -324,64 +246,26 @@
         " --exclude-declaration Packet_Array_Field_UnsizedElement_SizeModifier" +
         " --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier_" +
         " --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier" +
-        " $(in) > $(out)",
-    srcs: [":pdl_be_test_file"],
-    out: ["be_backend.rs"],
-}
-
-rust_defaults {
-    name: "pdl_backend_defaults",
-    features: ["serde"],
-    rustlibs: [
-        "libbytes",
-        "libserde",
-        "libtempfile",
-        "libpdl_runtime",
+        " $(location :pdl_be_test_file) > $(out);" +
+        "$(location :pdlc) $(location tests/canonical/be_test_vectors.json) --output-format rust --tests >> $(out)",
+    srcs: [
+        ":pdl_be_test_file",
+        "tests/canonical/be_test_vectors.json",
     ],
-}
-
-rust_library_host {
-    name: "libpdl_le_backend",
-    crate_name: "pdl_le_backend",
-    srcs: [":pdl_le_backend"],
-    defaults: ["pdl_backend_defaults"],
-    clippy_lints: "none",
-    lints: "none",
-}
-
-rust_library_host {
-    name: "libpdl_be_backend",
-    crate_name: "pdl_be_backend",
-    srcs: [":pdl_be_backend"],
-    defaults: ["pdl_backend_defaults"],
-    clippy_lints: "none",
-    lints: "none",
-}
-
-genrule {
-    name: "pdl_rust_generator_tests_le_src",
-    cmd: "$(location :generate_canonical_tests) $(in) pdl_le_backend > $(out)",
-    srcs: ["tests/canonical/le_test_vectors.json"],
-    out: ["le_canonical.rs"],
-    tools: [":generate_canonical_tests"],
-}
-
-genrule {
-    name: "pdl_rust_generator_tests_be_src",
-    cmd: "$(location :generate_canonical_tests) $(in) pdl_be_backend > $(out)",
-    srcs: ["tests/canonical/be_test_vectors.json"],
     out: ["be_canonical.rs"],
-    tools: [":generate_canonical_tests"],
+    tools: [":pdlc"],
 }
 
 rust_test_host {
     name: "pdl_rust_generator_tests_le",
     srcs: [":pdl_rust_generator_tests_le_src"],
     test_suites: ["general-tests"],
+    features: ["serde"],
     rustlibs: [
+        "libbytes",
         "libnum_traits",
-        "libpdl_le_backend",
         "libpdl_runtime",
+        "libserde",
         "libserde_json",
     ],
     clippy_lints: "none",
@@ -392,10 +276,12 @@
     name: "pdl_rust_generator_tests_be",
     srcs: [":pdl_rust_generator_tests_be_src"],
     test_suites: ["general-tests"],
+    features: ["serde"],
     rustlibs: [
+        "libbytes",
         "libnum_traits",
-        "libpdl_be_backend",
         "libpdl_runtime",
+        "libserde",
         "libserde_json",
     ],
     clippy_lints: "none",
@@ -410,6 +296,10 @@
     cmd: "set -o pipefail;" +
         " $(location :pdlc) $(in) |" +
         " $(location :pdl_python_generator)" +
+        " --exclude-declaration Packet_Array_Field_VariableElementSize_ConstantSize" +
+        " --exclude-declaration Packet_Array_Field_VariableElementSize_VariableSize" +
+        " --exclude-declaration Packet_Array_Field_VariableElementSize_VariableCount" +
+        " --exclude-declaration Packet_Array_Field_VariableElementSize_UnknownSize" +
         " --output $(out) --custom-type-location tests.custom_types",
     tool_files: [
         "tests/custom_types.py",
@@ -430,6 +320,10 @@
     cmd: "set -o pipefail;" +
         " $(location :pdlc) $(in) |" +
         " $(location :pdl_python_generator)" +
+        " --exclude-declaration Packet_Array_Field_VariableElementSize_ConstantSize" +
+        " --exclude-declaration Packet_Array_Field_VariableElementSize_VariableSize" +
+        " --exclude-declaration Packet_Array_Field_VariableElementSize_VariableCount" +
+        " --exclude-declaration Packet_Array_Field_VariableElementSize_UnknownSize" +
         " --output $(out) --custom-type-location tests.custom_types",
     tool_files: [
         "tests/custom_types.py",
@@ -486,6 +380,28 @@
     cmd: "set -o pipefail;" +
         " $(location :pdlc) $(in) |" +
         " $(location :pdl_cxx_generator)" +
+        " --exclude-declaration Packet_Custom_Field_ConstantSize" +
+        " --exclude-declaration Packet_Custom_Field_VariableSize" +
+        " --exclude-declaration Packet_Checksum_Field_FromStart" +
+        " --exclude-declaration Packet_Checksum_Field_FromEnd" +
+        " --exclude-declaration Struct_Custom_Field_ConstantSize" +
+        " --exclude-declaration Struct_Custom_Field_VariableSize" +
+        " --exclude-declaration Struct_Checksum_Field_FromStart" +
+        " --exclude-declaration Struct_Checksum_Field_FromEnd" +
+        " --exclude-declaration Packet_Array_Field_VariableElementSize_ConstantSize" +
+        " --exclude-declaration Packet_Array_Field_VariableElementSize_VariableSize" +
+        " --exclude-declaration Packet_Array_Field_VariableElementSize_VariableCount" +
+        " --exclude-declaration Packet_Array_Field_VariableElementSize_UnknownSize" +
+        " --exclude-declaration Struct_Custom_Field_ConstantSize_" +
+        " --exclude-declaration Struct_Custom_Field_VariableSize_" +
+        " --exclude-declaration Struct_Checksum_Field_FromStart_" +
+        " --exclude-declaration Struct_Checksum_Field_FromEnd_" +
+        " --exclude-declaration PartialParent5" +
+        " --exclude-declaration PartialChild5_A" +
+        " --exclude-declaration PartialChild5_B" +
+        " --exclude-declaration PartialParent12" +
+        " --exclude-declaration PartialChild12_A" +
+        " --exclude-declaration PartialChild12_B" +
         " --namespace le_test" +
         " --output $(out)",
     srcs: [
@@ -535,6 +451,28 @@
     cmd: "set -o pipefail;" +
         " $(location :pdlc) $(in) |" +
         " $(location :pdl_cxx_generator)" +
+        " --exclude-declaration Packet_Custom_Field_ConstantSize" +
+        " --exclude-declaration Packet_Custom_Field_VariableSize" +
+        " --exclude-declaration Packet_Checksum_Field_FromStart" +
+        " --exclude-declaration Packet_Checksum_Field_FromEnd" +
+        " --exclude-declaration Struct_Custom_Field_ConstantSize" +
+        " --exclude-declaration Struct_Custom_Field_VariableSize" +
+        " --exclude-declaration Struct_Checksum_Field_FromStart" +
+        " --exclude-declaration Struct_Checksum_Field_FromEnd" +
+        " --exclude-declaration Packet_Array_Field_VariableElementSize_ConstantSize" +
+        " --exclude-declaration Packet_Array_Field_VariableElementSize_VariableSize" +
+        " --exclude-declaration Packet_Array_Field_VariableElementSize_VariableCount" +
+        " --exclude-declaration Packet_Array_Field_VariableElementSize_UnknownSize" +
+        " --exclude-declaration Struct_Custom_Field_ConstantSize_" +
+        " --exclude-declaration Struct_Custom_Field_VariableSize_" +
+        " --exclude-declaration Struct_Checksum_Field_FromStart_" +
+        " --exclude-declaration Struct_Checksum_Field_FromEnd_" +
+        " --exclude-declaration PartialParent5" +
+        " --exclude-declaration PartialChild5_A" +
+        " --exclude-declaration PartialChild5_B" +
+        " --exclude-declaration PartialParent12" +
+        " --exclude-declaration PartialChild12_A" +
+        " --exclude-declaration PartialChild12_B" +
         " --namespace be_test" +
         " --output $(out)",
     srcs: [
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
deleted file mode 100644
index b16bd94..0000000
--- a/CONTRIBUTING.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# How to contribute
-
-We'd love to accept your patches and contributions to this project.
-
-## Before you begin
-
-### Sign our Contributor License Agreement
-
-Contributions to this project must be accompanied by a
-[Contributor License Agreement](https://cla.developers.google.com/about) (CLA).
-You (or your employer) retain the copyright to your contribution; this simply
-gives us permission to use and redistribute your contributions as part of the
-project.
-
-If you or your current employer have already signed the Google CLA (even if it
-was for a different project), you probably don't need to do it again.
-
-Visit <https://cla.developers.google.com/> to see your current agreements or to
-sign a new one.
-
-### Review our community guidelines
-
-This project follows
-[Google's Open Source Community Guidelines](https://opensource.google/conduct/).
-
-## Contribution process
-
-### Code reviews
-
-All submissions, including submissions by project members, require review. We
-use GitHub pull requests for this purpose. Consult
-[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
-information on using pull requests.
diff --git a/Cargo.toml b/Cargo.toml
index b0aa493..c89b1ff 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,7 +12,7 @@
 [package]
 edition = "2021"
 name = "pdl-compiler"
-version = "0.2.3"
+version = "0.3.0"
 authors = [
     "Henri Chataing <henrichataing@google.com>",
     "David de Jesus Duarte <licorne@google.com>",
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 4d86b22..bfd1edf 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "pdl-compiler"
-version = "0.2.3"
+version = "0.3.0"
 edition = "2021"
 description = "Parser and serializer generator for protocol binary packets"
 repository = "https://github.com/google/pdl/"
diff --git a/METADATA b/METADATA
index 0680736..8ffef1d 100644
--- a/METADATA
+++ b/METADATA
@@ -1,23 +1,20 @@
 # This project was upgraded with external_updater.
-# Usage: tools/external_updater/updater.sh update rust/crates/pdl-compiler
+# Usage: tools/external_updater/updater.sh update external/rust/crates/pdl-compiler
 # For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
 
 name: "pdl-compiler"
 description: "Parser and serializer generator for protocol binary packets"
 third_party {
-  url {
-    type: HOMEPAGE
-    value: "https://crates.io/crates/pdl-compiler"
-  }
-  url {
-    type: ARCHIVE
-    value: "https://static.crates.io/crates/pdl-compiler/pdl-compiler-0.2.3.crate"
-  }
-  version: "0.2.3"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2023
-    month: 11
-    day: 13
+    year: 2024
+    month: 5
+    day: 29
+  }
+  homepage: "https://crates.io/crates/pdl-compiler"
+  identifier {
+    type: "Archive"
+    value: "https://static.crates.io/crates/pdl-compiler/pdl-compiler-0.3.0.crate"
+    version: "0.3.0"
   }
 }
diff --git a/README.md b/README.md
index 1396b3d..a8e96fc 100644
--- a/README.md
+++ b/README.md
@@ -45,5 +45,5 @@
 ## Similar projects
 
 - [Kaitai](https://kaitai.io)
-- [EMBOSS](https://github.com/kimrutherford/EMBOSS)
+- [Emboss](https://github.com/google/emboss)
 - [P4](https://p4.org/p4-spec/docs/P4-16-v1.0.0-spec.html)
diff --git a/doc/cxx-generated-code-guide.rst b/doc/cxx-generated-code-guide.rst
deleted file mode 100644
index 3a71430..0000000
--- a/doc/cxx-generated-code-guide.rst
+++ /dev/null
@@ -1,47 +0,0 @@
-C++ Generated Code Guide
-========================
-
-Usage
------
-
-.. sourcecode:: bash
-
-    usage: generate_cxx_backend.py [-h] [--input INPUT] [--output OUTPUT] [--namespace NAMESPACE] [--include-header INCLUDE_HEADER] [--using-namespace USING_NAMESPACE]
-
-    options:
-      -h, --help            show this help message and exit
-      --input INPUT         Input PDL-JSON source
-      --output OUTPUT       Output C++ file
-      --namespace NAMESPACE
-                            Generated module namespace
-      --include-header INCLUDE_HEADER
-                            Added include directives
-      --using-namespace USING_NAMESPACE
-                            Added using namespace statements
-
-Example invocation:
-
-.. sourcecode:: bash
-
-    cargo run my-protocol.pdl --output-format json | \
-        ./scripts/generate_cxx_backend.py > my-protocol.h
-
-Language bindings
------------------
-
-Enum declarations
-^^^^^^^^^^^^^^^^^
-
-+---------------------------------------+---------------------------------------------------------------+
-| ::                                    | .. sourcecode:: c++                                           |
-|                                       |                                                               |
-|     enum TestEnum : 8 {               |     enum TestEnum : int8_t {                                  |
-|         A = 1,                        |         A = 1,                                                |
-|         B = 2..3,                     |         B_MIN = 2,                                            |
-|         C = 4,                        |         B_MAX = 3,                                            |
-|         OTHER = ..,                   |         C = 4,                                                |
-|     }                                 |     }                                                         |
-+---------------------------------------+---------------------------------------------------------------+
-
-.. note::
-    C++ enums are open by construction, default cases in enum declarations are ignored.
diff --git a/doc/python-generated-code-guide.rst b/doc/python-generated-code-guide.rst
deleted file mode 100644
index de766d4..0000000
--- a/doc/python-generated-code-guide.rst
+++ /dev/null
@@ -1,126 +0,0 @@
-Python Generated Code Guide
-===========================
-
-Usage
------
-
-.. sourcecode:: bash
-
-    usage: generate_python_backend.py [-h] [--input INPUT] [--output OUTPUT] [--custom-type-location CUSTOM_TYPE_LOCATION]
-
-    options:
-      -h, --help            show this help message and exit
-      --input INPUT         Input PDL-JSON source
-      --output OUTPUT       Output Python file
-      --custom-type-location CUSTOM_TYPE_LOCATION
-                            Module of declaration of custom types
-
-Example invocation:
-
-.. sourcecode:: bash
-
-    cargo run my-protocol.pdl --output-format json | \
-        ./scripts/generate_python_backend.py > my-protocol.py
-
-Language bindings
------------------
-
-The generator produces a pure python implementation of the parser and serializer
-for the selected grammar, using only builtin features of the Python language.
-The generated constructs are all type annotated and _should_ pass the type
-validation.
-
-All packets inherit either from their parent declaration or at the root
-a blanket `Packet` class implementation.
-
-.. sourcecode:: python
-
-    @dataclass
-    class Packet:
-        payload: Optional[bytes] = field(repr=False, default_factory=bytes, compare=False)
-
-Enum declarations
-^^^^^^^^^^^^^^^^^
-
-+---------------------------------------+---------------------------------------------------------------+
-| ::                                    | .. sourcecode:: python                                        |
-|                                       |                                                               |
-|     enum TestEnum : 8 {               |     class TestEnum(enum.IntEnum):                             |
-|         A = 1,                        |         A = 1                                                 |
-|         B = 2..3,                     |         B_MIN = 2                                             |
-|         C = 4,                        |         B_MAX = 3                                             |
-|         OTHER = ..,                   |         C = 4                                                 |
-|     }                                 |                                                               |
-+---------------------------------------+---------------------------------------------------------------+
-
-.. note::
-    Python enums are open by construction, default cases in enum declarations are ignored.
-
-Packet declarations
-^^^^^^^^^^^^^^^^^^^
-
-+---------------------------------------+---------------------------------------------------------------+
-| ::                                    | .. sourcecode:: python                                        |
-|                                       |                                                               |
-|     packet TestPacket {               |     @dataclass                                                |
-|         a: 8,                         |     packet TestPacket(Packet):                                |
-|         b: TestEnum,                  |         a: int = field(kw_only=True, default=0)               |
-|     }                                 |         b: TestEnum = field(kw_only=True, default=TestEnum.A) |
-|                                       |                                                               |
-|                                       |         @staticmethod                                         |
-|                                       |         def parse(span: bytes) -> Tuple['TestPacket', bytes]: |
-|                                       |             pass                                              |
-|                                       |                                                               |
-|                                       |         def serialize(self, payload: bytes = None) -> bytes:  |
-|                                       |             pass                                              |
-|                                       |                                                               |
-|                                       |         @property                                             |
-|                                       |         def size(self) -> int:                                |
-|                                       |             pass                                              |
-+---------------------------------------+---------------------------------------------------------------+
-| ::                                    | .. sourcecode:: python                                        |
-|                                       |                                                               |
-|     packet TestPacket: ParentPacket { |     @dataclass                                                |
-|         a: 8,                         |     packet TestPacket(ParentPacket):                          |
-|         b: TestEnum,                  |         a: int = field(kw_only=True, default=0)               |
-|     }                                 |         b: TestEnum = field(kw_only=True, default=TestEnum.A) |
-|                                       |                                                               |
-|                                       |         @staticmethod                                         |
-|                                       |         def parse(span: bytes) -> Tuple['TestPacket', bytes]: |
-|                                       |             pass                                              |
-|                                       |                                                               |
-|                                       |         def serialize(self, payload: bytes = None) -> bytes:  |
-|                                       |             pass                                              |
-|                                       |                                                               |
-|                                       |         @property                                             |
-|                                       |         def size(self) -> int:                                |
-|                                       |             pass                                              |
-+---------------------------------------+---------------------------------------------------------------+
-
-Field declarations
-^^^^^^^^^^^^^^^^^^
-
-Fields without a binding name do not have a concrete representation in the
-generated class, but are nonetheless validated during parsing or implicitely
-generated during serialization.
-
-+---------------------------------------+---------------------------------------------------------------+
-| ::                                    | .. sourcecode:: python                                        |
-|                                       |                                                               |
-|     a: 8                              |     a: int = field(kw_only=True, default=0)                   |
-+---------------------------------------+---------------------------------------------------------------+
-| ::                                    | .. sourcecode:: python                                        |
-|                                       |                                                               |
-|     a: TestEnum,                      |     a: TestEnum = field(kw_only=True, default=TestEnum.A)     |
-|     b: TestStruct                     |     b: TestStruct = field(kw_only=True,                       |
-|                                       |                           default_factory=TestStruct)         |
-+---------------------------------------+---------------------------------------------------------------+
-| ::                                    | .. sourcecode:: python                                        |
-|                                       |                                                               |
-|     a: 8[],                           |     a: List[int] = field(kw_only=True, default_factory=list)  |
-|     b: 16[128],                       |     b: List[int] = field(kw_only=True, default_factory=list)  |
-|     c: TestEnum[],                    |     c: List[TestEnum] = field(kw_only=True,                   |
-|     d: TestStruct[]                   |                               default_factory=list)           |
-|                                       |     d: List[TestStruct] = field(kw_only=True,                 |
-|                                       |                                 default_factory=list)         |
-+---------------------------------------+---------------------------------------------------------------+
diff --git a/doc/reference.md b/doc/reference.md
deleted file mode 100644
index ce2f0a7..0000000
--- a/doc/reference.md
+++ /dev/null
@@ -1,692 +0,0 @@
-# Packet Description Language
-
-[TOC]
-
-## Notation
-
-|    Notation   |            Example           |                        Meaning                       |
-|:-------------:|:----------------------------:|:----------------------------------------------------:|
-| __ANY__       | __ANY__                      | Any character                                        |
-| CAPITAL       | IDENTIFIER, INT              | A token production                                   |
-| snake_case    | declaration, constraint      | A syntactical production                             |
-| `string`      | `enum`, `=`                  | The exact character(s)                               |
-| \x            | \n, \r, \t, \0               | The character represented by this escape             |
-| x?            | `,`?                         | An optional item                                     |
-| x*            | ALPHANUM*                    | 0 or more of x                                       |
-| x+            | HEXDIGIT+                    | 1 or more of x                                       |
-| x \| y        | ALPHA \| DIGIT, `0x` \| `0X` | Either x or y                                        |
-| [x-y]         | [`a`-`z`]                    | Any of the characters in the range from x to y       |
-| !x            | !\n                          | Negative Predicate (lookahead), do not consume input |
-| ()            | (`,` enum_tag)               | Groups items                                         |
-
-
-[WHITESPACE](#Whitespace) and [COMMENT](#Comment) are implicitly inserted between every item
-and repetitions in syntactical rules (snake_case).
-
-```
-file: endianess declaration*
-```
-behaves like:
-```
-file: (WHITESPACE | COMMENT)* endianess (WHITESPACE | COMMENT)* (declaration | WHITESPACE | COMMENT)*
-```
-
-## File
-
-> file:\
-> &nbsp;&nbsp; endianess [declaration](#declarations)*
->
-> endianess:\
-> &nbsp;&nbsp; `little_endian_packets` | `big_endian_packets`
-
-The structure of a `.pdl`file is:
-1. A declaration of the protocol endianess: `little_endian_packets` or `big_endian_packets`. Followed by
-2. Declarations describing the structure of the protocol.
-
-```
-// The protocol is little endian
-little_endian_packets
-
-// Brew a coffee
-packet Brew {
-  pot: 8, // Output Pot: 8bit, 0-255
-  additions: CoffeeAddition[2] // Coffee Additions: array of 2 CoffeeAddition
-}
-```
-
-The endianess affects how fields of fractional byte sizes (hence named
-bit-fields) are parsed or serialized. Such fields are grouped together to the
-next byte boundary, least significant bit first, and then byte-swapped to the
-required endianess before being written to memory, or after being read from
-memory.
-
-```
-packet Coffee {
-  a: 1,
-  b: 15,
-  c: 3,
-  d: 5,
-}
-
-// The first two field are laid out as a single
-// integer of 16-bits
-//     MSB                                   LSB
-//     16                  8                 0
-//     +---------------------------------------+
-//     | b14 ..                        .. b0 |a|
-//     +---------------------------------------+
-//
-// The file endianness is applied to this integer
-// to obtain the byte layout of the packet fields.
-//
-// Little endian layout
-//     MSB                                   LSB
-//     7    6    5    4    3    2    1    0
-//     +---------------------------------------+
-//  0  |            b[6:0]                | a  |
-//     +---------------------------------------+
-//  1  |               b[14:7]                 |
-//     +---------------------------------------+
-//  2  |          d             |       c      |
-//     +---------------------------------------+
-//
-// Big endian layout
-//     MSB                                   LSB
-//     7    6    5    4    3    2    1    0
-//     +---------------------------------------+
-//  0  |               b[14:7]                 |
-//     +---------------------------------------+
-//  1  |            b[6:0]                | a  |
-//     +---------------------------------------+
-//  2  |          d             |       c      |
-//     +---------------------------------------+
-```
-
-Fields which qualify as bit-fields are:
-- [Scalar](#fields-scalar) fields
-- [Size](#fields-size) fields
-- [Count](#fields-count) fields
-- [Fixed](#fields-fixed) fields
-- [Reserved](#fields-reserved) fields
-- [Typedef](#fields-typedef) fields, when the field type is an
-  [Enum](#enum)
-
-Fields that do not qualify as bit-fields _must_ start and end on a byte boundary.
-
-## Identifiers
-
-- Identifiers can denote a field; an enumeration tag; or a declared type.
-
-- Field identifiers declared in a [packet](#packet) (resp. [struct](#struct)) belong to the _scope_ that extends
-  to the packet (resp. struct), and all derived packets (resp. structs).
-
-- Field identifiers declared in a [group](#group) belong to the _scope_ that
-  extends to the packets declaring a [group field](#group_field) for this group.
-
-- Two fields may not be declared with the same identifier in any packet scope.
-
-- Two types may not be declared width the same identifier.
-
-## Declarations
-
-> declaration: {#declaration}\
-> &nbsp;&nbsp; [enum_declaration](#enum) |\
-> &nbsp;&nbsp; [packet_declaration](#packet) |\
-> &nbsp;&nbsp; [struct_declaration](#struct) |\
-> &nbsp;&nbsp; [group_declaration](#group) |\
-> &nbsp;&nbsp; [checksum_declaration](#checksum) |\
-> &nbsp;&nbsp; [custom_field_declaration](#custom-field) |\
-> &nbsp;&nbsp; [test_declaration](#test)
-
-A *declaration* defines a type inside a `.pdl` file. A declaration can reference
-another declaration appearing later in the file.
-
-A declaration is either:
-- an [Enum](#enum) declaration
-- a [Packet](#packet) declaration
-- a [Struct](#struct) declaration
-- a [Group](#group) declaration
-- a [Checksum](#checksum) declaration
-- a [Custom Field](#custom-field) declaration
-- a [Test](#test) declaration
-
-### Enum
-
-> enum_declaration:\
-> &nbsp;&nbsp; `enum` [IDENTIFIER](#identifier) `:` [INTEGER](#integer) `{`\
-> &nbsp;&nbsp;&nbsp;&nbsp; enum_tag_list\
-> &nbsp;&nbsp; `}`
->
-> enum_tag_list:\
-> &nbsp;&nbsp; enum_tag (`,` enum_tag)* `,`?
->
-> enum_tag:\
-> &nbsp;&nbsp; enum_range | enum_value | enum_other
->
-> enum_range:\
-> &nbsp;&nbsp; [IDENTIFIER](#identifier) `=` [INTEGER](#integer) `..` [INTEGER](#integer)) (`{`\
-> &nbsp;&nbsp;&nbsp;&nbsp; enum_value_list\
-> &nbsp;&nbsp; `}`)?
->
-> enum_value_list:\
-> &nbsp;&nbsp; enum_value (`,` enum_value)* `,`?
->
-> enum_value:\
-> &nbsp;&nbsp; [IDENTIFIER](#identifier) `=` [INTEGER](#integer)
->
-> enum_other:\
-> &nbsp;&nbsp; [IDENTIFIER](#identifier) `=` `..`
-
-An *enumeration* or for short *enum*, is a declaration of a set of named [integer](#integer) constants
-or named [integer](#integer) ranges. [integer](#integer) ranges are inclusive in both ends.
-[integer](#integer) value within a range *must* be unique. [integer](#integer) ranges
-*must not* overlap.
-
-*enumeration* are closed by default, all values that are not explicitely described in the declaration are treated as invalid and _may_ cause a parsing error.
-
-An *enumaration* _may_ be declared open by specifiying the default case; all unrecognized values
-_shall_ falltrough to the default.
-
-The [integer](#integer) following the name specifies the bit size of the values.
-
-```
-enum CoffeeAddition: 5 {
-  Empty = 0,
-
-  NonAlcoholic = 1..9 {
-    Cream = 1,
-    Vanilla = 2,
-    Chocolate = 3,
-  },
-
-  Alcoholic = 10..19 {
-    Whisky = 10,
-    Rum = 11,
-    Kahlua = 12,
-    Aquavit = 13,
-  },
-
-  Custom = 20..29,
-
-  Other = ..
-}
-```
-
-### Packet
-
-> packet_declaration:\
-> &nbsp;&nbsp; `packet` [IDENTIFIER](#identifier)\
-> &nbsp;&nbsp;&nbsp;&nbsp; (`:` [IDENTIFIER](#identifier)\
-> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (`(` [constraint_list](#constraints) `)`)?\
-> &nbsp;&nbsp;&nbsp;&nbsp; )?\
-> &nbsp;&nbsp; `{`\
-> &nbsp;&nbsp;&nbsp;&nbsp; [field_list](#fields)?\
-> &nbsp;&nbsp; `}`
-
-A *packet* is a declaration of a sequence of [fields](#fields). While packets
-can contain bit-fields, the size of the whole packet must be a multiple of 8
-bits.
-
-A *packet* can optionally inherit from another *packet* declaration. In this case the packet
-inherits the parent's fields and the child's fields replace the
-[*\_payload\_*](#fields-payload) or [*\_body\_*](#fields-body) field of the parent.
-
-When inheriting, you can use constraints to set values on parent fields.
-See [constraints](#constraints) for more details.
-
-```
-packet Error {
-  code: 32,
-  _payload_
-}
-
-packet ImATeapot: Error(code = 418) {
-  brand_id: 8
-}
-```
-
-### Struct
-
-> struct_declaration:\
-> &nbsp;&nbsp; `struct` [IDENTIFIER](#identifier)\
-> &nbsp;&nbsp;&nbsp;&nbsp; (`:` [IDENTIFIER](#identifier)\
-> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (`(` [constraint_list](#constraints) `)`)?\
-> &nbsp;&nbsp;&nbsp;&nbsp; )?\
-> &nbsp;&nbsp; `{`\
-> &nbsp;&nbsp;&nbsp;&nbsp; [field_list](#fields)?\
-> &nbsp;&nbsp; `}`
-
-A *struct* follows the same rules as a [*packet*](#packet) with the following differences:
-- It inherits from a *struct* declaration instead of *packet* declaration.
-- A [typedef](#fields-typedef) field can reference a *struct*.
-
-### Group
-
-> group_declaration:\
-> &nbsp;&nbsp; `group` [IDENTIFIER](#identifier) `{`\
-> &nbsp;&nbsp;&nbsp;&nbsp; [field_list](#fields)\
-> &nbsp;&nbsp; `}`
-
-A *group* is a sequence of [fields](#fields) that expand in a
-[packet](#packet) or [struct](#struct) when used.
-
-See also the [Group field](#fields-group).
-
-```
-group Paged {
-  offset: 8,
-  limit: 8
-}
-
-packet AskBrewHistory {
-  pot: 8, // Coffee Pot
-  Paged
-}
-```
-behaves like:
-```
-packet AskBrewHistory {
-  pot: 8, // Coffee Pot
-  offset: 8,
-  limit: 8
-}
-```
-
-### Checksum
-
-> checksum_declaration:\
-> &nbsp;&nbsp; `checksum` [IDENTIFIER](#identifier) `:` [INTEGER](#integer) [STRING](#string)
-
-A *checksum* is a native type (not implemented in PDL). See your generator documentation
-for more information on how to use it.
-
-The [integer](#integer) following the name specify the bit size of the checksum value.
-The [string](#string) following the size is a value defined by the generator implementation.
-
-```
-checksum CRC16: 16 "crc16"
-```
-
-### Custom Field
-
-> custom_field_declaration:\
-> &nbsp;&nbsp; `custom_field` [IDENTIFIER](#identifier) (`:` [INTEGER](#integer))? [STRING](#string)
-
-A *custom field* is a native type (not implemented in PDL). See your generator documentation for more
-information on how to use it.
-
-If present, the [integer](#integer) following the name specify the bit size of the value.
-The [string](#string) following the size is a value defined by the generator implementation.
-
-```
-custom_field URL "url"
-```
-
-### Test
-
-> test_declaration:\
-> &nbsp;&nbsp; `test` [IDENTIFIER](#identifier) `{`\
-> &nbsp;&nbsp;&nbsp;&nbsp; test_case_list\
-> &nbsp;&nbsp; `}`
->
-> test_case_list:\
-> &nbsp;&nbsp; test_case (`,` test_case)* `,`?
->
-> test_case:\
-> &nbsp;&nbsp; [STRING](#string)
-
-A *test* declares a set of valid octet representations of a packet identified by its name.
-The generator implementation defines how to use the test data.
-
-A test passes if the packet parser accepts the input; if you want to test
-the values returned for each field, you may specify a derived packet with field values enforced using
-constraints.
-
-```
-packet Brew {
-  pot: 8,
-  addition: CoffeeAddition
-}
-
-test Brew {
-  "\x00\x00",
-  "\x00\x04"
-}
-
-// Fully Constrained Packet
-packet IrishCoffeeBrew: Brew(pot = 0, additions_list = Whisky) {}
-
-test IrishCoffeeBrew {
-  "\x00\x04"
-}
-```
-
-## Constraints
-
-> constraint:\
-> &nbsp;&nbsp; [IDENTIFIER](#identifier) `=` [IDENTIFIER](#identifier) | [INTEGER](#integer)
->
-> constraint_list:\
-> &nbsp;&nbsp; constraint (`,` constraint)* `,`?
-
-A *constraint* defines the value of a parent field.
-The value can either be an [enum](#enum) tag or an [integer](#integer).
-
-```
-group Additionable {
-  addition: CoffeAddition
-}
-
-packet IrishCoffeeBrew {
-  pot: 8,
-  Additionable {
-    addition = Whisky
-  }
-}
-
-packet Pot0IrishCoffeeBrew: IrishCoffeeBrew(pot = 0) {}
-```
-
-## Fields
-
-> field_list:\
-> &nbsp;&nbsp; field (`,` field)* `,`?
->
-> field:\
-> &nbsp;&nbsp; [checksum_field](#fields-checksum) |\
-> &nbsp;&nbsp; [padding_field](#fields-padding) |\
-> &nbsp;&nbsp; [size_field](#fields-size) |\
-> &nbsp;&nbsp; [count_field](#fields-count) |\
-> &nbsp;&nbsp; [payload_field](#fields-payload) |\
-> &nbsp;&nbsp; [body_field](#fields-body) |\
-> &nbsp;&nbsp; [fixed_field](#fields-fixed) |\
-> &nbsp;&nbsp; [reserved_field](#fields-reserved) |\
-> &nbsp;&nbsp; [array_field](#fields-array) |\
-> &nbsp;&nbsp; [scalar_field](#fields-scalar) |\
-> &nbsp;&nbsp; [typedef_field](#fields-typedef) |\
-> &nbsp;&nbsp; [group_field](#fields-group)
-
-A field is either:
-- a [Scalar](#fields-scalar) field
-- a [Typedef](#fields-typedef) field
-- a [Group](#fields-group) field
-- an [Array](#fields-array) field
-- a [Size](#fields-size) field
-- a [Count](#fields-count) field
-- a [Payload](#fields-payload) field
-- a [Body](#fields-body) field
-- a [Fixed](#fields-fixed) field
-- a [Checksum](#fields-checksum) field
-- a [Padding](#fields-padding) field
-- a [Reserved](#fields-reserved) field
-
-### Scalar {#fields-scalar}
-
-> scalar_field:\
-> &nbsp;&nbsp; [IDENTIFIER](#identifier) `:` [INTEGER](#integer)
-
-A *scalar* field defines a numeric value with a bit size.
-
-```
-struct Coffee {
-  temperature: 8
-}
-```
-
-### Typedef {#fields-typedef}
-
-> typedef_field:\
-> &nbsp;&nbsp; [IDENTIFIER](#identifier) `:` [IDENTIFIER](#identifier)
-
-A *typedef* field defines a field taking as value either an [enum](#enum), [struct](#struct),
-[checksum](#checksum) or a [custom_field](#custom-field).
-
-```
-packet LastTimeModification {
-  coffee: Coffee,
-  addition: CoffeeAddition
-}
-```
-
-### Array {#fields-array}
-
-> array_field:\
-> &nbsp;&nbsp; [IDENTIFIER](#identifier) `:` [INTEGER](#integer) | [IDENTIFIER](#identifier) `[`\
-> &nbsp;&nbsp;&nbsp;&nbsp; [SIZE_MODIFIER](#size-modifier) | [INTEGER](#integer)\
-> &nbsp;&nbsp; `]`
-
-An *array* field defines a sequence of `N` elements of type `T`.
-
-`N` can be:
-- An [integer](#integer) value.
-- A [size modifier](#size-modifier).
-- Unspecified: In this case the array is dynamically sized using a
-[*\_size\_*](#fields-size) or a [*\_count\_*](#fields-count).
-
-`T` can be:
-- An [integer](#integer) denoting the bit size of one element.
-- An [identifier](#identifier) referencing an [enum](#enum), a [struct](#struct)
-or a [custom field](#custom-field) type.
-
-The size of `T` must always be a multiple of 8 bits, that is, the array elements
-must start at byte boundaries.
-
-```
-packet Brew {
-   pots: 8[2],
-   additions: CoffeeAddition[2],
-   extra_additions: CoffeeAddition[],
-}
-```
-
-### Group {#fields-group}
-
-> group_field:\
-> &nbsp;&nbsp; [IDENTIFIER](#identifier) (`{` [constraint_list](#constraints) `}`)?
-
-A *group* field inlines all the fields defined in the referenced group.
-
-If a [constraint list](#constraints) constrains a [scalar](#fields-scalar) field
-or [typedef](#fields-typedef) field with an [enum](#enum) type, the field will
-become a [fixed](#fields-fixed) field.
-The [fixed](#fields-fixed) field inherits the type or size of the original field and the
-value from the constraint list.
-
-See [Group Declaration](#group) for more information.
-
-### Size {#fields-size}
-
-> size_field:\
-> &nbsp;&nbsp; `_size_` `(` [IDENTIFIER](#identifier) | `_payload_` | `_body_` `)` `:` [INTEGER](#integer)
-
-A *\_size\_* field is a [scalar](#fields-scalar) field with as value the size in octet of the designated
-[array](#fields-array), [*\_payload\_*](#fields-payload) or [*\_body\_*](#fields-body).
-
-```
-packet Parent {
-  _size_(_payload_): 2,
-  _payload_
-}
-
-packet Brew {
-  pot: 8,
-  _size_(additions): 8,
-  additions: CoffeeAddition[]
-}
-```
-
-### Count {#fields-count}
-
-> count_field:\
-> &nbsp;&nbsp; `_count_` `(` [IDENTIFIER](#identifier) `)` `:` [INTEGER](#integer)
-
-A *\_count\_* field is a [*scalar*](#fields-scalar) field with as value the number of elements of the designated
-[array](#fields-array).
-
-```
-packet Brew {
-  pot: 8,
-  _count_(additions): 8,
-  additions: CoffeeAddition[]
-}
-```
-
-### Payload {#fields-payload}
-
-> payload_field:\
-> &nbsp;&nbsp; `_payload_` (`:` `[` [SIZE_MODIFIER](#size-modifier) `]` )?
-
-A *\_payload\_* field is a dynamically sized array of octets.
-
-It declares where to parse the definition of a child [packet](#packet) or [struct](#struct).
-
-A [*\_size\_*](#fields-size) or a [*\_count\_*](#fields-count) field referencing
-the payload induce its size.
-
-If used, a [size modifier](#size-modifier) can alter the octet size.
-
-### Body {#fields-body}
-
-> body_field:\
-> &nbsp;&nbsp; `_body_`
-
-A *\_body\_* field is like a [*\_payload\_*](#fields-payload) field with the following differences:
-- The body field is private to the packet definition, it's accessible only when inheriting.
-- The body does not accept a size modifier.
-
-### Fixed {#fields-fixed}
-
-> fixed_field:\
-> &nbsp;&nbsp; `_fixed_` `=` \
-> &nbsp;&nbsp;&nbsp;&nbsp; ( [INTEGER](#integer) `:` [INTEGER](#integer) ) |\
-> &nbsp;&nbsp;&nbsp;&nbsp; ( [IDENTIFIER](#identifier) `:` [IDENTIFIER](#identifier) )
-
-A *\_fixed\_* field defines a constant with a known bit size.
-The constant can be either:
-- An [integer](#integer) value
-- An [enum](#enum) tag
-
-```
-packet Teapot {
-  _fixed_ = 42: 8,
-  _fixed_ = Empty: CoffeeAddition
-}
-```
-
-### Checksum {#fields-checksum}
-
-> checksum_field:\
-> &nbsp;&nbsp; `_checksum_start_` `(` [IDENTIFIER](#identifier) `)`
-
-A *\_checksum_start\_* field is a zero sized field that acts as a marker for the beginning of
-the fields covered by a checksum.
-
-The *\_checksum_start\_* references a [typedef](#fields-typedef) field
-with a [checksum](#checksum) type that stores the checksum value and selects the algorithm
-for the checksum.
-
-```
-checksum CRC16: 16 "crc16"
-
-packet CRCedBrew {
-  crc: CRC16,
-  _checksum_start_(crc),
-  pot: 8,
-}
-```
-
-### Padding {#fields-padding}
-
-> padding_field:\
-> &nbsp;&nbsp; `_padding_` `[` [INTEGER](#integer) `]`
-
-A *\_padding\_* field immediately following an array field pads the array field with `0`s to the
-specified number of **octets**.
-
-```
-packet PaddedCoffee {
-  additions: CoffeeAddition[],
-  _padding_[100]
-}
-```
-
-### Reserved {#fields-reserved}
-
-> reserved_field:\
-> &nbsp;&nbsp; `_reserved_` `:` [INTEGER](#integer)
-
-A *\_reserved\_* field adds reserved bits.
-
-```
-packet DeloreanCoffee {
-  _reserved_: 2014
-}
-```
-
-## Tokens
-
-### Integer
-
-> INTEGER:\
-> &nbsp;&nbsp; HEXVALUE | INTVALUE
->
-> HEXVALUE:\
-> &nbsp;&nbsp; `0x` | `0X` HEXDIGIT<sup>+</sup>
->
-> INTVALUE:\
-> &nbsp;&nbsp; DIGIT<sup>+</sup>
->
-> HEXDIGIT:\
-> &nbsp;&nbsp; DIGIT | [`a`-`f`] | [`A`-`F`]
->
-> DIGIT:\
-> &nbsp;&nbsp; [`0`-`9`]
-
-A integer is a number in base 10 (decimal) or in base 16 (hexadecimal) with
-the prefix `0x`
-
-### String
-
-> STRING:\
-> &nbsp;&nbsp; `"` (!`"` __ANY__)* `"`
-
-A string is sequence of character. It can be multi-line.
-
-### Identifier
-
-> IDENTIFIER: \
-> &nbsp;&nbsp; ALPHA (ALPHANUM | `_`)*
->
-> ALPHA:\
-> &nbsp;&nbsp; [`a`-`z`] | [`A`-`Z`]
->
-> ALPHANUM:\
-> &nbsp;&nbsp; ALPHA | DIGIT
-
-An identifier is a sequence of alphanumeric or `_` characters
-starting with a letter.
-
-### Size Modifier
-
-> SIZE_MODIFIER:\
-> &nbsp;&nbsp; `+` INTVALUE
-
-A size modifier alters the octet size of the field it is attached to.
-For example, `+ 2` defines that the size is 2 octet bigger than the
-actual field size.
-
-### Comment
-
-> COMMENT:\
-> &nbsp;&nbsp; BLOCK_COMMENT | LINE_COMMENT
->
-> BLOCK_COMMENT:\
-> &nbsp;&nbsp; `/*` (!`*/` ANY) `*/`
->
-> LINE_COMMENT:\
-> &nbsp;&nbsp; `//` (!\n ANY) `//`
-
-### Whitespace
-
-> WHITESPACE:\
-> &nbsp;&nbsp; ` ` | `\t` | `\n`
diff --git a/doc/rust-generated-code-guide.rst b/doc/rust-generated-code-guide.rst
deleted file mode 100644
index 6dfdfd0..0000000
--- a/doc/rust-generated-code-guide.rst
+++ /dev/null
@@ -1,98 +0,0 @@
-Rust Generated Code Guide
-=========================
-
-Usage
------
-
-Example invocation:
-
-.. sourcecode:: bash
-
-    cargo run my-protocol.pdl --output-format rust > my-protocol.rs
-
-Language bindings
------------------
-
-This section contains the generated rust bindings for language constructs that
-are stabilized.
-
-Preamble
-^^^^^^^^
-
-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.
-
-.. sourcecode:: rust
-
-        #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
-        pub struct Private<T>(T);
-
-        impl<T> std::ops::Deref for Private<T> { .. }
-
-.. warning::
-    PDL authorizes the use of rust keywords as identifier. Keyword identifiers
-    are generated as raw identifiers, e.g. `type` is generated as `r#type`.
-
-Enum declarations
-^^^^^^^^^^^^^^^^^
-
-+---------------------------------------+---------------------------------------------------------------+
-| ::                                    | .. sourcecode:: rust                                          |
-|                                       |                                                               |
-|     enum TestEnum : 8 {               |     #[repr(u64)]                                              |
-|         A = 1,                        |     #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]        |
-|         B = 2,                        |     enum TestEnum {                                           |
-|     }                                 |         A = 1,                                                |
-|                                       |         B = 2,                                                |
-|                                       |     }                                                         |
-|                                       |                                                               |
-|                                       |     impl TryFrom<u8> for TestEnum { .. }                      |
-|                                       |     impl From<TestEnum> for u8 { .. }                         |
-|                                       |     impl From<TestEnum> for u16 { .. }                        |
-|                                       |     impl From<TestEnum> for u32 { .. }                        |
-|                                       |     impl From<TestEnum> for u64 { .. }                        |
-|                                       |     impl From<TestEnum> for i8 { .. }                         |
-|                                       |     impl From<TestEnum> for i16 { .. }                        |
-|                                       |     impl From<TestEnum> for i32 { .. }                        |
-|                                       |     impl From<TestEnum> for i64 { .. }                        |
-+---------------------------------------+---------------------------------------------------------------+
-| ::                                    | .. sourcecode:: rust                                          |
-|                                       |                                                               |
-|     enum TestEnum : 8 {               |     #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]        |
-|         A = 1,                        |     enum TestEnum {                                           |
-|         B = 2..10 {                   |         A,                                                    |
-|             C = 3,                    |         C,                                                    |
-|         },                            |         B(Private<u8>),                                       |
-|     }                                 |     }                                                         |
-|                                       |                                                               |
-|                                       |     impl TryFrom<u8> for TestEnum { .. }                      |
-|                                       |     impl From<TestEnum> for u8 { .. }                         |
-|                                       |     impl From<TestEnum> for u16 { .. }                        |
-|                                       |     impl From<TestEnum> for u32 { .. }                        |
-|                                       |     impl From<TestEnum> for u64 { .. }                        |
-|                                       |     impl From<TestEnum> for i8 { .. }                         |
-|                                       |     impl From<TestEnum> for i16 { .. }                        |
-|                                       |     impl From<TestEnum> for i32 { .. }                        |
-|                                       |     impl From<TestEnum> for i64 { .. }                        |
-+---------------------------------------+---------------------------------------------------------------+
-| ::                                    | .. sourcecode:: rust                                          |
-|                                       |                                                               |
-|     enum TestEnum : 8 {               |     #[repr(u64)]                                              |
-|         A = 1,                        |     #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]        |
-|         B = 2,                        |     enum TestEnum {                                           |
-|         OTHER = ..,                   |         A,                                                    |
-|     }                                 |         B,                                                    |
-|                                       |         Other(Private<u8>),                                   |
-|                                       |     }                                                         |
-|                                       |                                                               |
-|                                       |     impl From<u8> for TestEnum { .. }                         |
-|                                       |     impl From<TestEnum> for u8 { .. }                         |
-|                                       |     impl From<TestEnum> for u16 { .. }                        |
-|                                       |     impl From<TestEnum> for u32 { .. }                        |
-|                                       |     impl From<TestEnum> for u64 { .. }                        |
-|                                       |     impl From<TestEnum> for i8 { .. }                         |
-|                                       |     impl From<TestEnum> for i16 { .. }                        |
-|                                       |     impl From<TestEnum> for i32 { .. }                        |
-|                                       |     impl From<TestEnum> for i64 { .. }                        |
-+---------------------------------------+---------------------------------------------------------------+
diff --git a/examples/jpeg.pdl b/examples/jpeg.pdl
deleted file mode 100644
index 75cde23..0000000
--- a/examples/jpeg.pdl
+++ /dev/null
@@ -1,88 +0,0 @@
-// Grammar file for the Jpeg File Format.
-// https://www.w3.org/Graphics/JPEG/jfif3.pdf
-
-big_endian_packets
-
-enum MarkerType : 8 {
-    NUL = 0x00, // JPEG reserved
-    TEM = 0x01, // temporary marker for arithmetic coding
-
-    // frame types
-    SOF0 = 0xc0, // start of frame (baseline jpeg)
-    SOF1 = 0xc1, // start of frame (extended sequential, huffman)
-    SOF2 = 0xc2, // start of frame (progressive, huffman)
-    SOF3 = 0xc3, // start of frame (lossless, huffman) libjpeg-unsupported
-    SOF5 = 0xc5, // start of frame (differential sequential, huffman) libjpeg-unsupported
-    SOF6 = 0xc6, // start of frame (differential progressive, huffman) libjpeg-unsupported
-    SOF7 = 0xc7, // start of frame (differential lossless, huffman) libjpeg-unsupported
-    SOF9 = 0xc9, // start of frame (extended sequential, arithmetic)
-    SOF10 = 0xca, // start of frame (progressive, arithmetic)
-    SOF11 = 0xcb, // start of frame (lossless, arithmetic) libjpeg-unsupported
-    SOF13 = 0xcd, // start of frame (differential sequential, arithmetic) libjpeg-unsupported
-    SOF14 = 0xce, // start of frame (differential progressive, arithmetic) libjpeg-unsupported
-    SOF15 = 0xcf, // start of frame (differential lossless, arithmetic) libjpeg-unsupported
-
-    DHT = 0xc4, // define huffman tables
-    JPG = 0xc8, // reserved for JPEG extension libjpeg-unsupported
-    DAC = 0xcc, // define arithmetic coding conditioning libjpeg-skipped
-
-    // restart markers (parameterless), only in scans data
-    RST = 0xd0..0xd7,
-
-    // delimiters
-    SOI = 0xd8, // start of image (parameterless)
-    EOI = 0xd9, // end of image (parameterless)
-    SOS = 0xda, // start of scan
-    DQT = 0xdb, // define quantization table(s)
-    DNL = 0xdc, // define number of lines # libjpeg-skipped
-    DRI = 0xdd, // define restart interval
-    DHP = 0xde, // define hierarchical progression
-    EXP = 0xdf, // expand reference components
-    COM = 0xfe, // extension data (comment)
-
-    // application segments
-    APP0 = 0xe0, // application segment 0 (JFIF (len >=14) / JFXX (len >= 6) / AVI MJPEG)
-    APP1 = 0xe1, // application segment 1 (EXIF/XMP/XAP ?)
-    APP2 = 0xe2, // application segment 2 (FlashPix / ICC)
-    APP3 = 0xe3, // application segment 3 (Kodak/...)
-    APP4 = 0xe4, // application segment 4 (FlashPix/...)
-    APP5 = 0xe5, // application segment 5 (Ricoh...)
-    APP6 = 0xe6, // application segment 6 (GoPro...)
-    APP7 = 0xe7, // application segment 7 (Pentax/Qualcomm)
-    APP8 = 0xe8, // application segment 8 (Spiff)
-    APP9 = 0xe9, // application segment 9 (MediaJukebox)
-    APP10 = 0xea, // application segment 10 (PhotoStudio)
-    APP11 = 0xeb, // application segment 11 (HDR)
-    APP12 = 0xec, // application segment 12 (photoshoP ducky / savE foR web)
-    APP13 = 0xed, // application segment 13 (photoshoP savE As)
-    APP14 = 0xee, // application segment 14 ("adobe" (length = 12))
-    APP15 = 0xef, // application segment 15 (GraphicConverter)
-}
-
-struct Marker {
-    _fixed_ = 0xff : 8,
-    type: MarkerType,
-    _payload_,
-}
-
-struct Segment: Marker {
-    _size_(_payload_): 16,
-    _payload_ [+2],
-}
-
-struct StartOfImage : Marker(type = SOI) {}
-struct EndOfImage : Marker(type = EOI) {}
-
-packet Image {
-    start: StartOfImage,
-    segments: Segment[],
-    // The payload contains the Entropy-Coded Segment, which doesn't follow any
-    // similar convention despite the same segment name. They represent most of
-    // the file's data. Its length is unknown in advance, nor defined in the
-    // file. The only way to get its length is to either decode it or to
-    // fast-forward over it: just scan forward for a FF byte.
-    // If it's a restart marker (followed by D0 - D7) or a data FF
-    // (followed by 00), continue.
-    _payload_,
-    end: EndOfImage,
-}
diff --git a/examples/pcap.pdl b/examples/pcap.pdl
deleted file mode 100644
index a40c0b0..0000000
--- a/examples/pcap.pdl
+++ /dev/null
@@ -1,27 +0,0 @@
-// Grammar file for the Libpcap File Format.
-// https://wiki.wireshark.org/Development/LibpcapFileFormat
-
-little_endian_packets
-
-struct PcapHeader {
-  _fixed_ = 0xa1b2c3d4: 32, /* magic number */
-  version_major: 16,
-  version_minor: 16,
-  thiszone: 32,  /* GMT to local correction */
-  sigfigs: 32,  /* accuracy of timestamps */
-  snaplen: 32,  /* max length of captured packets, in octets */
-  network: 32,  /* data link type */
-}
-
-struct PcapRecord {
-  ts_sec: 32,  /* timestamp seconds */
-  ts_usec: 32,  /* timestamp microseconds */
-  _size_(_payload_): 32, /* number of octets of packet saved in file */
-  orig_len: 32,  /* actual length of packet */
-  _payload_,  /* packet octets */
-}
-
-packet PcapFile {
-  header: PcapHeader,
-  records: PcapRecord[],
-}
diff --git a/rustfmt.toml b/rustfmt.toml
deleted file mode 100644
index 7b16ab7..0000000
--- a/rustfmt.toml
+++ /dev/null
@@ -1,8 +0,0 @@
-# Android Format Style
-#
-# Copied from Android:
-# https://cs.android.com/android/platform/superproject/+/master:packages/modules/Bluetooth/rustfmt.toml.
-
-edition = "2021"
-use_small_heuristics = "Max"
-newline_style = "Unix"
diff --git a/scripts/generate_cxx_backend.py b/scripts/generate_cxx_backend.py
index 4937079..d3abb39 100755
--- a/scripts/generate_cxx_backend.py
+++ b/scripts/generate_cxx_backend.py
@@ -817,7 +817,9 @@
     enum_type = get_cxx_scalar_type(decl.width)
     tag_decls = []
     for t in decl.tags:
-        tag_decls.append(f"{t.id} = {hex(t.value)},")
+        # Exclude default tags: DEFAULT = ..
+        if t.value is not None:
+            tag_decls.append(f"{t.id} = {hex(t.value)},")
 
     return dedent("""\
 
@@ -833,7 +835,9 @@
     enum_name = decl.id
     tag_cases = []
     for t in decl.tags:
-        tag_cases.append(f"case {enum_name}::{t.id}: return \"{t.id}\";")
+        # Exclude default tags: DEFAULT = ..
+        if t.value is not None:
+            tag_cases.append(f"case {enum_name}::{t.id}: return \"{t.id}\";")
 
     return dedent("""\
 
@@ -1654,7 +1658,7 @@
 
 
 def run(input: argparse.FileType, output: argparse.FileType, namespace: Optional[str], include_header: List[str],
-        using_namespace: List[str]):
+        using_namespace: List[str], exclude_declaration: List[str]):
 
     file = ast.File.from_json(json.load(input))
     core.desugar(file)
@@ -1664,28 +1668,6 @@
     open_namespace = f"namespace {namespace} {{" if namespace else ""
     close_namespace = f"}}  // {namespace}" if namespace else ""
 
-    # Disable unsupported features in the canonical test suite.
-    skipped_decls = [
-        'Packet_Custom_Field_ConstantSize',
-        'Packet_Custom_Field_VariableSize',
-        'Packet_Checksum_Field_FromStart',
-        'Packet_Checksum_Field_FromEnd',
-        'Struct_Custom_Field_ConstantSize',
-        'Struct_Custom_Field_VariableSize',
-        'Struct_Checksum_Field_FromStart',
-        'Struct_Checksum_Field_FromEnd',
-        'Struct_Custom_Field_ConstantSize_',
-        'Struct_Custom_Field_VariableSize_',
-        'Struct_Checksum_Field_FromStart_',
-        'Struct_Checksum_Field_FromEnd_',
-        'PartialParent5',
-        'PartialChild5_A',
-        'PartialChild5_B',
-        'PartialParent12',
-        'PartialChild12_A',
-        'PartialChild12_B',
-    ]
-
     output.write(
         dedent("""\
         // File generated from {input_name}, with the command:
@@ -1728,7 +1710,7 @@
             output.write(f"class {d.id}View;\n")
 
     for d in file.declarations:
-        if d.id in skipped_decls:
+        if d.id in exclude_declaration:
             continue
 
         if isinstance(d, ast.EnumDeclaration):
@@ -1755,6 +1737,11 @@
                         default=[],
                         action='append',
                         help='Added using namespace statements')
+    parser.add_argument('--exclude-declaration',
+                        type=str,
+                        default=[],
+                        action='append',
+                        help='Exclude declaration from the generated output')
     return run(**vars(parser.parse_args()))
 
 
diff --git a/scripts/generate_cxx_backend_tests.py b/scripts/generate_cxx_backend_tests.py
index 818d376..d8ddd44 100755
--- a/scripts/generate_cxx_backend_tests.py
+++ b/scripts/generate_cxx_backend_tests.py
@@ -328,6 +328,10 @@
         'Struct_Checksum_Field_FromEnd',
         'PartialParent5',
         'PartialParent12',
+        'Packet_Array_Field_VariableElementSize_ConstantSize',
+        'Packet_Array_Field_VariableElementSize_VariableSize',
+        'Packet_Array_Field_VariableElementSize_VariableCount',
+        'Packet_Array_Field_VariableElementSize_UnknownSize',
     ]
 
     output.write(
diff --git a/scripts/generate_python_backend.py b/scripts/generate_python_backend.py
index 8938173..a3a06de 100755
--- a/scripts/generate_python_backend.py
+++ b/scripts/generate_python_backend.py
@@ -33,7 +33,7 @@
 def generate_prelude() -> str:
     return dedent("""\
         from dataclasses import dataclass, field, fields
-        from typing import Optional, List, Tuple
+        from typing import Optional, List, Tuple, Union
         import enum
         import inspect
         import math
@@ -412,7 +412,7 @@
                 self.unchecked_append_(f"if {v} != {hex(field.value)}:")
                 self.unchecked_append_(f"    raise Exception('Unexpected fixed field value')")
             elif isinstance(field, ast.TypedefField):
-                self.unchecked_append_(f"fields['{field.id}'] = {field.type_id}({v})")
+                self.unchecked_append_(f"fields['{field.id}'] = {field.type_id}.from_int({v})")
             elif isinstance(field, ast.SizeField):
                 self.unchecked_append_(f"{field.field_id}_size = {v}")
             elif isinstance(field, ast.CountField):
@@ -1012,17 +1012,37 @@
     enum_name = decl.id
     tag_decls = []
     for t in decl.tags:
+        # Enums in python are closed and ranges cannot be represented;
+        # instead the generated code uses Union[int, Enum]
+        # when ranges are used.
         if t.value is not None:
             tag_decls.append(f"{t.id} = {hex(t.value)}")
-        if t.range is not None:
-            tag_decls.append(f"{t.id}_START = {hex(t.range[0])}")
-            tag_decls.append(f"{t.id}_END = {hex(t.range[1])}")
+
+    if core.is_open_enum(decl):
+        unknown_handler = ["return v"]
+    else:
+        unknown_handler = []
+        for t in decl.tags:
+            if t.range is not None:
+                unknown_handler.append(f"if v >= 0x{t.range[0]:x} and v <= 0x{t.range[1]:x}:")
+                unknown_handler.append(f"    return v")
+        unknown_handler.append("raise exn")
 
     return dedent("""\
 
         class {enum_name}(enum.IntEnum):
             {tag_decls}
-        """).format(enum_name=enum_name, tag_decls=indent(tag_decls, 1))
+
+            @staticmethod
+            def from_int(v: int) -> Union[int, '{enum_name}']:
+                try:
+                    return {enum_name}(v)
+                except ValueError as exn:
+                    {unknown_handler}
+
+        """).format(enum_name=enum_name,
+                    tag_decls=indent(tag_decls, 1),
+                    unknown_handler=indent(unknown_handler, 3))
 
 
 def generate_packet_declaration(packet: ast.Declaration) -> str:
@@ -1047,7 +1067,10 @@
         elif isinstance(f, ast.ScalarField):
             field_decls.append(f"{f.id}: int = field(kw_only=True, default=0)")
         elif isinstance(f, ast.TypedefField):
-            if isinstance(f.type, ast.EnumDeclaration):
+            if isinstance(f.type, ast.EnumDeclaration) and f.type.tags[0].range:
+                field_decls.append(
+                    f"{f.id}: {f.type_id} = field(kw_only=True, default={f.type.tags[0].range[0]})")
+            elif isinstance(f.type, ast.EnumDeclaration):
                 field_decls.append(
                     f"{f.id}: {f.type_id} = field(kw_only=True, default={f.type_id}.{f.type.tags[0].id})")
             elif isinstance(f.type, ast.ChecksumDeclaration):
@@ -1134,13 +1157,16 @@
     """).format(checksum_name=decl.id)
 
 
-def run(input: argparse.FileType, output: argparse.FileType, custom_type_location: Optional[str]):
+def run(input: argparse.FileType, output: argparse.FileType, custom_type_location: Optional[str], exclude_declaration: List[str]):
     file = ast.File.from_json(json.load(input))
     core.desugar(file)
 
     custom_types = []
     custom_type_checks = ""
     for d in file.declarations:
+        if d.id in exclude_declaration:
+            continue
+
         if isinstance(d, ast.CustomFieldDeclaration):
             custom_types.append(d.id)
             custom_type_checks += generate_custom_field_declaration_check(d)
@@ -1157,6 +1183,9 @@
     output.write(custom_type_checks)
 
     for d in file.declarations:
+        if d.id in exclude_declaration:
+            continue
+
         if isinstance(d, ast.EnumDeclaration):
             output.write(generate_enum_declaration(d))
         elif isinstance(d, (ast.PacketDeclaration, ast.StructDeclaration)):
@@ -1172,6 +1201,11 @@
                         type=str,
                         required=False,
                         help='Module of declaration of custom types')
+    parser.add_argument('--exclude-declaration',
+                        type=str,
+                        default=[],
+                        action='append',
+                        help='Exclude declaration from the generated output')
     return run(**vars(parser.parse_args()))
 
 
diff --git a/scripts/pdl/ast.py b/scripts/pdl/ast.py
index 5ade0fa..341fac5 100644
--- a/scripts/pdl/ast.py
+++ b/scripts/pdl/ast.py
@@ -87,6 +87,12 @@
     width: int
 
 
+@node('elementsize_field')
+class ElementSize(Field):
+    field_id: str
+    width: int
+
+
 @node('count_field')
 class CountField(Field):
     field_id: str
@@ -276,6 +282,8 @@
         loc = obj['loc']
         loc = SourceRange(loc['file'], SourceLocation(**loc['start']), SourceLocation(**loc['end']))
         constructor = constructors_.get(kind)
+        if not constructor:
+            raise Exception(f'Unknown kind {kind}')
         members = {'loc': loc, 'kind': kind}
         cond = None
         for name, value in obj.items():
diff --git a/scripts/pdl/core.py b/scripts/pdl/core.py
index 5ddbb02..27da56b 100644
--- a/scripts/pdl/core.py
+++ b/scripts/pdl/core.py
@@ -360,3 +360,9 @@
 
     else:
         return False
+
+def is_open_enum(decl: EnumDeclaration) -> bool:
+    """Return true if the enum declaration is open, i.e. contains a tag
+    declaration of the form DEFAULT = .."""
+
+    return any(t.value is None for t in decl.tags)
diff --git a/src/analyzer.rs b/src/analyzer.rs
index b80a6b6..90ed239 100644
--- a/src/analyzer.rs
+++ b/src/analyzer.rs
@@ -19,128 +19,70 @@
 use std::collections::HashMap;
 
 use crate::ast::*;
-use crate::parser::ast as parser_ast;
 
-pub mod ast {
-    use serde::Serialize;
+/// Field and declaration size information.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[allow(unused)]
+pub enum Size {
+    /// Constant size in bits.
+    Static(usize),
+    /// Size indicated at packet parsing by a size or count field.
+    /// The parameter is the static part of the size.
+    Dynamic,
+    /// The size cannot be determined statically or at runtime.
+    /// The packet assumes the largest possible size.
+    Unknown,
+}
 
-    /// Field and declaration size information.
-    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
-    #[allow(unused)]
-    pub enum Size {
-        /// Constant size in bits.
-        Static(usize),
-        /// Size indicated at packet parsing by a size or count field.
-        /// The parameter is the static part of the size.
-        Dynamic,
-        /// The size cannot be determined statically or at runtime.
-        /// The packet assumes the largest possible size.
-        Unknown,
+// TODO: use derive(Default) when UWB is using Rust 1.62.0.
+#[allow(clippy::derivable_impls)]
+impl Default for Size {
+    fn default() -> Size {
+        Size::Unknown
     }
+}
 
-    // TODO: use derive(Default) when UWB is using Rust 1.62.0.
-    #[allow(clippy::derivable_impls)]
-    impl Default for Size {
-        fn default() -> Size {
-            Size::Unknown
+impl std::ops::Add for Size {
+    type Output = Size;
+    fn add(self, rhs: Size) -> Self::Output {
+        match (self, rhs) {
+            (Size::Unknown, _) | (_, Size::Unknown) => Size::Unknown,
+            (Size::Dynamic, _) | (_, Size::Dynamic) => Size::Dynamic,
+            (Size::Static(lhs), Size::Static(rhs)) => Size::Static(lhs + rhs),
         }
     }
+}
 
-    #[derive(Debug, Serialize, Default, Clone, PartialEq)]
-    pub struct Annotation;
-
-    #[derive(Default, Debug, Clone, PartialEq, Eq)]
-    pub struct FieldAnnotation {
-        // Size of field.
-        pub size: Size,
-        // Size of field with padding bytes.
-        // This information exists only for array fields.
-        pub padded_size: Option<usize>,
-    }
-
-    #[derive(Default, Debug, Clone, PartialEq, Eq)]
-    pub struct DeclAnnotation {
-        // Size computed excluding the payload.
-        pub size: Size,
-        // Payload size, or Static(0) if the declaration does not
-        // have a payload.
-        pub payload_size: Size,
-    }
-
-    impl std::ops::Add for Size {
-        type Output = Size;
-        fn add(self, rhs: Size) -> Self::Output {
-            match (self, rhs) {
-                (Size::Unknown, _) | (_, Size::Unknown) => Size::Unknown,
-                (Size::Dynamic, _) | (_, Size::Dynamic) => Size::Dynamic,
-                (Size::Static(lhs), Size::Static(rhs)) => Size::Static(lhs + rhs),
-            }
+impl std::ops::Mul for Size {
+    type Output = Size;
+    fn mul(self, rhs: Size) -> Self::Output {
+        match (self, rhs) {
+            (Size::Unknown, _) | (_, Size::Unknown) => Size::Unknown,
+            (Size::Dynamic, _) | (_, Size::Dynamic) => Size::Dynamic,
+            (Size::Static(lhs), Size::Static(rhs)) => Size::Static(lhs * rhs),
         }
     }
+}
 
-    impl std::ops::Mul for Size {
-        type Output = Size;
-        fn mul(self, rhs: Size) -> Self::Output {
-            match (self, rhs) {
-                (Size::Unknown, _) | (_, Size::Unknown) => Size::Unknown,
-                (Size::Dynamic, _) | (_, Size::Dynamic) => Size::Dynamic,
-                (Size::Static(lhs), Size::Static(rhs)) => Size::Static(lhs * rhs),
-            }
+impl std::ops::Mul<usize> for Size {
+    type Output = Size;
+    fn mul(self, rhs: usize) -> Self::Output {
+        match self {
+            Size::Unknown => Size::Unknown,
+            Size::Dynamic => Size::Dynamic,
+            Size::Static(lhs) => Size::Static(lhs * rhs),
         }
     }
+}
 
-    impl std::ops::Mul<usize> for Size {
-        type Output = Size;
-        fn mul(self, rhs: usize) -> Self::Output {
-            match self {
-                Size::Unknown => Size::Unknown,
-                Size::Dynamic => Size::Dynamic,
-                Size::Static(lhs) => Size::Static(lhs * rhs),
-            }
+impl Size {
+    // Returns the width if the size is static.
+    pub fn static_(&self) -> Option<usize> {
+        match self {
+            Size::Static(size) => Some(*size),
+            Size::Dynamic | Size::Unknown => None,
         }
     }
-
-    impl Size {
-        // Returns the width if the size is static.
-        pub fn static_(&self) -> Option<usize> {
-            match self {
-                Size::Static(size) => Some(*size),
-                Size::Dynamic | Size::Unknown => None,
-            }
-        }
-    }
-
-    impl DeclAnnotation {
-        pub fn total_size(&self) -> Size {
-            self.size + self.payload_size
-        }
-    }
-
-    impl FieldAnnotation {
-        pub fn new(size: Size) -> Self {
-            FieldAnnotation { size, padded_size: None }
-        }
-
-        // Returns the field width or padded width if static.
-        pub fn static_(&self) -> Option<usize> {
-            match self.padded_size {
-                Some(padding) => Some(8 * padding),
-                None => self.size.static_(),
-            }
-        }
-    }
-
-    impl crate::ast::Annotation for Annotation {
-        type FieldAnnotation = FieldAnnotation;
-        type DeclAnnotation = DeclAnnotation;
-    }
-
-    #[allow(unused)]
-    pub type Field = crate::ast::Field<Annotation>;
-    #[allow(unused)]
-    pub type Decl = crate::ast::Decl<Annotation>;
-    #[allow(unused)]
-    pub type File = crate::ast::File<Annotation>;
 }
 
 /// List of unique errors reported as analyzer diagnostics.
@@ -212,12 +154,21 @@
 
 /// Gather information about the full AST.
 #[derive(Debug)]
-pub struct Scope<'d, A: Annotation = ast::Annotation> {
+pub struct Scope<'d> {
     /// Reference to the source file.
-    pub file: &'d crate::ast::File<A>,
+    pub file: &'d File,
     /// Collection of Group, Packet, Enum, Struct, Checksum, and CustomField
     /// declarations.
-    pub typedef: HashMap<String, &'d crate::ast::Decl<A>>,
+    pub typedef: HashMap<String, &'d Decl>,
+}
+
+/// Gather size information about the full AST.
+#[derive(Debug)]
+pub struct Schema {
+    decl_size: HashMap<DeclKey, Size>,
+    field_size: HashMap<FieldKey, Size>,
+    padded_size: HashMap<FieldKey, Option<usize>>,
+    payload_size: HashMap<DeclKey, Size>,
 }
 
 impl Diagnostics {
@@ -250,10 +201,10 @@
     }
 }
 
-impl<'d, A: Annotation + Default> Scope<'d, A> {
-    pub fn new(file: &'d crate::ast::File<A>) -> Result<Scope<'d, A>, Diagnostics> {
+impl<'d> Scope<'d> {
+    pub fn new(file: &'d File) -> Result<Scope<'d>, Diagnostics> {
         // Gather top-level declarations.
-        let mut scope: Scope<A> = Scope { file, typedef: Default::default() };
+        let mut scope: Scope = Scope { file, typedef: Default::default() };
         let mut diagnostics: Diagnostics = Default::default();
         for decl in &file.declarations {
             if let Some(id) = decl.id() {
@@ -286,24 +237,18 @@
     }
 
     /// Iterate over the child declarations of the selected declaration.
-    pub fn iter_children<'s>(
-        &'s self,
-        decl: &'d crate::ast::Decl<A>,
-    ) -> impl Iterator<Item = &'d crate::ast::Decl<A>> + 's {
+    pub fn iter_children<'s>(&'s self, decl: &'d Decl) -> impl Iterator<Item = &'d Decl> + 's {
         self.file.iter_children(decl)
     }
 
     /// Return the parent declaration of the selected declaration,
     /// if it has one.
-    pub fn get_parent(&self, decl: &crate::ast::Decl<A>) -> Option<&'d crate::ast::Decl<A>> {
+    pub fn get_parent(&self, decl: &Decl) -> Option<&'d Decl> {
         decl.parent_id().and_then(|parent_id| self.typedef.get(parent_id).cloned())
     }
 
     /// Iterate over the parent declarations of the selected declaration.
-    pub fn iter_parents<'s>(
-        &'s self,
-        decl: &'d crate::ast::Decl<A>,
-    ) -> impl Iterator<Item = &'d Decl<A>> + 's {
+    pub fn iter_parents<'s>(&'s self, decl: &'d Decl) -> impl Iterator<Item = &'d Decl> + 's {
         std::iter::successors(self.get_parent(decl), |decl| self.get_parent(decl))
     }
 
@@ -311,24 +256,21 @@
     /// including the current declaration.
     pub fn iter_parents_and_self<'s>(
         &'s self,
-        decl: &'d crate::ast::Decl<A>,
-    ) -> impl Iterator<Item = &'d Decl<A>> + 's {
+        decl: &'d Decl,
+    ) -> impl Iterator<Item = &'d Decl> + 's {
         std::iter::successors(Some(decl), |decl| self.get_parent(decl))
     }
 
     /// Iterate over the declaration and its parent's fields.
-    pub fn iter_fields<'s>(
-        &'s self,
-        decl: &'d crate::ast::Decl<A>,
-    ) -> impl Iterator<Item = &'d Field<A>> + 's {
+    pub fn iter_fields<'s>(&'s self, decl: &'d Decl) -> impl Iterator<Item = &'d Field> + 's {
         std::iter::successors(Some(decl), |decl| self.get_parent(decl)).flat_map(Decl::fields)
     }
 
     /// Iterate over the declaration parent's fields.
     pub fn iter_parent_fields<'s>(
         &'s self,
-        decl: &'d crate::ast::Decl<A>,
-    ) -> impl Iterator<Item = &'d crate::ast::Field<A>> + 's {
+        decl: &'d Decl,
+    ) -> impl Iterator<Item = &'d Field> + 's {
         std::iter::successors(self.get_parent(decl), |decl| self.get_parent(decl))
             .flat_map(Decl::fields)
     }
@@ -336,16 +278,13 @@
     /// Iterate over the declaration and its parent's constraints.
     pub fn iter_constraints<'s>(
         &'s self,
-        decl: &'d crate::ast::Decl<A>,
+        decl: &'d Decl,
     ) -> impl Iterator<Item = &'d Constraint> + 's {
         std::iter::successors(Some(decl), |decl| self.get_parent(decl)).flat_map(Decl::constraints)
     }
 
     /// Return the type declaration for the selected field, if applicable.
-    pub fn get_type_declaration(
-        &self,
-        field: &crate::ast::Field<A>,
-    ) -> Option<&'d crate::ast::Decl<A>> {
+    pub fn get_type_declaration(&self, field: &Field) -> Option<&'d Decl> {
         match &field.desc {
             FieldDesc::Checksum { .. }
             | FieldDesc::Padding { .. }
@@ -367,7 +306,7 @@
     }
 
     /// Test if the selected field is a bit-field.
-    pub fn is_bitfield(&self, field: &crate::ast::Field<A>) -> bool {
+    pub fn is_bitfield(&self, field: &Field) -> bool {
         match &field.desc {
             FieldDesc::Size { .. }
             | FieldDesc::Count { .. }
@@ -386,6 +325,173 @@
     }
 }
 
+impl Schema {
+    /// Check correct definition of packet sizes.
+    /// Annotate fields and declarations with the size in bits.
+    pub fn new(file: &File) -> Schema {
+        fn annotate_decl(schema: &mut Schema, scope: &HashMap<String, DeclKey>, decl: &Decl) {
+            // Compute the padding size for each field.
+            let mut padding = None;
+            for field in decl.fields().rev() {
+                schema.padded_size.insert(field.key, padding);
+                padding = match &field.desc {
+                    FieldDesc::Padding { size } => Some(8 * *size),
+                    _ => None,
+                };
+            }
+
+            let mut size = decl
+                .parent_id()
+                .and_then(|parent_id| scope.get(parent_id))
+                .map(|key| schema.decl_size(*key))
+                .unwrap_or(Size::Static(0));
+            let mut payload_size = Size::Static(0);
+
+            for field in decl.fields() {
+                // Compute the size of each declared fields.
+                let field_size = annotate_field(schema, scope, decl, field);
+
+                // Sum the size of the non payload fields to get the
+                // declaration size. Lookup the payload field size.
+                match &field.desc {
+                    FieldDesc::Payload { .. } | FieldDesc::Body { .. } => payload_size = field_size,
+                    _ => {
+                        size = size
+                            + match schema.padded_size.get(&field.key).unwrap() {
+                                Some(padding) => Size::Static(*padding),
+                                None => field_size,
+                            }
+                    }
+                }
+            }
+
+            // Save the declaration size.
+            let (size, payload_size) = match &decl.desc {
+                DeclDesc::Packet { .. } | DeclDesc::Struct { .. } | DeclDesc::Group { .. } => {
+                    (size, payload_size)
+                }
+                DeclDesc::Enum { width, .. }
+                | DeclDesc::Checksum { width, .. }
+                | DeclDesc::CustomField { width: Some(width), .. } => {
+                    (Size::Static(*width), Size::Static(0))
+                }
+                DeclDesc::CustomField { width: None, .. } => (Size::Dynamic, Size::Static(0)),
+                DeclDesc::Test { .. } => (Size::Static(0), Size::Static(0)),
+            };
+
+            schema.decl_size.insert(decl.key, size);
+            schema.payload_size.insert(decl.key, payload_size);
+        }
+
+        fn annotate_field(
+            schema: &mut Schema,
+            scope: &HashMap<String, DeclKey>,
+            decl: &Decl,
+            field: &Field,
+        ) -> Size {
+            let size = match &field.desc {
+                _ if field.cond.is_some() => Size::Dynamic,
+                FieldDesc::Checksum { .. } | FieldDesc::Padding { .. } => Size::Static(0),
+                FieldDesc::Size { width, .. }
+                | FieldDesc::Count { width, .. }
+                | FieldDesc::ElementSize { width, .. }
+                | FieldDesc::FixedScalar { width, .. }
+                | FieldDesc::Reserved { width }
+                | FieldDesc::Scalar { width, .. } => Size::Static(*width),
+                FieldDesc::Flag { .. } => Size::Static(1),
+                FieldDesc::Body | FieldDesc::Payload { .. } => {
+                    let has_payload_size = decl.fields().any(|field| match &field.desc {
+                        FieldDesc::Size { field_id, .. } => {
+                            field_id == "_body_" || field_id == "_payload_"
+                        }
+                        _ => false,
+                    });
+                    if has_payload_size {
+                        Size::Dynamic
+                    } else {
+                        Size::Unknown
+                    }
+                }
+                FieldDesc::Typedef { type_id, .. }
+                | FieldDesc::FixedEnum { enum_id: type_id, .. }
+                | FieldDesc::Group { group_id: type_id, .. } => {
+                    let type_key = scope.get(type_id).unwrap();
+                    schema.total_size(*type_key)
+                }
+                FieldDesc::Array { width: Some(width), size: Some(size), .. } => {
+                    Size::Static(*size * *width)
+                }
+                FieldDesc::Array {
+                    width: None, size: Some(size), type_id: Some(type_id), ..
+                } => {
+                    let type_key = scope.get(type_id).unwrap();
+                    schema.total_size(*type_key) * *size
+                }
+                FieldDesc::Array { id, size: None, .. } => {
+                    // The element does not matter when the size of the array is
+                    // not static. The array size depends on there being a count
+                    // or size field or not.
+                    let has_array_size = decl.fields().any(|field| match &field.desc {
+                        FieldDesc::Size { field_id, .. } | FieldDesc::Count { field_id, .. } => {
+                            field_id == id
+                        }
+                        _ => false,
+                    });
+                    if has_array_size {
+                        Size::Dynamic
+                    } else {
+                        Size::Unknown
+                    }
+                }
+                FieldDesc::Array { .. } => unreachable!(),
+            };
+
+            schema.field_size.insert(field.key, size);
+            size
+        }
+
+        let mut scope = HashMap::new();
+        for decl in &file.declarations {
+            if let Some(id) = decl.id() {
+                scope.insert(id.to_owned(), decl.key);
+            }
+        }
+
+        let mut schema = Schema {
+            field_size: Default::default(),
+            decl_size: Default::default(),
+            padded_size: Default::default(),
+            payload_size: Default::default(),
+        };
+
+        for decl in &file.declarations {
+            annotate_decl(&mut schema, &scope, decl);
+        }
+
+        schema
+    }
+
+    pub fn field_size(&self, key: FieldKey) -> Size {
+        *self.field_size.get(&key).unwrap()
+    }
+
+    pub fn decl_size(&self, key: DeclKey) -> Size {
+        *self.decl_size.get(&key).unwrap()
+    }
+
+    pub fn padded_size(&self, key: FieldKey) -> Option<usize> {
+        *self.padded_size.get(&key).unwrap()
+    }
+
+    pub fn payload_size(&self, key: DeclKey) -> Size {
+        *self.payload_size.get(&key).unwrap()
+    }
+
+    pub fn total_size(&self, key: DeclKey) -> Size {
+        self.decl_size(key) + self.payload_size(key)
+    }
+}
+
 /// Return the bit-width of a scalar value.
 fn bit_width(value: usize) -> usize {
     usize::BITS as usize - value.leading_zeros() as usize
@@ -411,10 +517,7 @@
 ///      - undeclared test identifier
 ///      - invalid test identifier
 ///      - recursive declaration
-fn check_decl_identifiers(
-    file: &parser_ast::File,
-    scope: &Scope<parser_ast::Annotation>,
-) -> Result<(), Diagnostics> {
+fn check_decl_identifiers(file: &File, scope: &Scope) -> Result<(), Diagnostics> {
     enum Mark {
         Temporary,
         Permanent,
@@ -425,9 +528,9 @@
     }
 
     fn bfs<'d>(
-        decl: &'d parser_ast::Decl,
+        decl: &'d Decl,
         context: &mut Context<'d>,
-        scope: &Scope<'d, parser_ast::Annotation>,
+        scope: &Scope<'d>,
         diagnostics: &mut Diagnostics,
     ) {
         let decl_id = decl.id().unwrap();
@@ -586,7 +689,7 @@
 /// Check field identifiers.
 /// Raises error diagnostics for the following cases:
 ///      - duplicate field identifier
-fn check_field_identifiers(file: &parser_ast::File) -> Result<(), Diagnostics> {
+fn check_field_identifiers(file: &File) -> Result<(), Diagnostics> {
     let mut diagnostics: Diagnostics = Default::default();
     for decl in &file.declarations {
         let mut local_scope = HashMap::new();
@@ -620,7 +723,7 @@
 /// Raises error diagnostics for the following cases:
 ///      - duplicate tag identifier
 ///      - duplicate tag value
-fn check_enum_declarations(file: &parser_ast::File) -> Result<(), Diagnostics> {
+fn check_enum_declarations(file: &File) -> Result<(), Diagnostics> {
     // Return the inclusive range with bounds correctly ordered.
     // The analyzer will raise an error if the bounds are incorrectly ordered, but this
     // will enable additional checks.
@@ -855,8 +958,8 @@
 /// Helper function for validating one constraint.
 fn check_constraint(
     constraint: &Constraint,
-    decl: &parser_ast::Decl,
-    scope: &Scope<parser_ast::Annotation>,
+    decl: &Decl,
+    scope: &Scope,
     diagnostics: &mut Diagnostics,
 ) {
     match scope.iter_fields(decl).find(|field| field.id() == Some(&constraint.id)) {
@@ -985,8 +1088,8 @@
 /// Helper function for validating a list of constraints.
 fn check_constraints_list<'d>(
     constraints: &'d [Constraint],
-    parent_decl: &parser_ast::Decl,
-    scope: &Scope<parser_ast::Annotation>,
+    parent_decl: &Decl,
+    scope: &Scope,
     mut constraints_by_id: HashMap<String, &'d Constraint>,
     diagnostics: &mut Diagnostics,
 ) {
@@ -1018,10 +1121,7 @@
 ///      - invalid constraint enum value (bad type)
 ///      - invalid constraint enum value (undeclared tag)
 ///      - duplicate constraint
-fn check_decl_constraints(
-    file: &parser_ast::File,
-    scope: &Scope<parser_ast::Annotation>,
-) -> Result<(), Diagnostics> {
+fn check_decl_constraints(file: &File, scope: &Scope) -> Result<(), Diagnostics> {
     let mut diagnostics: Diagnostics = Default::default();
     for decl in &file.declarations {
         // Check constraints for packet inheritance.
@@ -1060,10 +1160,7 @@
 ///      - invalid constraint enum value (bad type)
 ///      - invalid constraint enum value (undeclared tag)
 ///      - duplicate constraint
-fn check_group_constraints(
-    file: &parser_ast::File,
-    scope: &Scope<parser_ast::Annotation>,
-) -> Result<(), Diagnostics> {
+fn check_group_constraints(file: &File, scope: &Scope) -> Result<(), Diagnostics> {
     let mut diagnostics: Diagnostics = Default::default();
     for decl in &file.declarations {
         // Check constraints for group inlining.
@@ -1095,7 +1192,7 @@
 ///      - undeclared elementsize identifier
 ///      - invalid elementsize identifier
 ///      - duplicate elementsize field
-fn check_size_fields(file: &parser_ast::File) -> Result<(), Diagnostics> {
+fn check_size_fields(file: &File) -> Result<(), Diagnostics> {
     let mut diagnostics: Diagnostics = Default::default();
     for decl in &file.declarations {
         let mut size_for_id = HashMap::new();
@@ -1223,10 +1320,7 @@
 ///      - undeclared enum identifier
 ///      - invalid enum identifier
 ///      - undeclared tag identifier
-fn check_fixed_fields(
-    file: &parser_ast::File,
-    scope: &Scope<parser_ast::Annotation>,
-) -> Result<(), Diagnostics> {
+fn check_fixed_fields(file: &File, scope: &Scope) -> Result<(), Diagnostics> {
     let mut diagnostics: Diagnostics = Default::default();
     for decl in &file.declarations {
         for field in decl.fields() {
@@ -1291,16 +1385,16 @@
 ///      - duplicate body field
 ///      - duplicate body field size
 ///      - missing payload field
-fn check_payload_fields(file: &parser_ast::File) -> Result<(), Diagnostics> {
+fn check_payload_fields(file: &File) -> Result<(), Diagnostics> {
     // Check whether the declaration requires a payload field.
     // The payload is required if any child packets declares fields.
-    fn requires_payload(file: &parser_ast::File, decl: &parser_ast::Decl) -> bool {
+    fn requires_payload(file: &File, decl: &Decl) -> bool {
         file.iter_children(decl).any(|child| child.fields().next().is_some())
     }
 
     let mut diagnostics: Diagnostics = Default::default();
     for decl in &file.declarations {
-        let mut payload: Option<&parser_ast::Field> = None;
+        let mut payload: Option<&Field> = None;
         for field in decl.fields() {
             match &field.desc {
                 FieldDesc::Payload { .. } | FieldDesc::Body { .. } => {
@@ -1345,7 +1439,7 @@
 /// Check array fields.
 /// Raises error diagnostics for the following cases:
 ///      - redundant array field size
-fn check_array_fields(file: &parser_ast::File) -> Result<(), Diagnostics> {
+fn check_array_fields(file: &File) -> Result<(), Diagnostics> {
     let mut diagnostics: Diagnostics = Default::default();
     for decl in &file.declarations {
         for field in decl.fields() {
@@ -1379,7 +1473,7 @@
 /// Check padding fields.
 /// Raises error diagnostics for the following cases:
 ///      - padding field not following an array field
-fn check_padding_fields(file: &parser_ast::File) -> Result<(), Diagnostics> {
+fn check_padding_fields(file: &File) -> Result<(), Diagnostics> {
     let mut diagnostics: Diagnostics = Default::default();
     for decl in &file.declarations {
         let mut previous_is_array = false;
@@ -1405,10 +1499,7 @@
 ///      - checksum field precedes checksum start
 ///      - undeclared checksum field
 ///      - invalid checksum field
-fn check_checksum_fields(
-    _file: &parser_ast::File,
-    _scope: &Scope<parser_ast::Annotation>,
-) -> Result<(), Diagnostics> {
+fn check_checksum_fields(_file: &File, _scope: &Scope) -> Result<(), Diagnostics> {
     // TODO
     Ok(())
 }
@@ -1419,11 +1510,11 @@
 ///      - invalid constraint identifier
 ///      - invalid constraint scalar value (bad type)
 ///      - invalid constraint scalar value (overflow)
-fn check_optional_fields(file: &parser_ast::File) -> Result<(), Diagnostics> {
+fn check_optional_fields(file: &File) -> Result<(), Diagnostics> {
     let mut diagnostics: Diagnostics = Default::default();
     for decl in &file.declarations {
-        let mut local_scope: HashMap<String, &parser_ast::Field> = HashMap::new();
-        let mut condition_ids: HashMap<String, &parser_ast::Field> = HashMap::new();
+        let mut local_scope: HashMap<String, &Field> = HashMap::new();
+        let mut condition_ids: HashMap<String, &Field> = HashMap::new();
         for field in decl.fields() {
             if let Some(ref cond) = field.cond {
                 match &field.desc {
@@ -1527,167 +1618,13 @@
     diagnostics.err_or(())
 }
 
-/// Check correct definition of packet sizes.
-/// Annotate fields and declarations with the size in bits.
-fn compute_field_sizes(file: &parser_ast::File) -> ast::File {
-    fn annotate_decl(
-        decl: &parser_ast::Decl,
-        scope: &HashMap<String, ast::DeclAnnotation>,
-    ) -> ast::Decl {
-        // Annotate the declaration fields.
-        // Add the padding information to the fields in the same pass.
-        let mut decl = decl.annotate(Default::default(), |fields| {
-            let mut fields: Vec<_> =
-                fields.iter().map(|field| annotate_field(decl, field, scope)).collect();
-            let mut padding = None;
-            for field in fields.iter_mut().rev() {
-                field.annot.padded_size = padding;
-                padding = match &field.desc {
-                    FieldDesc::Padding { size } => Some(*size),
-                    _ => None,
-                };
-            }
-            fields
-        });
-
-        // Compute the declaration annotation.
-        decl.annot = match &decl.desc {
-            DeclDesc::Packet { fields, .. }
-            | DeclDesc::Struct { fields, .. }
-            | DeclDesc::Group { fields, .. } => {
-                let mut size = decl
-                    .parent_id()
-                    .and_then(|parent_id| scope.get(parent_id))
-                    .map(|annot| annot.size)
-                    .unwrap_or(ast::Size::Static(0));
-                let mut payload_size = ast::Size::Static(0);
-                for field in fields {
-                    match &field.desc {
-                        FieldDesc::Payload { .. } | FieldDesc::Body { .. } => {
-                            payload_size = field.annot.size
-                        }
-                        _ => {
-                            size = size
-                                + match field.annot.padded_size {
-                                    Some(padding) => ast::Size::Static(8 * padding),
-                                    None => field.annot.size,
-                                }
-                        }
-                    }
-                }
-                ast::DeclAnnotation { size, payload_size }
-            }
-            DeclDesc::Enum { width, .. }
-            | DeclDesc::Checksum { width, .. }
-            | DeclDesc::CustomField { width: Some(width), .. } => ast::DeclAnnotation {
-                size: ast::Size::Static(*width),
-                payload_size: ast::Size::Static(0),
-            },
-            DeclDesc::CustomField { width: None, .. } => {
-                ast::DeclAnnotation { size: ast::Size::Dynamic, payload_size: ast::Size::Static(0) }
-            }
-            DeclDesc::Test { .. } => ast::DeclAnnotation {
-                size: ast::Size::Static(0),
-                payload_size: ast::Size::Static(0),
-            },
-        };
-        decl
-    }
-
-    fn annotate_field(
-        decl: &parser_ast::Decl,
-        field: &parser_ast::Field,
-        scope: &HashMap<String, ast::DeclAnnotation>,
-    ) -> ast::Field {
-        field.annotate(match &field.desc {
-            _ if field.cond.is_some() => ast::FieldAnnotation::new(ast::Size::Dynamic),
-            FieldDesc::Checksum { .. } | FieldDesc::Padding { .. } => {
-                ast::FieldAnnotation::new(ast::Size::Static(0))
-            }
-            FieldDesc::Size { width, .. }
-            | FieldDesc::Count { width, .. }
-            | FieldDesc::ElementSize { width, .. }
-            | FieldDesc::FixedScalar { width, .. }
-            | FieldDesc::Reserved { width }
-            | FieldDesc::Scalar { width, .. } => {
-                ast::FieldAnnotation::new(ast::Size::Static(*width))
-            }
-            FieldDesc::Flag { .. } => ast::FieldAnnotation::new(ast::Size::Static(1)),
-            FieldDesc::Body | FieldDesc::Payload { .. } => {
-                let has_payload_size = decl.fields().any(|field| match &field.desc {
-                    FieldDesc::Size { field_id, .. } => {
-                        field_id == "_body_" || field_id == "_payload_"
-                    }
-                    _ => false,
-                });
-                ast::FieldAnnotation::new(if has_payload_size {
-                    ast::Size::Dynamic
-                } else {
-                    ast::Size::Unknown
-                })
-            }
-            FieldDesc::Typedef { type_id, .. }
-            | FieldDesc::FixedEnum { enum_id: type_id, .. }
-            | FieldDesc::Group { group_id: type_id, .. } => {
-                let type_annot = scope.get(type_id).unwrap();
-                ast::FieldAnnotation::new(type_annot.size + type_annot.payload_size)
-            }
-            FieldDesc::Array { width: Some(width), size: Some(size), .. } => {
-                ast::FieldAnnotation::new(ast::Size::Static(*size * *width))
-            }
-            FieldDesc::Array { width: None, size: Some(size), type_id: Some(type_id), .. } => {
-                let type_annot = scope.get(type_id).unwrap();
-                ast::FieldAnnotation::new((type_annot.size + type_annot.payload_size) * *size)
-            }
-            FieldDesc::Array { id, size: None, .. } => {
-                // The element does not matter when the size of the array is
-                // not static. The array size depends on there being a count
-                // or size field or not.
-                let has_array_size = decl.fields().any(|field| match &field.desc {
-                    FieldDesc::Size { field_id, .. } | FieldDesc::Count { field_id, .. } => {
-                        field_id == id
-                    }
-                    _ => false,
-                });
-                ast::FieldAnnotation::new(if has_array_size {
-                    ast::Size::Dynamic
-                } else {
-                    ast::Size::Unknown
-                })
-            }
-            FieldDesc::Array { .. } => unreachable!(),
-        })
-    }
-
-    // Construct a scope mapping typedef identifiers to decl annotations.
-    let mut scope = HashMap::new();
-
-    // Annotate declarations.
-    let mut declarations = Vec::new();
-    for decl in file.declarations.iter() {
-        let decl = annotate_decl(decl, &scope);
-        if let Some(id) = decl.id() {
-            scope.insert(id.to_string(), decl.annot.clone());
-        }
-        declarations.push(decl);
-    }
-
-    File {
-        version: file.version.clone(),
-        file: file.file,
-        comments: file.comments.clone(),
-        endianness: file.endianness,
-        declarations,
-    }
-}
-
 /// Inline group fields and remove group declarations.
-fn inline_groups(file: &parser_ast::File) -> Result<parser_ast::File, Diagnostics> {
+fn inline_groups(file: &File) -> Result<File, Diagnostics> {
     fn inline_fields<'a>(
-        fields: impl Iterator<Item = &'a parser_ast::Field>,
-        groups: &HashMap<String, &parser_ast::Decl>,
+        fields: impl Iterator<Item = &'a Field>,
+        groups: &HashMap<String, &Decl>,
         constraints: &HashMap<String, Constraint>,
-    ) -> Vec<parser_ast::Field> {
+    ) -> Vec<Field> {
         fields
             .flat_map(|field| match &field.desc {
                 FieldDesc::Group { group_id, constraints: group_constraints } => {
@@ -1700,18 +1637,18 @@
                     inline_fields(groups.get(group_id).unwrap().fields(), groups, &constraints)
                 }
                 FieldDesc::Scalar { id, width } if constraints.contains_key(id) => {
-                    vec![parser_ast::Field {
+                    vec![Field {
                         desc: FieldDesc::FixedScalar {
                             width: *width,
                             value: constraints.get(id).unwrap().value.unwrap(),
                         },
                         loc: field.loc,
-                        annot: field.annot,
+                        key: field.key,
                         cond: field.cond.clone(),
                     }]
                 }
                 FieldDesc::Typedef { id, type_id, .. } if constraints.contains_key(id) => {
-                    vec![parser_ast::Field {
+                    vec![Field {
                         desc: FieldDesc::FixedEnum {
                             enum_id: type_id.clone(),
                             tag_id: constraints
@@ -1720,7 +1657,7 @@
                                 .unwrap(),
                         },
                         loc: field.loc,
-                        annot: field.annot,
+                        key: field.key,
                         cond: field.cond.clone(),
                     }]
                 }
@@ -1740,7 +1677,7 @@
         .declarations
         .iter()
         .filter_map(|decl| match &decl.desc {
-            DeclDesc::Packet { fields, id, parent_id, constraints } => Some(parser_ast::Decl {
+            DeclDesc::Packet { fields, id, parent_id, constraints } => Some(Decl {
                 desc: DeclDesc::Packet {
                     fields: inline_fields(fields.iter(), &groups, &HashMap::new()),
                     id: id.clone(),
@@ -1748,9 +1685,9 @@
                     constraints: constraints.clone(),
                 },
                 loc: decl.loc,
-                annot: decl.annot,
+                key: decl.key,
             }),
-            DeclDesc::Struct { fields, id, parent_id, constraints } => Some(parser_ast::Decl {
+            DeclDesc::Struct { fields, id, parent_id, constraints } => Some(Decl {
                 desc: DeclDesc::Struct {
                     fields: inline_fields(fields.iter(), &groups, &HashMap::new()),
                     id: id.clone(),
@@ -1758,7 +1695,7 @@
                     constraints: constraints.clone(),
                 },
                 loc: decl.loc,
-                annot: decl.annot,
+                key: decl.key,
             }),
             DeclDesc::Group { .. } => None,
             _ => Some(decl.clone()),
@@ -1767,17 +1704,18 @@
 
     Ok(File {
         declarations,
-
         version: file.version.clone(),
         file: file.file,
         comments: file.comments.clone(),
         endianness: file.endianness,
+        // Keys are reused for inlined fields.
+        max_key: file.max_key,
     })
 }
 
 /// Replace Scalar fields used as condition for optional fields by the more
 /// specific Flag construct.
-fn desugar_flags(file: &mut parser_ast::File) {
+fn desugar_flags(file: &mut File) {
     for decl in &mut file.declarations {
         match &mut decl.desc {
             DeclDesc::Packet { fields, .. }
@@ -1813,7 +1751,7 @@
 
 /// Analyzer entry point, produces a new AST with annotations resulting
 /// from the analysis.
-pub fn analyze(file: &parser_ast::File) -> Result<ast::File, Diagnostics> {
+pub fn analyze(file: &File) -> Result<File, Diagnostics> {
     let scope = Scope::new(file)?;
     check_decl_identifiers(file, &scope)?;
     check_field_identifiers(file)?;
@@ -1830,13 +1768,13 @@
     desugar_flags(&mut file);
     let scope = Scope::new(&file)?;
     check_decl_constraints(&file, &scope)?;
-    Ok(compute_field_sizes(&file))
+    Ok(file)
 }
 
 #[cfg(test)]
 mod test {
     use crate::analyzer;
-    use crate::ast::*;
+    use crate::ast;
     use crate::parser::parse_inline;
     use codespan_reporting::term::termcolor;
 
@@ -1844,7 +1782,7 @@
 
     macro_rules! raises {
         ($code:ident, $text:literal) => {{
-            let mut db = SourceDatabase::new();
+            let mut db = ast::SourceDatabase::new();
             let file = parse_inline(&mut db, "stdin", $text.to_owned()).expect("parsing failure");
             let result = analyzer::analyze(&file);
             assert!(matches!(result, Err(_)));
@@ -1859,7 +1797,7 @@
 
     macro_rules! valid {
         ($text:literal) => {{
-            let mut db = SourceDatabase::new();
+            let mut db = ast::SourceDatabase::new();
             let file = parse_inline(&mut db, "stdin", $text.to_owned()).expect("parsing failure");
             assert!(analyzer::analyze(&file).is_ok());
         }};
@@ -3112,7 +3050,7 @@
         );
     }
 
-    use analyzer::ast::Size;
+    use analyzer::Size;
     use Size::*;
 
     #[derive(Debug, PartialEq, Eq)]
@@ -3123,15 +3061,16 @@
     }
 
     fn annotations(text: &str) -> Vec<Annotations> {
-        let mut db = SourceDatabase::new();
+        let mut db = ast::SourceDatabase::new();
         let file = parse_inline(&mut db, "stdin", text.to_owned()).expect("parsing failure");
         let file = analyzer::analyze(&file).expect("analyzer failure");
+        let schema = analyzer::Schema::new(&file);
         file.declarations
             .iter()
             .map(|decl| Annotations {
-                size: decl.annot.size,
-                payload_size: decl.annot.payload_size,
-                fields: decl.fields().map(|field| field.annot.size).collect(),
+                size: schema.decl_size(decl.key),
+                payload_size: schema.payload_size(decl.key),
+                fields: decl.fields().map(|field| schema.field_size(field.key)).collect(),
             })
             .collect()
     }
@@ -3626,8 +3565,8 @@
         );
     }
 
-    fn desugar(text: &str) -> analyzer::ast::File {
-        let mut db = SourceDatabase::new();
+    fn desugar(text: &str) -> analyzer::File {
+        let mut db = ast::SourceDatabase::new();
         let file = parse_inline(&mut db, "stdin", text.to_owned()).expect("parsing failure");
         analyzer::analyze(&file).expect("analyzer failure")
     }
diff --git a/src/ast.rs b/src/ast.rs
index 20d8bb8..e545c5e 100644
--- a/src/ast.rs
+++ b/src/ast.rs
@@ -43,11 +43,6 @@
     pub end: SourceLocation,
 }
 
-pub trait Annotation: fmt::Debug + Serialize {
-    type FieldAnnotation: Default + fmt::Debug + Clone;
-    type DeclAnnotation: Default + fmt::Debug + Clone;
-}
-
 #[derive(Debug, Serialize, Clone)]
 #[serde(tag = "kind", rename = "comment")]
 pub struct Comment {
@@ -110,6 +105,9 @@
     pub tag_id: Option<String>,
 }
 
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct FieldKey(pub usize);
+
 #[derive(Debug, Serialize, Clone, PartialEq, Eq)]
 #[serde(tag = "kind")]
 pub enum FieldDesc {
@@ -154,10 +152,12 @@
 }
 
 #[derive(Debug, Serialize, Clone)]
-pub struct Field<A: Annotation> {
+pub struct Field {
     pub loc: SourceRange,
+    /// Unique identifier used to refer to the AST node in
+    /// compilation environments.
     #[serde(skip_serializing)]
-    pub annot: A::FieldAnnotation,
+    pub key: FieldKey,
     #[serde(flatten)]
     pub desc: FieldDesc,
     pub cond: Option<Constraint>,
@@ -170,9 +170,12 @@
     pub input: String,
 }
 
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct DeclKey(pub usize);
+
 #[derive(Debug, Serialize, Clone, PartialEq, Eq)]
 #[serde(tag = "kind")]
-pub enum DeclDesc<A: Annotation> {
+pub enum DeclDesc {
     #[serde(rename = "checksum_declaration")]
     Checksum { id: String, function: String, width: usize },
     #[serde(rename = "custom_field_declaration")]
@@ -183,38 +186,42 @@
     Packet {
         id: String,
         constraints: Vec<Constraint>,
-        fields: Vec<Field<A>>,
+        fields: Vec<Field>,
         parent_id: Option<String>,
     },
     #[serde(rename = "struct_declaration")]
     Struct {
         id: String,
         constraints: Vec<Constraint>,
-        fields: Vec<Field<A>>,
+        fields: Vec<Field>,
         parent_id: Option<String>,
     },
     #[serde(rename = "group_declaration")]
-    Group { id: String, fields: Vec<Field<A>> },
+    Group { id: String, fields: Vec<Field> },
     #[serde(rename = "test_declaration")]
     Test { type_id: String, test_cases: Vec<TestCase> },
 }
 
 #[derive(Debug, Serialize, Clone)]
-pub struct Decl<A: Annotation> {
+pub struct Decl {
     pub loc: SourceRange,
+    /// Unique identifier used to refer to the AST node in
+    /// compilation environments.
     #[serde(skip_serializing)]
-    pub annot: A::DeclAnnotation,
+    pub key: DeclKey,
     #[serde(flatten)]
-    pub desc: DeclDesc<A>,
+    pub desc: DeclDesc,
 }
 
 #[derive(Debug, Serialize, Clone)]
-pub struct File<A: Annotation> {
+pub struct File {
     pub version: String,
     pub file: FileId,
     pub comments: Vec<Comment>,
     pub endianness: Endianness,
-    pub declarations: Vec<Decl<A>>,
+    pub declarations: Vec<Decl>,
+    #[serde(skip_serializing)]
+    pub max_key: usize,
 }
 
 impl SourceLocation {
@@ -350,8 +357,8 @@
     }
 }
 
-impl<A: Annotation + PartialEq> Eq for File<A> {}
-impl<A: Annotation + PartialEq> PartialEq for File<A> {
+impl Eq for File {}
+impl PartialEq for File {
     fn eq(&self, other: &Self) -> bool {
         // Implement structural equality, leave out comments and PDL
         // version information.
@@ -359,8 +366,8 @@
     }
 }
 
-impl<A: Annotation> File<A> {
-    pub fn new(file: FileId) -> File<A> {
+impl File {
+    pub fn new(file: FileId) -> File {
         File {
             version: "1,0".to_owned(),
             comments: vec![],
@@ -372,71 +379,27 @@
             },
             declarations: vec![],
             file,
+            max_key: 0,
         }
     }
 
     /// Iterate over the children of the selected declaration.
     /// /!\ This method is unsafe to use if the file contains cyclic
     /// declarations, use with caution.
-    pub fn iter_children<'d>(&'d self, decl: &'d Decl<A>) -> impl Iterator<Item = &'d Decl<A>> {
+    pub fn iter_children<'d>(&'d self, decl: &'d Decl) -> impl Iterator<Item = &'d Decl> {
         self.declarations.iter().filter(|other_decl| other_decl.parent_id() == decl.id())
     }
 }
 
-impl<A: Annotation + PartialEq> Eq for Decl<A> {}
-impl<A: Annotation + PartialEq> PartialEq for Decl<A> {
+impl Eq for Decl {}
+impl PartialEq for Decl {
     fn eq(&self, other: &Self) -> bool {
-        // Implement structural equality, leave out loc and annot.
+        // Implement structural equality, leave out loc and key.
         self.desc == other.desc
     }
 }
 
-impl<A: Annotation> Decl<A> {
-    pub fn new(loc: SourceRange, desc: DeclDesc<A>) -> Decl<A> {
-        Decl { loc, annot: Default::default(), desc }
-    }
-
-    pub fn annotate<F, B: Annotation>(
-        &self,
-        annot: B::DeclAnnotation,
-        annotate_fields: F,
-    ) -> Decl<B>
-    where
-        F: FnOnce(&[Field<A>]) -> Vec<Field<B>>,
-    {
-        let desc = match &self.desc {
-            DeclDesc::Checksum { id, function, width } => {
-                DeclDesc::Checksum { id: id.clone(), function: function.clone(), width: *width }
-            }
-            DeclDesc::CustomField { id, width, function } => {
-                DeclDesc::CustomField { id: id.clone(), width: *width, function: function.clone() }
-            }
-            DeclDesc::Enum { id, tags, width } => {
-                DeclDesc::Enum { id: id.clone(), tags: tags.clone(), width: *width }
-            }
-
-            DeclDesc::Test { type_id, test_cases } => {
-                DeclDesc::Test { type_id: type_id.clone(), test_cases: test_cases.clone() }
-            }
-            DeclDesc::Packet { id, constraints, parent_id, fields } => DeclDesc::Packet {
-                id: id.clone(),
-                constraints: constraints.clone(),
-                parent_id: parent_id.clone(),
-                fields: annotate_fields(fields),
-            },
-            DeclDesc::Struct { id, constraints, parent_id, fields } => DeclDesc::Struct {
-                id: id.clone(),
-                constraints: constraints.clone(),
-                parent_id: parent_id.clone(),
-                fields: annotate_fields(fields),
-            },
-            DeclDesc::Group { id, fields } => {
-                DeclDesc::Group { id: id.clone(), fields: annotate_fields(fields) }
-            }
-        };
-        Decl { loc: self.loc, desc, annot }
-    }
-
+impl Decl {
     pub fn id(&self) -> Option<&str> {
         match &self.desc {
             DeclDesc::Test { .. } => None,
@@ -467,7 +430,7 @@
         }
     }
 
-    pub fn fields(&self) -> std::slice::Iter<'_, Field<A>> {
+    pub fn fields(&self) -> std::slice::Iter<'_, Field> {
         match &self.desc {
             DeclDesc::Packet { fields, .. }
             | DeclDesc::Struct { fields, .. }
@@ -478,14 +441,14 @@
 
     /// Return the reference to the payload or body field in a declaration,
     /// if present.
-    pub fn payload(&self) -> Option<&Field<A>> {
+    pub fn payload(&self) -> Option<&Field> {
         self.fields()
             .find(|field| matches!(&field.desc, FieldDesc::Payload { .. } | FieldDesc::Body { .. }))
     }
 
     /// Return the reference to the payload or body size field in a declaration,
     /// if present.
-    pub fn payload_size(&self) -> Option<&Field<A>> {
+    pub fn payload_size(&self) -> Option<&Field> {
         self.fields().find(|field| match &field.desc {
             FieldDesc::Size { field_id, .. } => field_id == "_payload_" || field_id == "_body_",
             _ => false,
@@ -494,7 +457,7 @@
 
     /// Return the reference to the array size or count field in a declaration,
     /// if present.
-    pub fn array_size(&self, id: &str) -> Option<&Field<A>> {
+    pub fn array_size(&self, id: &str) -> Option<&Field> {
         self.fields().find(|field| match &field.desc {
             FieldDesc::Size { field_id, .. } | FieldDesc::Count { field_id, .. } => field_id == id,
             _ => false,
@@ -514,19 +477,15 @@
     }
 }
 
-impl<A: Annotation> Eq for Field<A> {}
-impl<A: Annotation> PartialEq for Field<A> {
+impl Eq for Field {}
+impl PartialEq for Field {
     fn eq(&self, other: &Self) -> bool {
         // Implement structural equality, leave out loc and annot.
         self.desc == other.desc
     }
 }
 
-impl<A: Annotation> Field<A> {
-    pub fn annotate<B: Annotation>(&self, annot: B::FieldAnnotation) -> Field<B> {
-        Field { loc: self.loc, annot, cond: self.cond.clone(), desc: self.desc.clone() }
-    }
-
+impl Field {
     pub fn id(&self) -> Option<&str> {
         match &self.desc {
             FieldDesc::Checksum { .. }
diff --git a/src/backends.rs b/src/backends.rs
index a80f1f9..79058fa 100644
--- a/src/backends.rs
+++ b/src/backends.rs
@@ -17,4 +17,5 @@
 pub mod intermediate;
 pub mod json;
 pub mod rust;
+pub mod rust_legacy;
 pub mod rust_no_allocation;
diff --git a/src/backends/intermediate.rs b/src/backends/intermediate.rs
index 4c92ae0..cdae0f1 100644
--- a/src/backends/intermediate.rs
+++ b/src/backends/intermediate.rs
@@ -15,7 +15,6 @@
 use std::collections::{btree_map::Entry, BTreeMap, HashMap};
 
 use crate::ast;
-use crate::parser;
 
 pub struct Schema<'a> {
     pub packets_and_structs: HashMap<&'a str, PacketOrStruct<'a>>,
@@ -98,7 +97,7 @@
     Alias(ComputedOffsetId<'a>),
 }
 
-pub fn generate(file: &parser::ast::File) -> Result<Schema, String> {
+pub fn generate(file: &ast::File) -> Result<Schema, String> {
     let mut schema = Schema { packets_and_structs: HashMap::new(), enums: HashMap::new() };
     match file.endianness.value {
         ast::EndiannessValue::LittleEndian => {}
@@ -112,7 +111,7 @@
     Ok(schema)
 }
 
-fn process_decl<'a>(schema: &mut Schema<'a>, decl: &'a parser::ast::Decl) {
+fn process_decl<'a>(schema: &mut Schema<'a>, decl: &'a ast::Decl) {
     match &decl.desc {
         ast::DeclDesc::Enum { id, tags, width, .. } => process_enum(schema, id, tags, *width),
         ast::DeclDesc::Packet { id, fields, .. } | ast::DeclDesc::Struct { id, fields, .. } => {
@@ -135,18 +134,11 @@
     );
 }
 
-fn process_packet_or_struct<'a>(
-    schema: &mut Schema<'a>,
-    id: &'a str,
-    fields: &'a [parser::ast::Field],
-) {
+fn process_packet_or_struct<'a>(schema: &mut Schema<'a>, id: &'a str, fields: &'a [ast::Field]) {
     schema.packets_and_structs.insert(id, compute_getters(schema, fields));
 }
 
-fn compute_getters<'a>(
-    schema: &Schema<'a>,
-    fields: &'a [parser::ast::Field],
-) -> PacketOrStruct<'a> {
+fn compute_getters<'a>(schema: &Schema<'a>, fields: &'a [ast::Field]) -> PacketOrStruct<'a> {
     let mut prev_pos_id = None;
     let mut curr_pos_id = ComputedOffsetId::HeaderStart;
     let mut computed_values = BTreeMap::new();
diff --git a/src/backends/json.rs b/src/backends/json.rs
index 526b29e..7bd6e4f 100644
--- a/src/backends/json.rs
+++ b/src/backends/json.rs
@@ -14,10 +14,10 @@
 
 //! Json compiler backend.
 
-use crate::parser;
+use crate::ast;
 
 /// Turn the AST into a JSON representation.
-pub fn generate(file: &parser::ast::File) -> Result<String, String> {
+pub fn generate(file: &ast::File) -> Result<String, String> {
     serde_json::to_string_pretty(&file)
         .map_err(|err| format!("could not JSON serialize grammar: {err}"))
 }
diff --git a/src/backends/rust/mod.rs b/src/backends/rust/mod.rs
new file mode 100644
index 0000000..0e57eb8
--- /dev/null
+++ b/src/backends/rust/mod.rs
@@ -0,0 +1,1723 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Rust compiler backend.
+
+use crate::{analyzer, ast};
+use quote::{format_ident, quote};
+use std::collections::BTreeSet;
+use std::collections::HashMap;
+use std::path::Path;
+use syn::LitInt;
+
+mod parser;
+mod preamble;
+mod serializer;
+pub mod test;
+mod types;
+
+pub use heck::ToUpperCamelCase;
+use parser::FieldParser;
+
+pub trait ToIdent {
+    /// Generate a sanitized rust identifier.
+    /// Rust specific keywords are renamed for validity.
+    fn to_ident(self) -> proc_macro2::Ident;
+}
+
+impl ToIdent for &'_ str {
+    fn to_ident(self) -> proc_macro2::Ident {
+        match self {
+            "as" | "break" | "const" | "continue" | "crate" | "else" | "enum" | "extern"
+            | "false" | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" | "match" | "mod"
+            | "move" | "mut" | "pub" | "ref" | "return" | "self" | "Self" | "static" | "struct"
+            | "super" | "trait" | "true" | "type" | "unsafe" | "use" | "where" | "while"
+            | "async" | "await" | "dyn" | "abstract" | "become" | "box" | "do" | "final"
+            | "macro" | "override" | "priv" | "typeof" | "unsized" | "virtual" | "yield"
+            | "try" => format_ident!("r#{}", self),
+            _ => format_ident!("{}", self),
+        }
+    }
+}
+
+/// Generate a bit-mask which masks out `n` least significant bits.
+///
+/// Literal integers in Rust default to the `i32` type. For this
+/// reason, if `n` is larger than 31, a suffix is added to the
+/// `LitInt` returned. This should either be `u64` or `usize`
+/// depending on where the result is used.
+pub fn mask_bits(n: usize, suffix: &str) -> syn::LitInt {
+    let suffix = if n > 31 { format!("_{suffix}") } else { String::new() };
+    // Format the hex digits as 0x1111_2222_3333_usize.
+    let hex_digits = format!("{:x}", (1u64 << n) - 1)
+        .as_bytes()
+        .rchunks(4)
+        .rev()
+        .map(|chunk| std::str::from_utf8(chunk).unwrap())
+        .collect::<Vec<&str>>()
+        .join("_");
+    syn::parse_str::<syn::LitInt>(&format!("0x{hex_digits}{suffix}")).unwrap()
+}
+
+/// Return the list of fields that will appear in the generated
+/// rust structs (<Packet> and <Packet>Builder).
+///  - must be a named field
+///  - must not be a flag
+///  - must not appear in the packet constraints.
+/// The fields are presented in declaration order, with ancestor
+/// fields declared first.
+/// The payload field _ if declared _ is handled separately.
+fn packet_data_fields<'a>(
+    scope: &'a analyzer::Scope<'a>,
+    decl: &'a ast::Decl,
+) -> Vec<&'a ast::Field> {
+    let all_constraints = HashMap::<String, _>::from_iter(
+        scope.iter_constraints(decl).map(|c| (c.id.to_string(), c)),
+    );
+
+    scope
+        .iter_fields(decl)
+        .filter(|f| f.id().is_some())
+        .filter(|f| !matches!(&f.desc, ast::FieldDesc::Flag { .. }))
+        .filter(|f| !all_constraints.contains_key(f.id().unwrap()))
+        .collect::<Vec<_>>()
+}
+
+/// Return the list of fields that have a constant value.
+/// The fields are presented in declaration order, with ancestor
+/// fields declared first.
+fn packet_constant_fields<'a>(
+    scope: &'a analyzer::Scope<'a>,
+    decl: &'a ast::Decl,
+) -> Vec<&'a ast::Field> {
+    let all_constraints = HashMap::<String, _>::from_iter(
+        scope.iter_constraints(decl).map(|c| (c.id.to_string(), c)),
+    );
+
+    scope
+        .iter_fields(decl)
+        .filter(|f| f.id().is_some())
+        .filter(|f| all_constraints.contains_key(f.id().unwrap()))
+        .collect::<Vec<_>>()
+}
+
+fn constraint_value(
+    fields: &[&'_ ast::Field],
+    constraint: &ast::Constraint,
+) -> proc_macro2::TokenStream {
+    match constraint {
+        ast::Constraint { value: Some(value), .. } => {
+            let value = proc_macro2::Literal::usize_unsuffixed(*value);
+            quote!(#value)
+        }
+        // TODO(mgeisler): include type_id in `ast::Constraint` and
+        // drop the packet_scope argument.
+        ast::Constraint { tag_id: Some(tag_id), .. } => {
+            let tag_id = format_ident!("{}", tag_id.to_upper_camel_case());
+            let type_id = fields
+                .iter()
+                .filter_map(|f| match &f.desc {
+                    ast::FieldDesc::Typedef { id, type_id } if id == &constraint.id => {
+                        Some(type_id.to_ident())
+                    }
+                    _ => None,
+                })
+                .next()
+                .unwrap();
+            quote!(#type_id::#tag_id)
+        }
+        _ => unreachable!("Invalid constraint: {constraint:?}"),
+    }
+}
+
+fn constraint_value_str(fields: &[&'_ ast::Field], constraint: &ast::Constraint) -> String {
+    match constraint {
+        ast::Constraint { value: Some(value), .. } => {
+            format!("{}", value)
+        }
+        ast::Constraint { tag_id: Some(tag_id), .. } => {
+            let tag_id = format_ident!("{}", tag_id.to_upper_camel_case());
+            let type_id = fields
+                .iter()
+                .filter_map(|f| match &f.desc {
+                    ast::FieldDesc::Typedef { id, type_id } if id == &constraint.id => {
+                        Some(type_id.to_ident())
+                    }
+                    _ => None,
+                })
+                .next()
+                .unwrap();
+            format!("{}::{}", type_id, tag_id)
+        }
+        _ => unreachable!("Invalid constraint: {constraint:?}"),
+    }
+}
+
+fn implements_copy(scope: &analyzer::Scope<'_>, field: &ast::Field) -> bool {
+    match &field.desc {
+        ast::FieldDesc::Scalar { .. } => true,
+        ast::FieldDesc::Typedef { type_id, .. } => match &scope.typedef[type_id].desc {
+            ast::DeclDesc::Enum { .. } | ast::DeclDesc::CustomField { .. } => true,
+            ast::DeclDesc::Struct { .. } => false,
+            desc => unreachable!("unexpected declaration: {desc:?}"),
+        },
+        ast::FieldDesc::Array { .. } => false,
+        _ => todo!(),
+    }
+}
+
+/// Generate code for a root packet declaration.
+///
+/// # Arguments
+/// * `endianness` - File endianness
+/// * `id` - Packet identifier.
+fn generate_root_packet_decl(
+    scope: &analyzer::Scope<'_>,
+    schema: &analyzer::Schema,
+    endianness: ast::EndiannessValue,
+    id: &str,
+) -> proc_macro2::TokenStream {
+    let decl = scope.typedef[id];
+    let name = id.to_ident();
+    let child_name = format_ident!("{id}Child");
+
+    // Return the list of fields that will appear in the generated
+    // rust structs (<Packet> and <Packet>Builder).
+    // The payload field _ if declared _ is handled separately.
+    let data_fields = packet_data_fields(scope, decl);
+    let data_field_ids = data_fields.iter().map(|f| f.id().unwrap().to_ident()).collect::<Vec<_>>();
+    let data_field_types = data_fields.iter().map(|f| types::rust_type(f)).collect::<Vec<_>>();
+    let data_field_borrows = data_fields
+        .iter()
+        .map(|f| {
+            if implements_copy(scope, f) {
+                quote! {}
+            } else {
+                quote! { & }
+            }
+        })
+        .collect::<Vec<_>>();
+    let payload_field = decl.payload().map(|_| quote! { pub payload: Vec<u8>, });
+    let payload_accessor =
+        decl.payload().map(|_| quote! { pub fn payload(&self) -> &[u8] { &self.payload } });
+
+    let parser_span = format_ident!("buf");
+    let mut field_parser = FieldParser::new(scope, schema, endianness, id, &parser_span);
+    for field in decl.fields() {
+        field_parser.add(field);
+    }
+
+    // For the implementation of decode_partial, sort the data field identifiers
+    // between parsed fields (extracted from the payload), and copied fields
+    // (copied from the parent).
+    let mut parsed_field_ids = vec![];
+    if decl.payload().is_some() {
+        parsed_field_ids.push(format_ident!("payload"));
+    }
+    for f in &data_fields {
+        let id = f.id().unwrap().to_ident();
+        parsed_field_ids.push(id);
+    }
+
+    let (encode_fields, encoded_len) =
+        serializer::encode(scope, schema, endianness, "buf".to_ident(), decl);
+
+    let encode = quote! {
+         fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+            #encode_fields
+            Ok(())
+        }
+    };
+
+    // Compute the encoded length of the packet.
+    let encoded_len = quote! {
+        fn encoded_len(&self) -> usize {
+            #encoded_len
+        }
+    };
+
+    // The implementation of decode for root packets contains the full
+    // parser implementation.
+    let decode = quote! {
+       fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+           #field_parser
+           Ok((Self { #( #parsed_field_ids, )* }, buf))
+       }
+    };
+
+    // Provide the implementation of the enum listing child declarations of the
+    // current declaration. This enum is only provided for declarations that
+    // have child packets.
+    let children_decl = scope.iter_children(decl).collect::<Vec<_>>();
+    let child_struct = (!children_decl.is_empty()).then(|| {
+        let children_ids = children_decl.iter().map(|decl| decl.id().unwrap().to_ident());
+        quote! {
+            #[derive(Debug, Clone, PartialEq, Eq)]
+            #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+            pub enum #child_name {
+                #( #children_ids(#children_ids), )*
+                None,
+            }
+        }
+    });
+
+    // Provide the implementation of the specialization function.
+    // The specialization function is only provided for declarations that have
+    // child packets.
+    let specialize = (!children_decl.is_empty()).then(|| {
+        // Gather fields that are constrained in immediate child declarations.
+        // Keep the fields sorted by name.
+        let constraint_fields = children_decl
+            .iter()
+            .flat_map(|decl| decl.constraints().map(|c| c.id.to_owned()))
+            .collect::<BTreeSet<_>>();
+        let constraint_ids = constraint_fields.iter().map(|id| id.to_ident());
+        let children_ids = children_decl.iter().map(|decl| decl.id().unwrap().to_ident());
+
+        // Build the case values and case branches.
+        // The case are ordered by child declaration order.
+        // TODO(henrichataing) ambiguities should be resolved by trying each
+        // case until one is successfully parsed.
+        let case_values = children_decl.iter().map(|child_decl| {
+            let constraint_values = constraint_fields.iter().map(|id| {
+                let constraint = child_decl.constraints().find(|c| &c.id == id);
+                match constraint {
+                    Some(constraint) => constraint_value(&data_fields, constraint),
+                    None => quote! { _ },
+                }
+            });
+            quote! { (#( #constraint_values, )*) }
+        });
+
+        // TODO(henrichataing) the default case is necessary only if the match
+        // is non-exhaustive.
+        let default_case = quote! { _ => #child_name::None, };
+
+        quote! {
+            pub fn specialize(&self) -> Result<#child_name, DecodeError> {
+                Ok(
+                    match (#( self.#constraint_ids, )*) {
+                        #( #case_values =>
+                            #child_name::#children_ids(self.try_into()?), )*
+                        #default_case
+                    }
+                )
+            }
+        }
+    });
+
+    quote! {
+        #[derive(Debug, Clone, PartialEq, Eq)]
+        #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+        pub struct #name {
+            #( pub #data_field_ids: #data_field_types, )*
+            #payload_field
+        }
+
+        #child_struct
+
+        impl #name {
+            #specialize
+            #payload_accessor
+
+            #(
+            pub fn #data_field_ids(&self) -> #data_field_borrows #data_field_types {
+                #data_field_borrows self.#data_field_ids
+            }
+            )*
+        }
+
+        impl Packet for #name {
+            #encoded_len
+            #encode
+            #decode
+        }
+    }
+}
+
+/// Generate code for a derived packet declaration
+///
+/// # Arguments
+/// * `endianness` - File endianness
+/// * `id` - Packet identifier.
+fn generate_derived_packet_decl(
+    scope: &analyzer::Scope<'_>,
+    schema: &analyzer::Schema,
+    endianness: ast::EndiannessValue,
+    id: &str,
+) -> proc_macro2::TokenStream {
+    let decl = scope.typedef[id];
+    let name = id.to_ident();
+    let parent_decl = scope.get_parent(decl).unwrap();
+    let parent_name = parent_decl.id().unwrap().to_ident();
+    let child_name = format_ident!("{id}Child");
+
+    // Extract all constraint values from the parent declarations.
+    let all_constraints = HashMap::<String, _>::from_iter(
+        scope.iter_constraints(decl).map(|c| (c.id.to_string(), c)),
+    );
+
+    let all_fields = scope.iter_fields(decl).collect::<Vec<_>>();
+
+    // Return the list of fields that will appear in the generated
+    // rust structs (<Packet> and <Packet>Builder).
+    // The payload field _ if declared _ is handled separately.
+    let data_fields = packet_data_fields(scope, decl);
+    let data_field_ids = data_fields.iter().map(|f| f.id().unwrap().to_ident()).collect::<Vec<_>>();
+    let data_field_types = data_fields.iter().map(|f| types::rust_type(f)).collect::<Vec<_>>();
+    let data_field_borrows = data_fields
+        .iter()
+        .map(|f| {
+            if implements_copy(scope, f) {
+                quote! {}
+            } else {
+                quote! { & }
+            }
+        })
+        .collect::<Vec<_>>();
+    let payload_field = decl.payload().map(|_| quote! { pub payload: Vec<u8>, });
+    let payload_accessor =
+        decl.payload().map(|_| quote! { pub fn payload(&self) -> &[u8] { &self.payload } });
+
+    let parent_data_fields = packet_data_fields(scope, parent_decl);
+
+    // Return the list of fields that have a constant value.
+    let constant_fields = packet_constant_fields(scope, decl);
+    let constant_field_ids =
+        constant_fields.iter().map(|f| f.id().unwrap().to_ident()).collect::<Vec<_>>();
+    let constant_field_types =
+        constant_fields.iter().map(|f| types::rust_type(f)).collect::<Vec<_>>();
+    let constant_field_values = constant_fields.iter().map(|f| {
+        let c = all_constraints.get(f.id().unwrap()).unwrap();
+        constraint_value(&all_fields, c)
+    });
+
+    // Generate field parsing and serialization.
+    let parser_span = format_ident!("buf");
+    let mut field_parser = FieldParser::new(scope, schema, endianness, id, &parser_span);
+    for field in decl.fields() {
+        field_parser.add(field);
+    }
+
+    // For the implementation of decode_partial, sort the data field identifiers
+    // between parsed fields (extracted from the payload), and copied fields
+    // (copied from the parent).
+    let mut parsed_field_ids = vec![];
+    let mut copied_field_ids = vec![];
+    let mut cloned_field_ids = vec![];
+    if decl.payload().is_some() {
+        parsed_field_ids.push(format_ident!("payload"));
+    }
+    for f in &data_fields {
+        let id = f.id().unwrap().to_ident();
+        if decl.fields().any(|ff| f.id() == ff.id()) {
+            parsed_field_ids.push(id);
+        } else if implements_copy(scope, f) {
+            copied_field_ids.push(id);
+        } else {
+            cloned_field_ids.push(id);
+        }
+    }
+
+    let (partial_field_serializer, field_serializer, encoded_len) =
+        serializer::encode_partial(scope, schema, endianness, "buf".to_ident(), decl);
+
+    let encode_partial = quote! {
+        pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+            #partial_field_serializer
+            Ok(())
+        }
+    };
+
+    let encode = quote! {
+         fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+            #field_serializer
+            Ok(())
+        }
+    };
+
+    // Compute the encoded length of the packet.
+    let encoded_len = quote! {
+        fn encoded_len(&self) -> usize {
+            #encoded_len
+        }
+    };
+
+    // Constraint checks are only run for constraints added to this declaration
+    // and not parent constraints which are expected to have been validated
+    // earlier.
+    let constraint_checks = decl.constraints().map(|c| {
+        let field_id = c.id.to_ident();
+        let field_name = &c.id;
+        let packet_name = id;
+        let value = constraint_value(&parent_data_fields, c);
+        let value_str = constraint_value_str(&parent_data_fields, c);
+        quote! {
+            if parent.#field_id() != #value {
+                return Err(DecodeError::InvalidFieldValue {
+                    packet: #packet_name,
+                    field: #field_name,
+                    expected: #value_str,
+                    actual: format!("{:?}", parent.#field_id()),
+                })
+            }
+        }
+    });
+
+    let decode_partial = if parent_decl.payload().is_some() {
+        // Generate an implementation of decode_partial that will decode
+        // data fields present in the parent payload.
+        // TODO(henrichataing) add constraint validation to decode_partial,
+        // return DecodeError::InvalidConstraint.
+        quote! {
+            fn decode_partial(parent: &#parent_name) -> Result<Self, DecodeError> {
+                let mut buf: &[u8] = &parent.payload;
+                #( #constraint_checks )*
+                #field_parser
+                if buf.is_empty() {
+                    Ok(Self {
+                        #( #parsed_field_ids, )*
+                        #( #copied_field_ids: parent.#copied_field_ids, )*
+                        #( #cloned_field_ids: parent.#cloned_field_ids.clone(), )*
+                    })
+                } else {
+                    Err(DecodeError::TrailingBytes)
+                }
+            }
+        }
+    } else {
+        // Generate an implementation of decode_partial that will only copy
+        // data fields present in the parent.
+        // TODO(henrichataing) add constraint validation to decode_partial,
+        // return DecodeError::InvalidConstraint.
+        quote! {
+            fn decode_partial(parent: &#parent_name) -> Result<Self, DecodeError> {
+                #( #constraint_checks )*
+                Ok(Self {
+                    #( #copied_field_ids: parent.#copied_field_ids, )*
+                })
+            }
+        }
+    };
+
+    let decode =
+        // The implementation of decode for derived packets relies on
+        // the parent packet parser.
+        quote! {
+            fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+                let (parent, trailing_bytes) = #parent_name::decode(buf)?;
+                let packet = Self::decode_partial(&parent)?;
+                Ok((packet, trailing_bytes))
+            }
+        };
+
+    // Provide the implementation of conversion helpers from
+    // the current packet to its parent packets. The implementation
+    // is explicit for the immediate parent, and derived using other
+    // Into<> implementations for the ancestors.
+    let into_parent = {
+        let parent_data_field_ids = parent_data_fields.iter().map(|f| f.id().unwrap().to_ident());
+        let parent_data_field_values = parent_data_fields.iter().map(|f| {
+            let id = f.id().unwrap().to_ident();
+            match all_constraints.get(f.id().unwrap()) {
+                Some(c) => constraint_value(&parent_data_fields, c),
+                None => quote! { packet.#id },
+            }
+        });
+        if parent_decl.payload().is_some() {
+            quote! {
+                impl TryFrom<&#name> for #parent_name {
+                    type Error = EncodeError;
+                    fn try_from(packet: &#name) -> Result<#parent_name, Self::Error> {
+                        let mut payload = Vec::new();
+                        packet.encode_partial(&mut payload)?;
+                        Ok(#parent_name {
+                            #( #parent_data_field_ids: #parent_data_field_values, )*
+                            payload,
+                        })
+                    }
+                }
+
+                impl TryFrom<#name> for #parent_name {
+                    type Error = EncodeError;
+                    fn try_from(packet: #name) -> Result<#parent_name, Self::Error> {
+                        (&packet).try_into()
+                    }
+                }
+            }
+        } else {
+            quote! {
+                impl From<&#name> for #parent_name {
+                    fn from(packet: &#name) -> #parent_name {
+                        #parent_name {
+                            #( #parent_data_field_ids: #parent_data_field_values, )*
+                        }
+                    }
+                }
+
+                impl From<#name> for #parent_name {
+                    fn from(packet: #name) -> #parent_name {
+                        (&packet).into()
+                    }
+                }
+            }
+        }
+    };
+
+    let into_ancestors = scope.iter_parents(parent_decl).map(|ancestor_decl| {
+        let ancestor_name = ancestor_decl.id().unwrap().to_ident();
+        quote! {
+            impl TryFrom<&#name> for #ancestor_name {
+                type Error = EncodeError;
+                fn try_from(packet: &#name) -> Result<#ancestor_name, Self::Error> {
+                    (&#parent_name::try_from(packet)?).try_into()
+                }
+            }
+
+            impl TryFrom<#name> for #ancestor_name {
+                type Error = EncodeError;
+                fn try_from(packet: #name) -> Result<#ancestor_name, Self::Error> {
+                    (&packet).try_into()
+                }
+            }
+        }
+    });
+
+    // Provide the implementation of conversion helper from
+    // the parent packet. This function is actually the parse
+    // implementation. This helper is provided only if the packet has a
+    // parent declaration.
+    let try_from_parent = quote! {
+        impl TryFrom<&#parent_name> for #name {
+            type Error = DecodeError;
+            fn try_from(parent: &#parent_name) -> Result<#name, Self::Error> {
+                #name::decode_partial(&parent)
+            }
+        }
+
+        impl TryFrom<#parent_name> for #name {
+            type Error = DecodeError;
+            fn try_from(parent: #parent_name) -> Result<#name, Self::Error> {
+                (&parent).try_into()
+            }
+        }
+    };
+
+    // Provide the implementation of the enum listing child declarations of the
+    // current declaration. This enum is only provided for declarations that
+    // have child packets.
+    let children_decl = scope.iter_children(decl).collect::<Vec<_>>();
+    let child_struct = (!children_decl.is_empty()).then(|| {
+        let children_ids = children_decl.iter().map(|decl| decl.id().unwrap().to_ident());
+        quote! {
+            #[derive(Debug, Clone, PartialEq, Eq)]
+            #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+            pub enum #child_name {
+                #( #children_ids(#children_ids), )*
+                None,
+            }
+        }
+    });
+
+    // Provide the implementation of the specialization function.
+    // The specialization function is only provided for declarations that have
+    // child packets.
+    let specialize = (!children_decl.is_empty()).then(|| {
+        // Gather fields that are constrained in immediate child declarations.
+        // Keep the fields sorted by name.
+        let constraint_fields = children_decl
+            .iter()
+            .flat_map(|decl| decl.constraints().map(|c| c.id.to_owned()))
+            .collect::<BTreeSet<_>>();
+        let constraint_ids = constraint_fields.iter().map(|id| id.to_ident());
+        let children_ids = children_decl.iter().map(|decl| decl.id().unwrap().to_ident());
+
+        // Build the case values and case branches.
+        // The case are ordered by child declaration order.
+        // TODO(henrichataing) ambiguities should be resolved by trying each
+        // case until one is successfully parsed.
+        let case_values = children_decl.iter().map(|child_decl| {
+            let constraint_values = constraint_fields.iter().map(|id| {
+                let constraint = child_decl.constraints().find(|c| &c.id == id);
+                match constraint {
+                    Some(constraint) => constraint_value(&data_fields, constraint),
+                    None => quote! { _ },
+                }
+            });
+            quote! { (#( #constraint_values, )*) }
+        });
+
+        // TODO(henrichataing) the default case is necessary only if the match
+        // is non-exhaustive.
+        let default_case = quote! { _ => #child_name::None, };
+
+        quote! {
+            pub fn specialize(&self) -> Result<#child_name, DecodeError> {
+                Ok(
+                    match (#( self.#constraint_ids, )*) {
+                        #( #case_values =>
+                            #child_name::#children_ids(self.try_into()?), )*
+                        #default_case
+                    }
+                )
+            }
+        }
+    });
+
+    quote! {
+        #[derive(Debug, Clone, PartialEq, Eq)]
+        #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+        pub struct #name {
+            #( pub #data_field_ids: #data_field_types, )*
+            #payload_field
+        }
+
+        #try_from_parent
+        #into_parent
+        #( #into_ancestors )*
+
+        #child_struct
+
+        impl #name {
+            #specialize
+            #decode_partial
+            #encode_partial
+            #payload_accessor
+
+            #(
+            pub fn #data_field_ids(&self) -> #data_field_borrows #data_field_types {
+                #data_field_borrows self.#data_field_ids
+            }
+            )*
+
+            #(
+            pub fn #constant_field_ids(&self) -> #constant_field_types {
+                #constant_field_values
+            }
+            )*
+        }
+
+        impl Packet for #name {
+            #encoded_len
+            #encode
+            #decode
+        }
+    }
+}
+
+/// Generate an enum declaration.
+///
+/// # Arguments
+/// * `id` - Enum identifier.
+/// * `tags` - List of enum tags.
+/// * `width` - Width of the backing type of the enum, in bits.
+fn generate_enum_decl(id: &str, tags: &[ast::Tag], width: usize) -> proc_macro2::TokenStream {
+    // Determine if the enum is open, i.e. a default tag is defined.
+    fn enum_default_tag(tags: &[ast::Tag]) -> Option<ast::TagOther> {
+        tags.iter()
+            .filter_map(|tag| match tag {
+                ast::Tag::Other(tag) => Some(tag.clone()),
+                _ => None,
+            })
+            .next()
+    }
+
+    // Determine if the enum is complete, i.e. all values in the backing
+    // integer range have a matching tag in the original declaration.
+    fn enum_is_complete(tags: &[ast::Tag], max: usize) -> bool {
+        let mut ranges = tags
+            .iter()
+            .filter_map(|tag| match tag {
+                ast::Tag::Value(tag) => Some((tag.value, tag.value)),
+                ast::Tag::Range(tag) => Some(tag.range.clone().into_inner()),
+                _ => None,
+            })
+            .collect::<Vec<_>>();
+        ranges.sort_unstable();
+        ranges.first().unwrap().0 == 0
+            && ranges.last().unwrap().1 == max
+            && ranges.windows(2).all(|window| {
+                if let [left, right] = window {
+                    left.1 == right.0 - 1
+                } else {
+                    false
+                }
+            })
+    }
+
+    // Determine if the enum is primitive, i.e. does not contain any tag range.
+    fn enum_is_primitive(tags: &[ast::Tag]) -> bool {
+        tags.iter().all(|tag| matches!(tag, ast::Tag::Value(_)))
+    }
+
+    // Return the maximum value for the scalar type.
+    fn scalar_max(width: usize) -> usize {
+        if width >= usize::BITS as usize {
+            usize::MAX
+        } else {
+            (1 << width) - 1
+        }
+    }
+
+    // Format an enum tag identifier to rust upper caml case.
+    fn format_tag_ident(id: &str) -> proc_macro2::TokenStream {
+        let id = format_ident!("{}", id.to_upper_camel_case());
+        quote! { #id }
+    }
+
+    // Format a constant value as hexadecimal constant.
+    fn format_value(value: usize) -> LitInt {
+        syn::parse_str::<syn::LitInt>(&format!("{:#x}", value)).unwrap()
+    }
+
+    // Backing type for the enum.
+    let backing_type = types::Integer::new(width);
+    let backing_type_str = proc_macro2::Literal::string(&format!("u{}", backing_type.width));
+    let range_max = scalar_max(width);
+    let default_tag = enum_default_tag(tags);
+    let is_open = default_tag.is_some();
+    let is_complete = enum_is_complete(tags, scalar_max(width));
+    let is_primitive = enum_is_primitive(tags);
+    let name = id.to_ident();
+
+    // Generate the variant cases for the enum declaration.
+    // Tags declared in ranges are flattened in the same declaration.
+    let use_variant_values = is_primitive && (is_complete || !is_open);
+    let repr_u64 = use_variant_values.then(|| quote! { #[repr(u64)] });
+    let mut variants = vec![];
+    for tag in tags.iter() {
+        match tag {
+            ast::Tag::Value(tag) if use_variant_values => {
+                let id = format_tag_ident(&tag.id);
+                let value = format_value(tag.value);
+                variants.push(quote! { #id = #value })
+            }
+            ast::Tag::Value(tag) => variants.push(format_tag_ident(&tag.id)),
+            ast::Tag::Range(tag) => {
+                variants.extend(tag.tags.iter().map(|tag| format_tag_ident(&tag.id)));
+                let id = format_tag_ident(&tag.id);
+                variants.push(quote! { #id(Private<#backing_type>) })
+            }
+            ast::Tag::Other(_) => (),
+        }
+    }
+
+    // Generate the cases for parsing the enum value from an integer.
+    let mut from_cases = vec![];
+    for tag in tags.iter() {
+        match tag {
+            ast::Tag::Value(tag) => {
+                let id = format_tag_ident(&tag.id);
+                let value = format_value(tag.value);
+                from_cases.push(quote! { #value => Ok(#name::#id) })
+            }
+            ast::Tag::Range(tag) => {
+                from_cases.extend(tag.tags.iter().map(|tag| {
+                    let id = format_tag_ident(&tag.id);
+                    let value = format_value(tag.value);
+                    quote! { #value => Ok(#name::#id) }
+                }));
+                let id = format_tag_ident(&tag.id);
+                let start = format_value(*tag.range.start());
+                let end = format_value(*tag.range.end());
+                from_cases.push(quote! { #start ..= #end => Ok(#name::#id(Private(value))) })
+            }
+            ast::Tag::Other(_) => (),
+        }
+    }
+
+    // Generate the cases for serializing the enum value to an integer.
+    let mut into_cases = vec![];
+    for tag in tags.iter() {
+        match tag {
+            ast::Tag::Value(tag) => {
+                let id = format_tag_ident(&tag.id);
+                let value = format_value(tag.value);
+                into_cases.push(quote! { #name::#id => #value })
+            }
+            ast::Tag::Range(tag) => {
+                into_cases.extend(tag.tags.iter().map(|tag| {
+                    let id = format_tag_ident(&tag.id);
+                    let value = format_value(tag.value);
+                    quote! { #name::#id => #value }
+                }));
+                let id = format_tag_ident(&tag.id);
+                into_cases.push(quote! { #name::#id(Private(value)) => *value })
+            }
+            ast::Tag::Other(_) => (),
+        }
+    }
+
+    // Generate a default case if the enum is open and incomplete.
+    if !is_complete && is_open {
+        let unknown_id = format_tag_ident(&default_tag.unwrap().id);
+        let range_max = format_value(range_max);
+        variants.push(quote! { #unknown_id(Private<#backing_type>) });
+        from_cases.push(quote! { 0..=#range_max => Ok(#name::#unknown_id(Private(value))) });
+        into_cases.push(quote! { #name::#unknown_id(Private(value)) => *value });
+    }
+
+    // Generate an error case if the enum size is lower than the backing
+    // type size, or if the enum is closed or incomplete.
+    if backing_type.width != width || (!is_complete && !is_open) {
+        from_cases.push(quote! { _ => Err(value) });
+    }
+
+    // Derive other Into<uN> and Into<iN> implementations from the explicit
+    // implementation, where the type is larger than the backing type.
+    let derived_signed_into_types = [8, 16, 32, 64]
+        .into_iter()
+        .filter(|w| *w > width)
+        .map(|w| syn::parse_str::<syn::Type>(&format!("i{}", w)).unwrap());
+    let derived_unsigned_into_types = [8, 16, 32, 64]
+        .into_iter()
+        .filter(|w| *w >= width && *w != backing_type.width)
+        .map(|w| syn::parse_str::<syn::Type>(&format!("u{}", w)).unwrap());
+    let derived_into_types = derived_signed_into_types.chain(derived_unsigned_into_types);
+
+    quote! {
+        #repr_u64
+        #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+        #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+        #[cfg_attr(feature = "serde", serde(try_from = #backing_type_str, into = #backing_type_str))]
+        pub enum #name {
+            #(#variants,)*
+        }
+
+        impl TryFrom<#backing_type> for #name {
+            type Error = #backing_type;
+            fn try_from(value: #backing_type) -> Result<Self, Self::Error> {
+                match value {
+                    #(#from_cases,)*
+                }
+            }
+        }
+
+        impl From<&#name> for #backing_type {
+            fn from(value: &#name) -> Self {
+                match value {
+                    #(#into_cases,)*
+                }
+            }
+        }
+
+        impl From<#name> for #backing_type {
+            fn from(value: #name) -> Self {
+                (&value).into()
+            }
+        }
+
+        #(impl From<#name> for #derived_into_types {
+            fn from(value: #name) -> Self {
+                #backing_type::from(value) as Self
+            }
+        })*
+    }
+}
+
+/// Generate the declaration for a custom field of static size.
+///
+/// * `id` - Enum identifier.
+/// * `width` - Width of the backing type of the enum, in bits.
+fn generate_custom_field_decl(
+    endianness: ast::EndiannessValue,
+    id: &str,
+    width: usize,
+) -> proc_macro2::TokenStream {
+    let name = id;
+    let id = id.to_ident();
+    let backing_type = types::Integer::new(width);
+    let backing_type_str = proc_macro2::Literal::string(&format!("u{}", backing_type.width));
+    let max_value = mask_bits(width, &format!("u{}", backing_type.width));
+    let size = proc_macro2::Literal::usize_unsuffixed(width / 8);
+
+    let read_value = types::get_uint(endianness, width, &format_ident!("buf"));
+    let read_value = if [8, 16, 32, 64].contains(&width) {
+        quote! { #read_value.into() }
+    } else {
+        // The value is masked when read, and the conversion must succeed.
+        quote! { (#read_value).try_into().unwrap() }
+    };
+
+    let write_value = types::put_uint(
+        endianness,
+        &quote! { #backing_type::from(self) },
+        width,
+        &format_ident!("buf"),
+    );
+
+    let common = quote! {
+        impl From<&#id> for #backing_type {
+            fn from(value: &#id) -> #backing_type {
+                value.0
+            }
+        }
+
+        impl From<#id> for #backing_type {
+            fn from(value: #id) -> #backing_type {
+                value.0
+            }
+        }
+
+        impl Packet for #id {
+            fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+                if buf.len() < #size {
+                    return Err(DecodeError::InvalidLengthError {
+                        obj: #name,
+                        wanted: #size,
+                        got: buf.len(),
+                    })
+                }
+
+                Ok((#read_value, buf))
+            }
+
+            fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+                #write_value;
+                Ok(())
+            }
+
+            fn encoded_len(&self) -> usize {
+                #size
+            }
+        }
+    };
+
+    if backing_type.width == width {
+        quote! {
+            #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+            #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+            #[cfg_attr(feature = "serde", serde(from = #backing_type_str, into = #backing_type_str))]
+            pub struct #id(#backing_type);
+
+            #common
+
+            impl From<#backing_type> for #id {
+                fn from(value: #backing_type) -> Self {
+                    #id(value)
+                }
+            }
+        }
+    } else {
+        quote! {
+            #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+            #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+            #[cfg_attr(feature = "serde", serde(try_from = #backing_type_str, into = #backing_type_str))]
+            pub struct #id(#backing_type);
+
+            #common
+
+            impl TryFrom<#backing_type> for #id {
+                type Error = #backing_type;
+                fn try_from(value: #backing_type) -> Result<Self, Self::Error> {
+                    if value > #max_value {
+                        Err(value)
+                    } else {
+                        Ok(#id(value))
+                    }
+                }
+            }
+        }
+    }
+}
+
+fn generate_decl(
+    scope: &analyzer::Scope<'_>,
+    schema: &analyzer::Schema,
+    file: &ast::File,
+    decl: &ast::Decl,
+) -> proc_macro2::TokenStream {
+    match &decl.desc {
+        ast::DeclDesc::Packet { id, .. } | ast::DeclDesc::Struct { id, .. } => {
+            match scope.get_parent(decl) {
+                None => generate_root_packet_decl(scope, schema, file.endianness.value, id),
+                Some(_) => generate_derived_packet_decl(scope, schema, file.endianness.value, id),
+            }
+        }
+        ast::DeclDesc::Enum { id, tags, width } => generate_enum_decl(id, tags, *width),
+        ast::DeclDesc::CustomField { id, width: Some(width), .. } => {
+            generate_custom_field_decl(file.endianness.value, id, *width)
+        }
+        ast::DeclDesc::CustomField { .. } => {
+            // No need to generate anything for a custom field,
+            // we just assume it will be in scope.
+            quote!()
+        }
+        _ => todo!("unsupported Decl::{:?}", decl),
+    }
+}
+
+/// Generate Rust code from an AST.
+///
+/// The code is not formatted, pipe it through `rustfmt` to get
+/// readable source code.
+pub fn generate_tokens(
+    sources: &ast::SourceDatabase,
+    file: &ast::File,
+    custom_fields: &[String],
+) -> proc_macro2::TokenStream {
+    let source = sources.get(file.file).expect("could not read source");
+    let preamble = preamble::generate(Path::new(source.name()));
+
+    let scope = analyzer::Scope::new(file).expect("could not create scope");
+    let schema = analyzer::Schema::new(file);
+    let custom_fields = custom_fields.iter().map(|custom_field| {
+        syn::parse_str::<syn::Path>(custom_field)
+            .unwrap_or_else(|err| panic!("invalid path '{custom_field}': {err:?}"))
+    });
+    let decls = file.declarations.iter().map(|decl| generate_decl(&scope, &schema, file, decl));
+    quote! {
+        #preamble
+        #(use #custom_fields;)*
+
+        #(#decls)*
+    }
+}
+
+/// Generate formatted Rust code from an AST.
+///
+/// The code is not formatted, pipe it through `rustfmt` to get
+/// readable source code.
+pub fn generate(
+    sources: &ast::SourceDatabase,
+    file: &ast::File,
+    custom_fields: &[String],
+) -> String {
+    let syntax_tree =
+        syn::parse2(generate_tokens(sources, file, custom_fields)).expect("Could not parse code");
+    prettyplease::unparse(&syntax_tree)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::analyzer;
+    use crate::ast;
+    use crate::parser::parse_inline;
+    use crate::test_utils::{assert_snapshot_eq, format_rust};
+    use paste::paste;
+
+    /// Create a unit test for the given PDL `code`.
+    ///
+    /// The unit test will compare the generated Rust code for all
+    /// declarations with previously saved snapshots. The snapshots
+    /// are read from `"tests/generated/{name}_{endianness}_{id}.rs"`
+    /// where `is` taken from the declaration.
+    ///
+    /// When adding new tests or modifying existing ones, use
+    /// `UPDATE_SNAPSHOTS=1 cargo test` to automatically populate the
+    /// snapshots with the expected output.
+    ///
+    /// The `code` cannot have an endianness declaration, instead you
+    /// must supply either `little_endian` or `big_endian` as
+    /// `endianness`.
+    macro_rules! make_pdl_test {
+        ($name:ident, $code:expr, $endianness:ident) => {
+            paste! {
+                #[test]
+                fn [< test_ $name _ $endianness >]() {
+                    let name = stringify!($name);
+                    let endianness = stringify!($endianness);
+                    let code = format!("{endianness}_packets\n{}", $code);
+                    let mut db = ast::SourceDatabase::new();
+                    let file = parse_inline(&mut db, "test", code).unwrap();
+                    let file = analyzer::analyze(&file).unwrap();
+                    let actual_code = generate(&db, &file, &[]);
+                    assert_snapshot_eq(
+                        &format!("tests/generated/rust/{name}_{endianness}.rs"),
+                        &format_rust(&actual_code),
+                    );
+                }
+            }
+        };
+    }
+
+    /// Create little- and bit-endian tests for the given PDL `code`.
+    ///
+    /// The `code` cannot have an endianness declaration: we will
+    /// automatically generate unit tests for both
+    /// "little_endian_packets" and "big_endian_packets".
+    macro_rules! test_pdl {
+        ($name:ident, $code:expr $(,)?) => {
+            make_pdl_test!($name, $code, little_endian);
+            make_pdl_test!($name, $code, big_endian);
+        };
+    }
+
+    test_pdl!(packet_decl_empty, "packet Foo {}");
+
+    test_pdl!(packet_decl_8bit_scalar, " packet Foo { x:  8 }");
+    test_pdl!(packet_decl_24bit_scalar, "packet Foo { x: 24 }");
+    test_pdl!(packet_decl_64bit_scalar, "packet Foo { x: 64 }");
+
+    test_pdl!(
+        enum_declaration,
+        r#"
+        enum IncompleteTruncatedClosed : 3 {
+            A = 0,
+            B = 1,
+        }
+
+        enum IncompleteTruncatedOpen : 3 {
+            A = 0,
+            B = 1,
+            UNKNOWN = ..
+        }
+
+        enum IncompleteTruncatedClosedWithRange : 3 {
+            A = 0,
+            B = 1..6 {
+                X = 1,
+                Y = 2,
+            }
+        }
+
+        enum IncompleteTruncatedOpenWithRange : 3 {
+            A = 0,
+            B = 1..6 {
+                X = 1,
+                Y = 2,
+            },
+            UNKNOWN = ..
+        }
+
+        enum CompleteTruncated : 3 {
+            A = 0,
+            B = 1,
+            C = 2,
+            D = 3,
+            E = 4,
+            F = 5,
+            G = 6,
+            H = 7,
+        }
+
+        enum CompleteTruncatedWithRange : 3 {
+            A = 0,
+            B = 1..7 {
+                X = 1,
+                Y = 2,
+            }
+        }
+
+        enum CompleteWithRange : 8 {
+            A = 0,
+            B = 1,
+            C = 2..255,
+        }
+        "#
+    );
+
+    test_pdl!(
+        custom_field_declaration,
+        r#"
+        // Still unsupported.
+        // custom_field Dynamic "dynamic"
+
+        // Should generate a type with From<u32> implementation.
+        custom_field ExactSize : 32 "exact_size"
+
+        // Should generate a type with TryFrom<u32> implementation.
+        custom_field TruncatedSize : 24 "truncated_size"
+        "#
+    );
+
+    test_pdl!(
+        packet_decl_simple_scalars,
+        r#"
+          packet Foo {
+            x: 8,
+            y: 16,
+            z: 24,
+          }
+        "#
+    );
+
+    test_pdl!(
+        packet_decl_complex_scalars,
+        r#"
+          packet Foo {
+            a: 3,
+            b: 8,
+            c: 5,
+            d: 24,
+            e: 12,
+            f: 4,
+          }
+        "#,
+    );
+
+    // Test that we correctly mask a byte-sized value in the middle of
+    // a chunk.
+    test_pdl!(
+        packet_decl_mask_scalar_value,
+        r#"
+          packet Foo {
+            a: 2,
+            b: 24,
+            c: 6,
+          }
+        "#,
+    );
+
+    test_pdl!(
+        struct_decl_complex_scalars,
+        r#"
+          struct Foo {
+            a: 3,
+            b: 8,
+            c: 5,
+            d: 24,
+            e: 12,
+            f: 4,
+          }
+        "#,
+    );
+
+    test_pdl!(packet_decl_8bit_enum, " enum Foo :  8 { A = 1, B = 2 } packet Bar { x: Foo }");
+    test_pdl!(packet_decl_24bit_enum, "enum Foo : 24 { A = 1, B = 2 } packet Bar { x: Foo }");
+    test_pdl!(packet_decl_64bit_enum, "enum Foo : 64 { A = 1, B = 2 } packet Bar { x: Foo }");
+
+    test_pdl!(
+        packet_decl_mixed_scalars_enums,
+        "
+          enum Enum7 : 7 {
+            A = 1,
+            B = 2,
+          }
+
+          enum Enum9 : 9 {
+            A = 1,
+            B = 2,
+          }
+
+          packet Foo {
+            x: Enum7,
+            y: 5,
+            z: Enum9,
+            w: 3,
+          }
+        "
+    );
+
+    test_pdl!(packet_decl_8bit_scalar_array, " packet Foo { x:  8[3] }");
+    test_pdl!(packet_decl_24bit_scalar_array, "packet Foo { x: 24[5] }");
+    test_pdl!(packet_decl_64bit_scalar_array, "packet Foo { x: 64[7] }");
+
+    test_pdl!(
+        packet_decl_8bit_enum_array,
+        "enum Foo :  8 { FOO_BAR = 1, BAZ = 2 } packet Bar { x: Foo[3] }"
+    );
+    test_pdl!(
+        packet_decl_24bit_enum_array,
+        "enum Foo : 24 { FOO_BAR = 1, BAZ = 2 } packet Bar { x: Foo[5] }"
+    );
+    test_pdl!(
+        packet_decl_64bit_enum_array,
+        "enum Foo : 64 { FOO_BAR = 1, BAZ = 2 } packet Bar { x: Foo[7] }"
+    );
+
+    test_pdl!(
+        packet_decl_array_dynamic_count,
+        "
+          packet Foo {
+            _count_(x): 5,
+            padding: 3,
+            x: 24[]
+          }
+        "
+    );
+
+    test_pdl!(
+        packet_decl_array_dynamic_size,
+        "
+          packet Foo {
+            _size_(x): 5,
+            padding: 3,
+            x: 24[]
+          }
+        "
+    );
+
+    test_pdl!(
+        packet_decl_array_unknown_element_width_dynamic_size,
+        "
+          struct Foo {
+            _count_(a): 40,
+            a: 16[],
+          }
+
+          packet Bar {
+            _size_(x): 40,
+            x: Foo[],
+          }
+        "
+    );
+
+    test_pdl!(
+        packet_decl_array_unknown_element_width_dynamic_count,
+        "
+          struct Foo {
+            _count_(a): 40,
+            a: 16[],
+          }
+
+          packet Bar {
+            _count_(x): 40,
+            x: Foo[],
+          }
+        "
+    );
+
+    test_pdl!(
+        packet_decl_array_with_padding,
+        "
+          struct Foo {
+            _count_(a): 40,
+            a: 16[],
+          }
+
+          packet Bar {
+            a: Foo[],
+            _padding_ [128],
+          }
+        "
+    );
+
+    test_pdl!(
+        packet_decl_array_dynamic_element_size,
+        "
+          struct Foo {
+            inner: 8[]
+          }
+          packet Bar {
+            _elementsize_(x): 5,
+            padding: 3,
+            x: Foo[]
+          }
+        "
+    );
+
+    test_pdl!(
+        packet_decl_array_dynamic_element_size_dynamic_size,
+        "
+          struct Foo {
+            inner: 8[]
+          }
+          packet Bar {
+            _size_(x): 4,
+            _elementsize_(x): 4,
+            x: Foo[]
+          }
+        "
+    );
+
+    test_pdl!(
+        packet_decl_array_dynamic_element_size_dynamic_count,
+        "
+          struct Foo {
+            inner: 8[]
+          }
+          packet Bar {
+            _count_(x): 4,
+            _elementsize_(x): 4,
+            x: Foo[]
+          }
+        "
+    );
+
+    test_pdl!(
+        packet_decl_array_dynamic_element_size_static_count,
+        "
+          struct Foo {
+            inner: 8[]
+          }
+          packet Bar {
+            _elementsize_(x): 5,
+            padding: 3,
+            x: Foo[4]
+          }
+        "
+    );
+
+    test_pdl!(
+        packet_decl_array_dynamic_element_size_static_count_1,
+        "
+          struct Foo {
+            inner: 8[]
+          }
+          packet Bar {
+            _elementsize_(x): 5,
+            padding: 3,
+            x: Foo[1]
+          }
+        "
+    );
+
+    test_pdl!(
+        packet_decl_reserved_field,
+        "
+          packet Foo {
+            _reserved_: 40,
+          }
+        "
+    );
+
+    test_pdl!(
+        packet_decl_custom_field,
+        r#"
+          custom_field Bar1 : 24 "exact"
+          custom_field Bar2 : 32 "truncated"
+
+          packet Foo {
+            a: Bar1,
+            b: Bar2,
+          }
+        "#
+    );
+
+    test_pdl!(
+        packet_decl_fixed_scalar_field,
+        "
+          packet Foo {
+            _fixed_ = 7 : 7,
+            b: 57,
+          }
+        "
+    );
+
+    test_pdl!(
+        packet_decl_fixed_enum_field,
+        "
+          enum Enum7 : 7 {
+            A = 1,
+            B = 2,
+          }
+
+          packet Foo {
+              _fixed_ = A : Enum7,
+              b: 57,
+          }
+        "
+    );
+
+    test_pdl!(
+        packet_decl_payload_field_variable_size,
+        "
+          packet Foo {
+              a: 8,
+              _size_(_payload_): 8,
+              _payload_,
+              b: 16,
+          }
+        "
+    );
+
+    test_pdl!(
+        packet_decl_payload_field_unknown_size,
+        "
+          packet Foo {
+              a: 24,
+              _payload_,
+          }
+        "
+    );
+
+    test_pdl!(
+        packet_decl_payload_field_unknown_size_terminal,
+        "
+          packet Foo {
+              _payload_,
+              a: 24,
+          }
+        "
+    );
+
+    test_pdl!(
+        packet_decl_child_packets,
+        "
+          enum Enum16 : 16 {
+            A = 1,
+            B = 2,
+          }
+
+          packet Foo {
+              a: 8,
+              b: Enum16,
+              _size_(_payload_): 8,
+              _payload_
+          }
+
+          packet Bar : Foo (a = 100) {
+              x: 8,
+          }
+
+          packet Baz : Foo (b = B) {
+              y: 16,
+          }
+        "
+    );
+
+    test_pdl!(
+        packet_decl_grand_children,
+        "
+          enum Enum16 : 16 {
+            A = 1,
+            B = 2,
+          }
+
+          packet Parent {
+              foo: Enum16,
+              bar: Enum16,
+              baz: Enum16,
+              _size_(_payload_): 8,
+              _payload_
+          }
+
+          packet Child : Parent (foo = A) {
+              quux: Enum16,
+              _payload_,
+          }
+
+          packet GrandChild : Child (bar = A, quux = A) {
+              _body_,
+          }
+
+          packet GrandGrandChild : GrandChild (baz = A) {
+              _body_,
+          }
+        "
+    );
+
+    test_pdl!(
+        packet_decl_parent_with_no_payload,
+        "
+          enum Enum8 : 8 {
+            A = 0,
+          }
+
+          packet Parent {
+            v : Enum8,
+          }
+
+          packet Child : Parent (v = A) {
+          }
+        "
+    );
+
+    test_pdl!(
+        packet_decl_parent_with_alias_child,
+        "
+          enum Enum8 : 8 {
+            A = 0,
+            B = 1,
+            C = 2,
+          }
+
+          packet Parent {
+            v : Enum8,
+            _payload_,
+          }
+
+          packet AliasChild : Parent {
+            _payload_
+          }
+
+          packet NormalChild : Parent (v = A) {
+          }
+
+          packet NormalGrandChild1 : AliasChild (v = B) {
+          }
+
+          packet NormalGrandChild2 : AliasChild (v = C) {
+              _payload_
+          }
+        "
+    );
+
+    test_pdl!(
+        reserved_identifier,
+        "
+          packet Test {
+            type: 8,
+          }
+        "
+    );
+
+    test_pdl!(
+        payload_with_size_modifier,
+        "
+        packet Test {
+            _size_(_payload_): 8,
+            _payload_ : [+1],
+        }
+        "
+    );
+
+    test_pdl!(
+        struct_decl_child_structs,
+        "
+          enum Enum16 : 16 {
+            A = 1,
+            B = 2,
+          }
+
+          struct Foo {
+              a: 8,
+              b: Enum16,
+              _size_(_payload_): 8,
+              _payload_
+          }
+
+          struct Bar : Foo (a = 100) {
+              x: 8,
+          }
+
+          struct Baz : Foo (b = B) {
+              y: 16,
+          }
+        "
+    );
+
+    test_pdl!(
+        struct_decl_grand_children,
+        "
+          enum Enum16 : 16 {
+            A = 1,
+            B = 2,
+          }
+
+          struct Parent {
+              foo: Enum16,
+              bar: Enum16,
+              baz: Enum16,
+              _size_(_payload_): 8,
+              _payload_
+          }
+
+          struct Child : Parent (foo = A) {
+              quux: Enum16,
+              _payload_,
+          }
+
+          struct GrandChild : Child (bar = A, quux = A) {
+              _body_,
+          }
+
+          struct GrandGrandChild : GrandChild (baz = A) {
+              _body_,
+          }
+        "
+    );
+}
diff --git a/src/backends/rust/parser.rs b/src/backends/rust/parser.rs
index 8e76592..2d19fc9 100644
--- a/src/backends/rust/parser.rs
+++ b/src/backends/rust/parser.rs
@@ -12,14 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use crate::analyzer::ast as analyzer_ast;
-use crate::backends::rust::{
-    constraint_to_value, find_constrained_parent_fields, mask_bits, types, ToIdent,
-    ToUpperCamelCase,
-};
+use crate::backends::rust::{mask_bits, types, ToIdent, ToUpperCamelCase};
 use crate::{analyzer, ast};
 use quote::{format_ident, quote};
-use std::collections::{BTreeSet, HashMap};
 
 fn size_field_ident(id: &str) -> proc_macro2::Ident {
     format_ident!("{}_size", id.trim_matches('_'))
@@ -28,17 +23,18 @@
 /// A single bit-field.
 struct BitField<'a> {
     shift: usize, // The shift to apply to this field.
-    field: &'a analyzer_ast::Field,
+    field: &'a ast::Field,
 }
 
 pub struct FieldParser<'a> {
     scope: &'a analyzer::Scope<'a>,
+    schema: &'a analyzer::Schema,
     endianness: ast::EndiannessValue,
-    decl: &'a analyzer_ast::Decl,
+    decl: &'a ast::Decl,
     packet_name: &'a str,
     span: &'a proc_macro2::Ident,
     chunk: Vec<BitField<'a>>,
-    code: Vec<proc_macro2::TokenStream>,
+    tokens: proc_macro2::TokenStream,
     shift: usize,
     offset: usize,
 }
@@ -46,24 +42,26 @@
 impl<'a> FieldParser<'a> {
     pub fn new(
         scope: &'a analyzer::Scope<'a>,
+        schema: &'a analyzer::Schema,
         endianness: ast::EndiannessValue,
         packet_name: &'a str,
         span: &'a proc_macro2::Ident,
     ) -> FieldParser<'a> {
         FieldParser {
             scope,
+            schema,
             endianness,
             decl: scope.typedef[packet_name],
             packet_name,
             span,
             chunk: Vec::new(),
-            code: Vec::new(),
+            tokens: quote! {},
             shift: 0,
             offset: 0,
         }
     }
 
-    pub fn add(&mut self, field: &'a analyzer_ast::Field) {
+    pub fn add(&mut self, field: &'a ast::Field) {
         match &field.desc {
             _ if field.cond.is_some() => self.add_optional_field(field),
             _ if self.scope.is_bitfield(field) => self.add_bit_field(field),
@@ -73,7 +71,7 @@
                 *width,
                 type_id.as_deref(),
                 *size,
-                field.annot.padded_size,
+                self.schema.padded_size(field.key),
                 self.scope.get_type_declaration(field),
             ),
             ast::FieldDesc::Typedef { id, type_id } => self.add_typedef_field(id, type_id),
@@ -85,7 +83,7 @@
         }
     }
 
-    fn add_optional_field(&mut self, field: &'a analyzer_ast::Field) {
+    fn add_optional_field(&mut self, field: &'a ast::Field) {
         let cond_id = field.cond.as_ref().unwrap().id.to_ident();
         let cond_value = syn::parse_str::<syn::LitInt>(&format!(
             "{}",
@@ -93,55 +91,55 @@
         ))
         .unwrap();
 
-        self.code.push(
-            match &field.desc {
-                ast::FieldDesc::Scalar { id, width } => {
+        self.tokens.extend(match &field.desc {
+            ast::FieldDesc::Scalar { id, width } => {
+                let id = id.to_ident();
+                let value = types::get_uint(self.endianness, *width, self.span);
+                quote! {
+                    let #id = (#cond_id == #cond_value).then(|| #value);
+                }
+            }
+            ast::FieldDesc::Typedef { id, type_id } => match &self.scope.typedef[type_id].desc {
+                ast::DeclDesc::Enum { width, .. } => {
+                    let name = id;
+                    let type_name = type_id;
                     let id = id.to_ident();
+                    let type_id = type_id.to_ident();
+                    let decl_id = &self.packet_name;
                     let value = types::get_uint(self.endianness, *width, self.span);
                     quote! {
-                        let #id = (#cond_id == #cond_value).then(|| #value);
+                        let #id = (#cond_id == #cond_value)
+                            .then(||
+                                #type_id::try_from(#value).map_err(|unknown_val| {
+                                    DecodeError::InvalidEnumValueError {
+                                        obj: #decl_id,
+                                        field: #name,
+                                        value: unknown_val as u64,
+                                        type_: #type_name,
+                                    }
+                                }))
+                            .transpose()?;
                     }
-                },
-                ast::FieldDesc::Typedef { id, type_id } =>
-                    match &self.scope.typedef[type_id].desc {
-                        ast::DeclDesc::Enum { width, .. } => {
-                            let name = id;
-                            let type_name = type_id;
-                            let id = id.to_ident();
-                            let type_id = type_id.to_ident();
-                            let decl_id = &self.packet_name;
-                            let value = types::get_uint(self.endianness, *width, self.span);
-                            quote! {
-                                let #id = (#cond_id == #cond_value)
-                                    .then(||
-                                        #type_id::try_from(#value).map_err(|unknown_val| Error::InvalidEnumValueError {
-                                            obj: #decl_id.to_string(),
-                                            field: #name.to_string(),
-                                            value: unknown_val as u64,
-                                            type_: #type_name.to_string(),
-                                        }))
-                                    .transpose()?;
-                            }
-                        }
-                        ast::DeclDesc::Struct { .. } => {
-                            let id = id.to_ident();
-                            let type_id = type_id.to_ident();
-                            let span = self.span;
-                            quote! {
-                                let #id = (#cond_id == #cond_value)
-                                    .then(|| #type_id::parse_inner(&mut #span))
-                                    .transpose()?;
-                            }
-                        }
-                        _ => unreachable!(),
+                }
+                ast::DeclDesc::Struct { .. } => {
+                    let id = id.to_ident();
+                    let type_id = type_id.to_ident();
+                    let span = self.span;
+                    quote! {
+                        let #id = (#cond_id == #cond_value)
+                            .then(|| #type_id::decode_mut(&mut #span))
+                            .transpose()?;
                     }
+                }
                 _ => unreachable!(),
-            })
+            },
+            _ => unreachable!(),
+        })
     }
 
-    fn add_bit_field(&mut self, field: &'a analyzer_ast::Field) {
+    fn add_bit_field(&mut self, field: &'a ast::Field) {
         self.chunk.push(BitField { shift: self.shift, field });
-        self.shift += field.annot.size.static_().unwrap();
+        self.shift += self.schema.field_size(field.key).static_().unwrap();
         if self.shift % 8 != 0 {
             return;
         }
@@ -162,7 +160,7 @@
         let get = types::get_uint(self.endianness, self.shift, self.span);
         if self.chunk.len() > 1 {
             // Multiple values: we read into a local variable.
-            self.code.push(quote! {
+            self.tokens.extend(quote! {
                 let #chunk_name = #get;
             });
         }
@@ -182,7 +180,7 @@
                 v = quote! { (#v >> #shift) }
             }
 
-            let width = field.annot.size.static_().unwrap();
+            let width = self.schema.field_size(field.key).static_().unwrap();
             let value_type = types::Integer::new(width);
             if !single_value && width < value_type.width {
                 // Mask value if we grabbed more than `width` and if
@@ -195,7 +193,7 @@
                 v = quote! { #v as #value_type };
             }
 
-            self.code.push(match &field.desc {
+            self.tokens.extend(match &field.desc {
                 ast::FieldDesc::Scalar { id, .. }
                 | ast::FieldDesc::Flag { id, .. } => {
                     let id = id.to_ident();
@@ -209,7 +207,7 @@
                     quote! {
                         let fixed_value = #v;
                         if fixed_value != #value_type::from(#enum_id::#tag_id)  {
-                            return Err(Error::InvalidFixedValue {
+                            return Err(DecodeError::InvalidFixedValue {
                                 expected: #value_type::from(#enum_id::#tag_id) as u64,
                                 actual: fixed_value as u64,
                             });
@@ -221,7 +219,7 @@
                     quote! {
                         let fixed_value = #v;
                         if fixed_value != #value {
-                            return Err(Error::InvalidFixedValue {
+                            return Err(DecodeError::InvalidFixedValue {
                                 expected: #value,
                                 actual: fixed_value as u64,
                             });
@@ -235,11 +233,11 @@
                     let id = id.to_ident();
                     let type_id = type_id.to_ident();
                     quote! {
-                        let #id = #type_id::try_from(#v).map_err(|unknown_val| Error::InvalidEnumValueError {
-                            obj: #packet_name.to_string(),
-                            field: #field_name.to_string(),
+                        let #id = #type_id::try_from(#v).map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                            obj: #packet_name,
+                            field: #field_name,
                             value: unknown_val as u64,
-                            type_: #type_name.to_string(),
+                            type_: #type_name,
                         })?;
                     }
                 }
@@ -248,7 +246,7 @@
                         let span = self.span;
                         let size = proc_macro2::Literal::usize_unsuffixed(size);
                         quote! {
-                            #span.get_mut().advance(#size);
+                            #span.advance(#size);
                         }
                     } else {
                         //  Otherwise we don't need anything: we will
@@ -263,6 +261,12 @@
                         let #id = #v as usize;
                     }
                 }
+                ast::FieldDesc::ElementSize { field_id, .. } => {
+                    let id = format_ident!("{field_id}_element_size");
+                    quote! {
+                        let #id = #v as usize;
+                    }
+                }
                 ast::FieldDesc::Count { field_id, .. } => {
                     let id = format_ident!("{field_id}_count");
                     quote! {
@@ -291,6 +295,15 @@
         }
     }
 
+    fn find_element_size_field(&self, id: &str) -> Option<proc_macro2::Ident> {
+        self.decl.fields().find_map(|field| match &field.desc {
+            ast::FieldDesc::ElementSize { field_id, .. } if field_id == id => {
+                Some(format_ident!("{id}_element_size"))
+            }
+            _ => None,
+        })
+    }
+
     fn payload_field_offset_from_end(&self) -> Option<usize> {
         let decl = self.scope.typedef[self.packet_name];
         let mut fields = decl.fields();
@@ -300,7 +313,9 @@
 
         let mut offset = 0;
         for field in fields {
-            if let Some(width) = field.annot.static_() {
+            if let Some(width) =
+                self.schema.padded_size(field.key).or(self.schema.field_size(field.key).static_())
+            {
                 offset += width;
             } else {
                 return None;
@@ -312,12 +327,12 @@
 
     fn check_size(&mut self, span: &proc_macro2::Ident, wanted: &proc_macro2::TokenStream) {
         let packet_name = &self.packet_name;
-        self.code.push(quote! {
-            if #span.get().remaining() < #wanted {
-                return Err(Error::InvalidLengthError {
-                    obj: #packet_name.to_string(),
+        self.tokens.extend(quote! {
+            if #span.remaining() < #wanted {
+                return Err(DecodeError::InvalidLengthError {
+                    obj: #packet_name,
                     wanted: #wanted,
-                    got: #span.get().remaining(),
+                    got: #span.remaining(),
                 });
             }
         });
@@ -335,18 +350,22 @@
         // known). If None, the array is a Vec with a dynamic size.
         size: Option<usize>,
         padding_size: Option<usize>,
-        decl: Option<&analyzer_ast::Decl>,
+        decl: Option<&ast::Decl>,
     ) {
         enum ElementWidth {
-            Static(usize), // Static size in bytes.
+            Static(usize),               // Static size in bytes.
+            Dynamic(proc_macro2::Ident), // Dynamic size in bytes.
             Unknown,
         }
-        let element_width = match width.or_else(|| decl.unwrap().annot.total_size().static_()) {
-            Some(w) => {
-                assert_eq!(w % 8, 0, "Array element size ({w}) is not a multiple of 8");
-                ElementWidth::Static(w / 8)
-            }
-            None => ElementWidth::Unknown,
+        let element_width = if let Some(w) =
+            width.or_else(|| self.schema.total_size(decl.unwrap().key).static_())
+        {
+            assert_eq!(w % 8, 0, "Array element size ({w}) is not a multiple of 8");
+            ElementWidth::Static(w / 8)
+        } else if let Some(element_size_field) = self.find_element_size_field(id) {
+            ElementWidth::Dynamic(element_size_field)
+        } else {
+            ElementWidth::Unknown
         };
 
         // The "shape" of the array, i.e., the number of elements
@@ -373,17 +392,19 @@
         let span = match padding_size {
             Some(padding_size) => {
                 let span = self.span;
-                self.check_size(span, &quote!(#padding_size));
-                self.code.push(quote! {
-                    let (head, tail) = #span.get().split_at(#padding_size);
-                    let mut head = &mut Cell::new(head);
-                    #span.replace(tail);
+                let padding_octets = padding_size / 8;
+                self.check_size(span, &quote!(#padding_octets));
+                self.tokens.extend(quote! {
+                    let (mut head, tail) = #span.split_at(#padding_octets);
+                    #span = tail;
                 });
                 format_ident!("head")
             }
             None => self.span.clone(),
         };
 
+        let field_name = id;
+        let packet_name = self.packet_name;
         let id = id.to_ident();
 
         let parse_element = self.parse_array_element(&span, width, type_id, decl);
@@ -395,12 +416,11 @@
                 self.check_size(&span, &quote!(#size_field));
                 let parse_element =
                     self.parse_array_element(&format_ident!("head"), width, type_id, decl);
-                self.code.push(quote! {
-                    let (head, tail) = #span.get().split_at(#size_field);
-                    let mut head = &mut Cell::new(head);
-                    #span.replace(tail);
+                self.tokens.extend(quote! {
+                    let (mut head, tail) = #span.split_at(#size_field);
+                    #span = tail;
                     let mut #id = Vec::new();
-                    while !head.get().is_empty() {
+                    while !head.is_empty() {
                         #id.push(#parse_element?);
                     }
                 });
@@ -409,34 +429,36 @@
                 // The element width is not known, but the array
                 // element count is known statically. Parse elements
                 // item by item as an array.
-                let count = syn::Index::from(*count);
-                self.code.push(quote! {
+                let count = proc_macro2::Literal::usize_unsuffixed(*count);
+                self.tokens.extend(quote! {
                     // TODO(mgeisler): use
                     // https://doc.rust-lang.org/std/array/fn.try_from_fn.html
                     // when stabilized.
-                    let #id = (0..#count)
-                        .map(|_| #parse_element)
-                        .collect::<Result<Vec<_>>>()?
+                    let mut #id = Vec::with_capacity(#count);
+                    for _ in 0..#count {
+                        #id.push(#parse_element?)
+                    }
+                    let #id = #id
                         .try_into()
-                        .map_err(|_| Error::InvalidPacketError)?;
+                        .map_err(|_| DecodeError::InvalidPacketError)?;
                 });
             }
             (ElementWidth::Unknown, ArrayShape::CountField(count_field)) => {
                 // The element width is not known, but the array
                 // element count is known by the count field. Parse
                 // elements item by item as a vector.
-                self.code.push(quote! {
+                self.tokens.extend(quote! {
                     let #id = (0..#count_field)
                         .map(|_| #parse_element)
-                        .collect::<Result<Vec<_>>>()?;
+                        .collect::<Result<Vec<_>, DecodeError>>()?;
                 });
             }
             (ElementWidth::Unknown, ArrayShape::Unknown) => {
                 // Neither the count not size is known, parse elements
                 // until the end of the span.
-                self.code.push(quote! {
+                self.tokens.extend(quote! {
                     let mut #id = Vec::new();
-                    while !#span.get().is_empty() {
+                    while !#span.is_empty() {
                         #id.push(#parse_element?);
                     }
                 });
@@ -444,34 +466,36 @@
             (ElementWidth::Static(element_width), ArrayShape::Static(count)) => {
                 // The element width is known, and the array element
                 // count is known statically.
-                let count = syn::Index::from(*count);
+                let count = proc_macro2::Literal::usize_unsuffixed(*count);
                 // This creates a nicely formatted size.
                 let array_size = if element_width == 1 {
                     quote!(#count)
                 } else {
-                    let element_width = syn::Index::from(element_width);
+                    let element_width = proc_macro2::Literal::usize_unsuffixed(element_width);
                     quote!(#count * #element_width)
                 };
                 self.check_size(&span, &quote! { #array_size });
-                self.code.push(quote! {
+                self.tokens.extend(quote! {
                     // TODO(mgeisler): use
                     // https://doc.rust-lang.org/std/array/fn.try_from_fn.html
                     // when stabilized.
-                    let #id = (0..#count)
-                        .map(|_| #parse_element)
-                        .collect::<Result<Vec<_>>>()?
+                    let mut #id = Vec::with_capacity(#count);
+                    for _ in 0..#count {
+                        #id.push(#parse_element?)
+                    }
+                    let #id = #id
                         .try_into()
-                        .map_err(|_| Error::InvalidPacketError)?;
+                        .map_err(|_| DecodeError::InvalidPacketError)?;
                 });
             }
             (ElementWidth::Static(element_width), ArrayShape::CountField(count_field)) => {
                 // The element width is known, and the array element
                 // count is known dynamically by the count field.
                 self.check_size(&span, &quote!(#count_field * #element_width));
-                self.code.push(quote! {
+                self.tokens.extend(quote! {
                     let #id = (0..#count_field)
                         .map(|_| #parse_element)
-                        .collect::<Result<Vec<_>>>()?;
+                        .collect::<Result<Vec<_>, DecodeError>>()?;
                 });
             }
             (ElementWidth::Static(element_width), ArrayShape::SizeField(_))
@@ -483,14 +507,14 @@
                     self.check_size(&span, &quote!(#size_field));
                     quote!(#size_field)
                 } else {
-                    quote!(#span.get().remaining())
+                    quote!(#span.remaining())
                 };
                 let count_field = format_ident!("{id}_count");
                 let array_count = if element_width != 1 {
-                    let element_width = syn::Index::from(element_width);
-                    self.code.push(quote! {
+                    let element_width = proc_macro2::Literal::usize_unsuffixed(element_width);
+                    self.tokens.extend(quote! {
                         if #array_size % #element_width != 0 {
-                            return Err(Error::InvalidArraySize {
+                            return Err(DecodeError::InvalidArraySize {
                                 array: #array_size,
                                 element: #element_width,
                             });
@@ -502,13 +526,115 @@
                     array_size
                 };
 
-                self.code.push(quote! {
+                self.tokens.extend(quote! {
                     let mut #id = Vec::with_capacity(#array_count);
                     for _ in 0..#array_count {
                         #id.push(#parse_element?);
                     }
                 });
             }
+            (ElementWidth::Dynamic(element_size_field), ArrayShape::Static(count)) => {
+                // The element width is known, and the array element
+                // count is known statically.
+                let array_size = if *count == 1 {
+                    quote!(#element_size_field)
+                } else {
+                    quote!(#count * #element_size_field)
+                };
+
+                self.check_size(&span, &array_size);
+
+                let parse_element =
+                    self.parse_array_element(&format_ident!("chunk"), width, type_id, decl);
+
+                self.tokens.extend(quote! {
+                    // TODO: use
+                    // https://doc.rust-lang.org/std/array/fn.try_from_fn.html
+                    // when stabilized.
+                    let #id = #span.chunks(#element_size_field)
+                        .take(#count)
+                        .map(|mut chunk| #parse_element.and_then(|value| {
+                            if chunk.is_empty() {
+                                Ok(value)
+                            } else {
+                                Err(DecodeError::TrailingBytesInArray {
+                                    obj: #packet_name,
+                                    field: #field_name,
+                                })
+                            }
+                         }))
+                        .collect::<Result<Vec<_>, DecodeError>>()?;
+                    #span = &#span[#array_size..];
+                    let #id = #id
+                        .try_into()
+                        .map_err(|_| DecodeError::InvalidPacketError)?;
+                });
+            }
+            (ElementWidth::Dynamic(element_size_field), ArrayShape::CountField(count_field)) => {
+                // The element width is known, and the array element
+                // count is known dynamically by the count field.
+                self.check_size(&span, &quote!(#count_field * #element_size_field));
+
+                let parse_element =
+                    self.parse_array_element(&format_ident!("chunk"), width, type_id, decl);
+
+                self.tokens.extend(quote! {
+                    let #id = #span.chunks(#element_size_field)
+                        .take(#count_field)
+                        .map(|mut chunk| #parse_element.and_then(|value| {
+                            if chunk.is_empty() {
+                                Ok(value)
+                            } else {
+                                Err(DecodeError::TrailingBytesInArray {
+                                    obj: #packet_name,
+                                    field: #field_name,
+                                })
+                            }
+                         }))
+                        .collect::<Result<Vec<_>, DecodeError>>()?;
+                    #span = &#span[(#element_size_field * #count_field)..];
+                });
+            }
+            (ElementWidth::Dynamic(element_size_field), ArrayShape::SizeField(_))
+            | (ElementWidth::Dynamic(element_size_field), ArrayShape::Unknown) => {
+                // The element width is known, and the array full size
+                // is known by size field, or unknown (in which case
+                // it is the remaining span length).
+                let array_size = if let ArrayShape::SizeField(size_field) = &array_shape {
+                    self.check_size(&span, &quote!(#size_field));
+                    quote!(#size_field)
+                } else {
+                    quote!(#span.remaining())
+                };
+                self.tokens.extend(quote! {
+                    if #array_size % #element_size_field != 0 {
+                        return Err(DecodeError::InvalidArraySize {
+                            array: #array_size,
+                            element: #element_size_field,
+                        });
+                    }
+                });
+
+                let parse_element =
+                    self.parse_array_element(&format_ident!("chunk"), width, type_id, decl);
+
+                self.tokens.extend(quote! {
+                    let #id = #span.chunks(#element_size_field)
+                        .take(#array_size / #element_size_field)
+                        .map(|mut chunk| #parse_element.and_then(|value| {
+                            if chunk.is_empty() {
+                                Ok(value)
+                            } else {
+                                Err(DecodeError::TrailingBytesInArray {
+                                    obj: #packet_name,
+                                    field: #field_name,
+                                })
+                            }
+                         }))
+                        .collect::<Result<Vec<_>, DecodeError>>()?;
+                    #span = &#span[#array_size..];
+                });
+            }
         }
     }
 
@@ -520,19 +646,15 @@
         assert_eq!(self.shift, 0, "Typedef field does not start on an octet boundary");
 
         let decl = self.scope.typedef[type_id];
-        if let ast::DeclDesc::Struct { parent_id: Some(_), .. } = &decl.desc {
-            panic!("Derived struct used in typedef field");
-        }
-
         let span = self.span;
         let id = id.to_ident();
         let type_id = type_id.to_ident();
 
-        self.code.push(match decl.annot.size {
-            analyzer_ast::Size::Unknown | analyzer_ast::Size::Dynamic => quote! {
-                let #id = #type_id::parse_inner(&mut #span)?;
+        self.tokens.extend(match self.schema.decl_size(decl.key) {
+            analyzer::Size::Unknown | analyzer::Size::Dynamic => quote! {
+                let (#id, mut #span) = #type_id::decode(#span)?;
             },
-            analyzer_ast::Size::Static(width) => {
+            analyzer::Size::Static(width) => {
                 assert_eq!(width % 8, 0, "Typedef field type size is not a multiple of 8");
                 match &decl.desc {
                     ast::DeclDesc::Checksum { .. } => todo!(),
@@ -551,11 +673,8 @@
                         }
                     }
                     ast::DeclDesc::Struct { .. } => {
-                        let width = syn::Index::from(width / 8);
                         quote! {
-                            let (head, tail) = #span.get().split_at(#width);
-                            #span.replace(tail);
-                            let #id = #type_id::parse(head)?;
+                            let (#id, mut #span) = #type_id::decode(#span)?;
                         }
                     }
                     _ => unreachable!(),
@@ -587,10 +706,10 @@
                 // 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! {
+                self.tokens.extend(quote! {
                     if #size_field < #size_modifier {
-                        return Err(Error::InvalidLengthError {
-                            obj: #packet_name.to_string(),
+                        return Err(DecodeError::InvalidLengthError {
+                            obj: #packet_name,
                             wanted: #size_modifier,
                             got: #size_field,
                         });
@@ -599,16 +718,16 @@
                 });
             }
             self.check_size(self.span, &quote!(#size_field ));
-            self.code.push(quote! {
-                let payload = &#span.get()[..#size_field];
-                #span.get_mut().advance(#size_field);
+            self.tokens.extend(quote! {
+                let payload = #span[..#size_field].to_vec();
+                #span.advance(#size_field);
             });
         } else if offset_from_end == Some(0) {
             // The payload or body is the last field of a packet,
             // consume the remaining span.
-            self.code.push(quote! {
-                let payload = #span.get();
-                #span.get_mut().advance(payload.len());
+            self.tokens.extend(quote! {
+                let payload = #span.to_vec();
+                #span.advance(payload.len());
             });
         } else if let Some(offset_from_end) = offset_from_end {
             // The payload or body is followed by fields of static
@@ -619,17 +738,17 @@
                 0,
                 "Payload field offset from end of packet is not a multiple of 8"
             );
-            let offset_from_end = syn::Index::from(offset_from_end / 8);
+            let offset_from_end = proc_macro2::Literal::usize_unsuffixed(offset_from_end / 8);
             self.check_size(self.span, &quote!(#offset_from_end));
-            self.code.push(quote! {
-                let payload = &#span.get()[..#span.get().len() - #offset_from_end];
-                #span.get_mut().advance(payload.len());
+            self.tokens.extend(quote! {
+                let payload = #span[..#span.len() - #offset_from_end].to_vec();
+                #span.advance(payload.len());
             });
         }
 
         let decl = self.scope.typedef[self.packet_name];
         if let ast::DeclDesc::Struct { .. } = &decl.desc {
-            self.code.push(quote! {
+            self.tokens.extend(quote! {
                 let payload = Vec::from(payload);
             });
         }
@@ -641,12 +760,12 @@
         span: &proc_macro2::Ident,
         width: Option<usize>,
         type_id: Option<&str>,
-        decl: Option<&analyzer_ast::Decl>,
+        decl: Option<&ast::Decl>,
     ) -> proc_macro2::TokenStream {
         if let Some(width) = width {
             let get_uint = types::get_uint(self.endianness, width, span);
             return quote! {
-                Ok::<_, Error>(#get_uint)
+                Ok::<_, DecodeError>(#get_uint)
             };
         }
 
@@ -655,130 +774,25 @@
             let type_id = id.to_ident();
             let packet_name = &self.packet_name;
             return quote! {
-                #type_id::try_from(#get_uint).map_err(|unknown_val| Error::InvalidEnumValueError {
-                    obj: #packet_name.to_string(),
-                    field: String::new(), // TODO(mgeisler): fill out or remove
+                #type_id::try_from(#get_uint).map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                    obj: #packet_name,
+                    field: "", // TODO(mgeisler): fill out or remove
                     value: unknown_val as u64,
-                    type_: #id.to_string(),
+                    type_: #id,
                 })
             };
         }
 
         let type_id = type_id.unwrap().to_ident();
         quote! {
-            #type_id::parse_inner(#span)
+            #type_id::decode_mut(&mut #span)
         }
     }
-
-    pub fn done(&mut self) {
-        let decl = self.scope.typedef[self.packet_name];
-        if let ast::DeclDesc::Struct { .. } = &decl.desc {
-            return; // Structs don't parse the child structs recursively.
-        }
-
-        let children = self.scope.iter_children(decl).collect::<Vec<_>>();
-        if children.is_empty() && self.decl.payload().is_none() {
-            return;
-        }
-
-        let all_fields = HashMap::<String, _>::from_iter(
-            self.scope.iter_fields(decl).filter_map(|f| f.id().map(|id| (id.to_string(), f))),
-        );
-
-        // Gather fields that are constrained in immediate child declarations.
-        // Keep the fields sorted by name.
-        // TODO: fields that are only matched in grand children will not be included.
-        let constrained_fields = children
-            .iter()
-            .flat_map(|child| child.constraints().map(|c| &c.id))
-            .collect::<BTreeSet<_>>();
-
-        let mut match_values = Vec::new();
-        let mut child_parse_args = Vec::new();
-        let mut child_ids_data = Vec::new();
-        let mut child_ids = Vec::new();
-
-        let get_constraint_value = |mut constraints: std::slice::Iter<'_, ast::Constraint>,
-                                    id: &str|
-         -> Option<proc_macro2::TokenStream> {
-            constraints.find(|c| c.id == id).map(|c| constraint_to_value(&all_fields, c))
-        };
-
-        for child in children.iter() {
-            let tuple_values = constrained_fields
-                .iter()
-                .map(|id| {
-                    get_constraint_value(child.constraints(), id).map(|v| vec![v]).unwrap_or_else(
-                        || {
-                            self.scope
-                                .file
-                                .iter_children(child)
-                                .filter_map(|d| get_constraint_value(d.constraints(), id))
-                                .collect()
-                        },
-                    )
-                })
-                .collect::<Vec<_>>();
-
-            // If no constraint values are found for the tuple just skip the child
-            // packet as it would capture unwanted input packets.
-            if tuple_values.iter().all(|v| v.is_empty()) {
-                continue;
-            }
-
-            let tuple_values = tuple_values
-                .iter()
-                .map(|v| v.is_empty().then_some(quote!(_)).unwrap_or_else(|| quote!( #(#v)|* )))
-                .collect::<Vec<_>>();
-
-            let fields = find_constrained_parent_fields(self.scope, child.id().unwrap())
-                .iter()
-                .map(|field| field.id().unwrap().to_ident())
-                .collect::<Vec<_>>();
-
-            match_values.push(quote!( (#(#tuple_values),*) ));
-            child_parse_args.push(quote!( #(, #fields)*));
-            child_ids_data.push(format_ident!("{}Data", child.id().unwrap()));
-            child_ids.push(child.id().unwrap().to_ident());
-        }
-
-        let constrained_field_idents = constrained_fields.iter().map(|field| field.to_ident());
-        let packet_data_child = format_ident!("{}DataChild", self.packet_name);
-
-        // Parsing of packet children requires having a payload field;
-        // it is allowed to inherit from a packet with empty payload, in this
-        // case generate an empty payload value.
-        if !decl
-            .fields()
-            .any(|f| matches!(&f.desc, ast::FieldDesc::Payload { .. } | ast::FieldDesc::Body))
-        {
-            self.code.push(quote! {
-                let payload: &[u8] = &[];
-            })
-        }
-        self.code.push(quote! {
-            let child = match (#(#constrained_field_idents),*) {
-                #(#match_values if #child_ids_data::conforms(&payload) => {
-                    let mut cell = Cell::new(payload);
-                    let child_data = #child_ids_data::parse_inner(&mut cell #child_parse_args)?;
-                    // TODO(mgeisler): communicate back to user if !cell.get().is_empty()?
-                    #packet_data_child::#child_ids(child_data)
-                }),*
-                _ if !payload.is_empty() => {
-                    #packet_data_child::Payload(Bytes::copy_from_slice(payload))
-                }
-                _ => #packet_data_child::None,
-            };
-        });
-    }
 }
 
 impl quote::ToTokens for FieldParser<'_> {
     fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
-        let code = &self.code;
-        tokens.extend(quote! {
-            #(#code)*
-        });
+        tokens.extend(self.tokens.clone());
     }
 }
 
@@ -794,7 +808,7 @@
     /// # Panics
     ///
     /// Panics on parse errors.
-    pub fn parse_str(text: &str) -> analyzer_ast::File {
+    pub fn parse_str(text: &str) -> ast::File {
         let mut db = ast::SourceDatabase::new();
         let file = parse_inline(&mut db, "stdin", String::from(text)).expect("parse error");
         analyzer::analyze(&file).expect("analyzer error")
@@ -810,8 +824,9 @@
             ";
         let file = parse_str(code);
         let scope = analyzer::Scope::new(&file).unwrap();
+        let schema = analyzer::Schema::new(&file);
         let span = format_ident!("bytes");
-        let parser = FieldParser::new(&scope, file.endianness.value, "P", &span);
+        let parser = FieldParser::new(&scope, &schema, file.endianness.value, "P", &span);
         assert_eq!(parser.find_size_field("a"), None);
         assert_eq!(parser.find_count_field("a"), None);
     }
@@ -827,8 +842,9 @@
             ";
         let file = parse_str(code);
         let scope = analyzer::Scope::new(&file).unwrap();
+        let schema = analyzer::Schema::new(&file);
         let span = format_ident!("bytes");
-        let parser = FieldParser::new(&scope, file.endianness.value, "P", &span);
+        let parser = FieldParser::new(&scope, &schema, file.endianness.value, "P", &span);
         assert_eq!(parser.find_size_field("b"), None);
         assert_eq!(parser.find_count_field("b"), Some(format_ident!("b_count")));
     }
@@ -844,8 +860,9 @@
             ";
         let file = parse_str(code);
         let scope = analyzer::Scope::new(&file).unwrap();
+        let schema = analyzer::Schema::new(&file);
         let span = format_ident!("bytes");
-        let parser = FieldParser::new(&scope, file.endianness.value, "P", &span);
+        let parser = FieldParser::new(&scope, &schema, file.endianness.value, "P", &span);
         assert_eq!(parser.find_size_field("c"), Some(format_ident!("c_size")));
         assert_eq!(parser.find_count_field("c"), None);
     }
diff --git a/src/backends/rust/preamble.rs b/src/backends/rust/preamble.rs
index e9af398..bc64817 100644
--- a/src/backends/rust/preamble.rs
+++ b/src/backends/rust/preamble.rs
@@ -55,15 +55,14 @@
         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>;
+        use std::result::Result;
+        use pdl_runtime::{DecodeError, EncodeError, Packet};
 
         /// 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)]
+        #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
         pub struct Private<T>(T);
 
         impl<T> std::ops::Deref for Private<T> {
@@ -72,6 +71,12 @@
                 &self.0
             }
         }
+
+        impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                T::fmt(&self.0, f)
+            }
+        }
     }
 }
 
diff --git a/src/backends/rust/serializer.rs b/src/backends/rust/serializer.rs
index b83f7c8..c4b88e0 100644
--- a/src/backends/rust/serializer.rs
+++ b/src/backends/rust/serializer.rs
@@ -12,131 +12,229 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use crate::analyzer::ast as analyzer_ast;
 use crate::backends::rust::{mask_bits, types, ToIdent, ToUpperCamelCase};
 use crate::{analyzer, ast};
 use quote::{format_ident, quote};
 
-/// A single bit-field value.
-struct BitField {
-    value: proc_macro2::TokenStream, // An expression which produces a value.
-    field_type: types::Integer,      // The type of the value.
-    shift: usize,                    // A bit-shift to apply to `value`.
+/// Generate a range check for a scalar value backed to a rust type
+/// that exceeds the actual size of the PDL field.
+fn range_check(
+    value: proc_macro2::TokenStream,
+    width: usize,
+    packet_name: &str,
+    field_name: &str,
+) -> proc_macro2::TokenStream {
+    let max_value = mask_bits(width, "u64");
+    quote! {
+        if #value > #max_value {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: #packet_name,
+                field: #field_name,
+                value: #value as u64,
+                maximum_value: #max_value as u64,
+            })
+        }
+    }
 }
 
-pub struct FieldSerializer<'a> {
-    scope: &'a analyzer::Scope<'a>,
-    endianness: ast::EndiannessValue,
-    packet_name: &'a str,
-    span: &'a proc_macro2::Ident,
-    chunk: Vec<BitField>,
-    code: Vec<proc_macro2::TokenStream>,
+/// Represents the computed size of a packet,
+/// compoased of constant and variable size fields.
+struct RuntimeSize {
+    constant: usize,
+    variable: Vec<proc_macro2::TokenStream>,
+}
+
+impl RuntimeSize {
+    fn payload_size() -> Self {
+        RuntimeSize { constant: 0, variable: vec![quote! { self.payload.len() }] }
+    }
+}
+
+impl std::ops::AddAssign<&RuntimeSize> for RuntimeSize {
+    fn add_assign(&mut self, other: &RuntimeSize) {
+        self.constant += other.constant;
+        self.variable.extend_from_slice(&other.variable)
+    }
+}
+
+impl quote::ToTokens for RuntimeSize {
+    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
+        let constant = proc_macro2::Literal::usize_unsuffixed(self.constant);
+        tokens.extend(match self {
+            RuntimeSize { variable, .. } if variable.is_empty() => quote! { #constant },
+            RuntimeSize { variable, constant: 0 } => quote! { #(#variable)+* },
+            RuntimeSize { variable, .. } => quote! { #constant + #(#variable)+* },
+        })
+    }
+}
+
+/// Represents part of a compound bit-field.
+struct BitField {
+    value: proc_macro2::TokenStream,
+    field_type: types::Integer,
     shift: usize,
 }
 
-impl<'a> FieldSerializer<'a> {
+struct Encoder {
+    endianness: ast::EndiannessValue,
+    buf: proc_macro2::Ident,
+    packet_name: String,
+    packet_size: RuntimeSize,
+    payload_size: RuntimeSize,
+    tokens: proc_macro2::TokenStream,
+    bit_shift: usize,
+    bit_fields: Vec<BitField>,
+}
+
+impl Encoder {
     pub fn new(
-        scope: &'a analyzer::Scope<'a>,
         endianness: ast::EndiannessValue,
-        packet_name: &'a str,
-        span: &'a proc_macro2::Ident,
-    ) -> FieldSerializer<'a> {
-        FieldSerializer {
-            scope,
+        packet_name: &str,
+        buf: proc_macro2::Ident,
+        payload_size: RuntimeSize,
+    ) -> Self {
+        Encoder {
+            buf,
+            packet_name: packet_name.to_owned(),
             endianness,
-            packet_name,
-            span,
-            chunk: Vec::new(),
-            code: Vec::new(),
-            shift: 0,
+            packet_size: RuntimeSize { constant: 0, variable: vec![] },
+            payload_size,
+            tokens: quote! {},
+            bit_shift: 0,
+            bit_fields: vec![],
         }
     }
 
-    pub fn add(&mut self, field: &analyzer_ast::Field) {
-        match &field.desc {
-            _ if field.cond.is_some() => self.add_optional_field(field),
-            _ if self.scope.is_bitfield(field) => self.add_bit_field(field),
-            ast::FieldDesc::Array { id, width, .. } => self.add_array_field(
-                id,
-                *width,
-                field.annot.padded_size,
-                self.scope.get_type_declaration(field),
-            ),
-            ast::FieldDesc::Typedef { id, type_id } => {
-                self.add_typedef_field(id, type_id);
+    fn encode_typedef_field(
+        &mut self,
+        scope: &analyzer::Scope<'_>,
+        schema: &analyzer::Schema,
+        id: &str,
+        type_id: &str,
+    ) {
+        assert_eq!(self.bit_shift, 0, "Typedef field does not start on an octet boundary");
+
+        let decl = scope.typedef[type_id];
+        let id = id.to_ident();
+        let buf = &self.buf;
+
+        self.tokens.extend(match &decl.desc {
+            ast::DeclDesc::Checksum { .. } => todo!(),
+            ast::DeclDesc::CustomField { width: Some(width), .. } => {
+                let backing_type = types::Integer::new(*width);
+                let put_uint = types::put_uint(
+                    self.endianness,
+                    &quote! { #backing_type::from(self.#id) },
+                    *width,
+                    &self.buf,
+                );
+                quote! {
+                    #put_uint;
+                }
             }
-            ast::FieldDesc::Payload { .. } | ast::FieldDesc::Body { .. } => {
-                self.add_payload_field();
-            }
-            // Padding field handled in serialization of associated array field.
-            ast::FieldDesc::Padding { .. } => (),
-            _ => todo!("Cannot yet serialize {field:?}"),
+            ast::DeclDesc::Struct { .. } | ast::DeclDesc::CustomField { .. } => quote! {
+                self.#id.encode(#buf)?;
+            },
+            _ => todo!("{:?}", decl),
+        });
+
+        match schema.decl_size(decl.key) {
+            analyzer::Size::Static(s) => self.packet_size.constant += s,
+            _ => self.packet_size.variable.push(quote! { self.#id.encoded_len() }),
         }
     }
 
-    fn add_optional_field(&mut self, field: &analyzer_ast::Field) {
-        self.code.push(match &field.desc {
+    fn encode_optional_field(
+        &mut self,
+        scope: &analyzer::Scope<'_>,
+        _schema: &analyzer::Schema,
+        field: &ast::Field,
+    ) {
+        assert_eq!(self.bit_shift, 0, "Optional field does not start on an octet boundary");
+
+        self.tokens.extend(match &field.desc {
             ast::FieldDesc::Scalar { id, width } => {
-                let name = id;
+                let field_name = id;
                 let id = id.to_ident();
                 let backing_type = types::Integer::new(*width);
-                let write = types::put_uint(self.endianness, &quote!(*#id), *width, self.span);
-
-                let range_check = (backing_type.width > *width).then(|| {
-                    let packet_name = &self.packet_name;
-                    let max_value = mask_bits(*width, "u64");
-
-                    quote! {
-                        if *#id > #max_value {
-                            panic!(
-                                "Invalid value for {}::{}: {} > {}",
-                                #packet_name, #name, #id, #max_value
-                            );
-                        }
-                    }
-                });
-
+                let put_uint = types::put_uint(self.endianness, &quote!(*#id), *width, &self.buf);
+                let range_check = (backing_type.width > *width)
+                    .then(|| range_check(quote! { *#id }, *width, &self.packet_name, field_name));
                 quote! {
                     if let Some(#id) = &self.#id {
                         #range_check
-                        #write
+                        #put_uint;
                     }
                 }
             }
-            ast::FieldDesc::Typedef { id, type_id } => match &self.scope.typedef[type_id].desc {
+            ast::FieldDesc::Typedef { id, type_id } => match &scope.typedef[type_id].desc {
                 ast::DeclDesc::Enum { width, .. } => {
                     let id = id.to_ident();
                     let backing_type = types::Integer::new(*width);
-                    let write = types::put_uint(
+                    let put_uint = types::put_uint(
                         self.endianness,
                         &quote!(#backing_type::from(#id)),
                         *width,
-                        self.span,
+                        &self.buf,
                     );
+
                     quote! {
                         if let Some(#id) = &self.#id {
-                            #write
+                            #put_uint;
                         }
                     }
                 }
                 ast::DeclDesc::Struct { .. } => {
                     let id = id.to_ident();
-                    let span = self.span;
+                    let buf = &self.buf;
+
                     quote! {
                         if let Some(#id) = &self.#id {
-                            #id.write_to(#span);
+                            #id.encode(#buf)?;
                         }
                     }
                 }
                 _ => unreachable!(),
             },
             _ => unreachable!(),
+        });
+
+        self.packet_size.variable.push(match &field.desc {
+            ast::FieldDesc::Scalar { id, width } => {
+                let id = id.to_ident();
+                let size = width / 8;
+                quote! { if self.#id.is_some() { #size } else { 0 } }
+            }
+            ast::FieldDesc::Typedef { id, type_id } => match &scope.typedef[type_id].desc {
+                ast::DeclDesc::Enum { width, .. } => {
+                    let id = id.to_ident();
+                    let size = width / 8;
+                    quote! { if self.#id.is_some() { #size } else { 0 } }
+                }
+                ast::DeclDesc::Struct { .. } => {
+                    let id = id.to_ident();
+                    let type_id = type_id.to_ident();
+                    quote! {
+                        &self.#id
+                            .as_ref()
+                            .map(#type_id::encoded_len)
+                            .unwrap_or(0)
+                    }
+                }
+                _ => unreachable!(),
+            },
+            _ => unreachable!(),
         })
     }
 
-    fn add_bit_field(&mut self, field: &analyzer_ast::Field) {
-        let width = field.annot.size.static_().unwrap();
-        let shift = self.shift;
+    fn encode_bit_field(
+        &mut self,
+        scope: &analyzer::Scope<'_>,
+        schema: &analyzer::Schema,
+        field: &ast::Field,
+    ) {
+        let width = schema.field_size(field.key).static_().unwrap();
+        let shift = self.bit_shift;
 
         match &field.desc {
             ast::FieldDesc::Flag { optional_field_id, set_value, .. } => {
@@ -145,7 +243,7 @@
                     syn::parse_str::<syn::LitInt>(&format!("{}", set_value)).unwrap();
                 let cond_value_absent =
                     syn::parse_str::<syn::LitInt>(&format!("{}", 1 - set_value)).unwrap();
-                self.chunk.push(BitField {
+                self.bit_fields.push(BitField {
                     value: quote! {
                         if self.#optional_field_id.is_some() {
                             #cond_value_present
@@ -158,27 +256,28 @@
                 });
             }
             ast::FieldDesc::Scalar { id, width } => {
-                let field_name = id.to_ident();
+                let field_name = id;
+                let field_id = id.to_ident();
                 let field_type = types::Integer::new(*width);
                 if field_type.width > *width {
-                    let packet_name = &self.packet_name;
-                    let max_value = mask_bits(*width, "u64");
-                    self.code.push(quote! {
-                        if self.#field_name > #max_value {
-                            panic!(
-                                "Invalid value for {}::{}: {} > {}",
-                                #packet_name, #id, self.#field_name, #max_value
-                            );
-                        }
-                    });
+                    self.tokens.extend(range_check(
+                        quote! { self.#field_id() },
+                        *width,
+                        &self.packet_name,
+                        field_name,
+                    ));
                 }
-                self.chunk.push(BitField { value: quote!(self.#field_name), field_type, shift });
+                self.bit_fields.push(BitField {
+                    value: quote! { self.#field_id() },
+                    field_type,
+                    shift,
+                });
             }
             ast::FieldDesc::FixedEnum { enum_id, tag_id, .. } => {
                 let field_type = types::Integer::new(width);
                 let enum_id = enum_id.to_ident();
                 let tag_id = format_ident!("{}", tag_id.to_upper_camel_case());
-                self.chunk.push(BitField {
+                self.bit_fields.push(BitField {
                     value: quote!(#field_type::from(#enum_id::#tag_id)),
                     field_type,
                     shift,
@@ -187,13 +286,13 @@
             ast::FieldDesc::FixedScalar { value, .. } => {
                 let field_type = types::Integer::new(width);
                 let value = proc_macro2::Literal::usize_unsuffixed(*value);
-                self.chunk.push(BitField { value: quote!(#value), field_type, shift });
+                self.bit_fields.push(BitField { value: quote!(#value), field_type, shift });
             }
             ast::FieldDesc::Typedef { id, .. } => {
-                let field_name = id.to_ident();
+                let id = id.to_ident();
                 let field_type = types::Integer::new(width);
-                self.chunk.push(BitField {
-                    value: quote!(#field_type::from(self.#field_name)),
+                self.bit_fields.push(BitField {
+                    value: quote!(#field_type::from(self.#id())),
                     field_type,
                     shift,
                 });
@@ -205,9 +304,8 @@
                 let packet_name = &self.packet_name;
                 let max_value = mask_bits(*width, "usize");
 
-                let decl = self.scope.typedef.get(self.packet_name).unwrap();
-                let value_field = self
-                    .scope
+                let decl = scope.typedef.get(&self.packet_name).unwrap();
+                let value_field = scope
                     .iter_fields(decl)
                     .find(|field| match &field.desc {
                         ast::FieldDesc::Payload { .. } => field_id == "_payload_",
@@ -220,9 +318,7 @@
                 let field_type = types::Integer::new(*width);
                 // TODO: size modifier
 
-                let value_field_decl = self.scope.get_type_declaration(value_field);
-
-                let field_size_name = format_ident!("{field_id}_size");
+                let value_field_decl = scope.get_type_declaration(value_field);
                 let array_size = match (&value_field.desc, value_field_decl.map(|decl| &decl.desc))
                 {
                     (ast::FieldDesc::Payload { size_modifier: Some(size_modifier) }, _) => {
@@ -231,33 +327,29 @@
                                 .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) }
-                        }
+                        let payload_size = &self.payload_size;
+                        quote! { (#payload_size + #size_modifier) }
                     }
                     (ast::FieldDesc::Payload { .. } | ast::FieldDesc::Body { .. }, _) => {
-                        if let ast::DeclDesc::Packet { .. } = &decl.desc {
-                            quote! { self.child.get_total_size() }
-                        } else {
-                            quote! { self.payload.len() }
-                        }
+                        let payload_size = &self.payload_size;
+                        quote! { #payload_size }
                     }
                     (ast::FieldDesc::Array { width: Some(width), .. }, _)
                     | (ast::FieldDesc::Array { .. }, Some(ast::DeclDesc::Enum { width, .. })) => {
-                        let byte_width = syn::Index::from(width / 8);
-                        if byte_width.index == 1 {
+                        let size = width / 8;
+                        if size == 1 {
                             quote! { self.#field_name.len() }
                         } else {
-                            quote! { (self.#field_name.len() * #byte_width) }
+                            let size = proc_macro2::Literal::usize_unsuffixed(size);
+                            quote! { (self.#field_name.len() * #size) }
                         }
                     }
                     (ast::FieldDesc::Array { .. }, _) => {
-                        self.code.push(quote! {
+                        let field_size_name = format_ident!("{field_id}_size");
+                        self.tokens.extend(quote! {
                             let #field_size_name = self.#field_name
                                 .iter()
-                                .map(|elem| elem.get_size())
+                                .map(Packet::encoded_len)
                                 .sum::<usize>();
                         });
                         quote! { #field_size_name }
@@ -265,37 +357,79 @@
                     _ => panic!("Unexpected size field: {field:?}"),
                 };
 
-                self.code.push(quote! {
+                self.tokens.extend(quote! {
                     if #array_size > #max_value {
-                        panic!(
-                            "Invalid length for {}::{}: {} > {}",
-                            #packet_name, #field_id, #array_size, #max_value
-                        );
+                        return Err(EncodeError::SizeOverflow {
+                            packet: #packet_name,
+                            field: #field_id,
+                            size: #array_size,
+                            maximum_size: #max_value,
+                        })
                     }
                 });
 
-                self.chunk.push(BitField {
+                self.bit_fields.push(BitField {
                     value: quote!(#array_size as #field_type),
                     field_type,
                     shift,
                 });
             }
+            ast::FieldDesc::ElementSize { field_id, width, .. } => {
+                let field_name = field_id.to_ident();
+                let field_type = types::Integer::new(*width);
+                let field_element_size_name = format_ident!("{field_id}_element_size");
+                let packet_name = &self.packet_name;
+                let max_value = mask_bits(*width, "usize");
+                self.tokens.extend(quote! {
+                    let #field_element_size_name = self.#field_name
+                        .get(0)
+                        .map_or(0, Packet::encoded_len);
+
+                    for (element_index, element) in self.#field_name.iter().enumerate() {
+                        if element.encoded_len() != #field_element_size_name {
+                            return Err(EncodeError::InvalidArrayElementSize {
+                                packet: #packet_name,
+                                field: #field_id,
+                                size: element.encoded_len(),
+                                expected_size: #field_element_size_name,
+                                element_index,
+                            })
+                        }
+                    }
+                    if #field_element_size_name > #max_value {
+                        return Err(EncodeError::SizeOverflow {
+                            packet: #packet_name,
+                            field: #field_id,
+                            size: #field_element_size_name,
+                            maximum_size: #max_value,
+                        })
+                    }
+                    let #field_element_size_name = #field_element_size_name as #field_type;
+                });
+                self.bit_fields.push(BitField {
+                    value: quote!(#field_element_size_name),
+                    field_type,
+                    shift,
+                });
+            }
             ast::FieldDesc::Count { field_id, width, .. } => {
                 let field_name = field_id.to_ident();
                 let field_type = types::Integer::new(*width);
                 if field_type.width > *width {
                     let packet_name = &self.packet_name;
                     let max_value = mask_bits(*width, "usize");
-                    self.code.push(quote! {
+                    self.tokens.extend(quote! {
                         if self.#field_name.len() > #max_value {
-                            panic!(
-                                "Invalid length for {}::{}: {} > {}",
-                                #packet_name, #field_id, self.#field_name.len(), #max_value
-                            );
+                            return Err(EncodeError::CountOverflow {
+                                packet: #packet_name,
+                                field: #field_id,
+                                count: self.#field_name.len(),
+                                maximum_count: #max_value,
+                            })
                         }
                     });
                 }
-                self.chunk.push(BitField {
+                self.bit_fields.push(BitField {
                     value: quote!(self.#field_name.len() as #field_type),
                     field_type,
                     shift,
@@ -304,17 +438,17 @@
             _ => todo!("{field:?}"),
         }
 
-        self.shift += width;
-        if self.shift % 8 == 0 {
+        self.bit_shift += width;
+        if self.bit_shift % 8 == 0 {
             self.pack_bit_fields()
         }
     }
 
     fn pack_bit_fields(&mut self) {
-        assert_eq!(self.shift % 8, 0);
-        let chunk_type = types::Integer::new(self.shift);
+        assert_eq!(self.bit_shift % 8, 0);
+        let chunk_type = types::Integer::new(self.bit_shift);
         let values = self
-            .chunk
+            .bit_fields
             .drain(..)
             .map(|BitField { mut value, field_type, shift }| {
                 if field_type.width != chunk_type.width {
@@ -331,44 +465,52 @@
             })
             .collect::<Vec<_>>();
 
-        match values.as_slice() {
+        self.tokens.extend(match values.as_slice() {
             [] => {
-                let span = format_ident!("{}", self.span);
-                let count = syn::Index::from(self.shift / 8);
-                self.code.push(quote! {
-                    #span.put_bytes(0, #count);
-                });
+                let buf = format_ident!("{}", self.buf);
+                let count = proc_macro2::Literal::usize_unsuffixed(self.bit_shift / 8);
+                quote! {
+                    #buf.put_bytes(0, #count);
+                }
             }
             [value] => {
-                let put = types::put_uint(self.endianness, value, self.shift, self.span);
-                self.code.push(quote! {
+                let put = types::put_uint(self.endianness, value, self.bit_shift, &self.buf);
+                quote! {
                     #put;
-                });
+                }
             }
             _ => {
-                let put = types::put_uint(self.endianness, &quote!(value), self.shift, self.span);
-                self.code.push(quote! {
+                let put =
+                    types::put_uint(self.endianness, &quote!(value), self.bit_shift, &self.buf);
+                quote! {
                     let value = #(#values)|*;
                     #put;
-                });
+                }
             }
-        }
+        });
 
-        self.shift = 0;
+        self.packet_size.constant += self.bit_shift / 8;
+        self.bit_shift = 0;
     }
 
-    fn add_array_field(
+    fn encode_array_field(
         &mut self,
+        _scope: &analyzer::Scope<'_>,
+        schema: &analyzer::Schema,
         id: &str,
         width: Option<usize>,
         padding_size: Option<usize>,
-        decl: Option<&analyzer_ast::Decl>,
+        decl: Option<&ast::Decl>,
     ) {
-        let span = format_ident!("{}", self.span);
-        let serialize = match width {
+        assert_eq!(self.bit_shift, 0, "Array field does not start on an octet boundary");
+
+        let buf = &self.buf;
+
+        // Code to encode one array element.
+        let put_element = match width {
             Some(width) => {
                 let value = quote!(*elem);
-                types::put_uint(self.endianness, &value, width, self.span)
+                types::put_uint(self.endianness, &value, width, &self.buf)
             }
             None => {
                 if let Some(ast::DeclDesc::Enum { width, .. }) = decl.map(|decl| &decl.desc) {
@@ -377,112 +519,175 @@
                         self.endianness,
                         &quote!(#element_type::from(elem)),
                         *width,
-                        self.span,
+                        &self.buf,
                     )
                 } else {
                     quote! {
-                        elem.write_to(#span)
+                        elem.encode(#buf)?
                     }
                 }
             }
         };
 
+        let packet_name = &self.packet_name;
+        let field_name = id;
         let id = id.to_ident();
 
-        self.code.push(match padding_size {
-            Some(padding_size) =>
-                quote! {
-                    let current_size = #span.len();
-                    for elem in &self.#id {
-                        #serialize;
-                    }
-                    let array_size = #span.len() - current_size;
-                    if array_size > #padding_size {
-                        panic!("attempted to serialize an array larger than the enclosing padding size");
-                    }
-                    #span.put_bytes(0, #padding_size - array_size);
-                },
-            None =>
-                quote! {
-                    for elem in &self.#id {
-                        #serialize;
-                    }
-                }
-        });
-    }
+        let element_width = match &width {
+            Some(width) => Some(*width),
+            None => schema.decl_size(decl.unwrap().key).static_(),
+        };
 
-    fn add_typedef_field(&mut self, id: &str, type_id: &str) {
-        assert_eq!(self.shift, 0, "Typedef field does not start on an octet boundary");
-        let decl = self.scope.typedef[type_id];
-        if let ast::DeclDesc::Struct { parent_id: Some(_), .. } = &decl.desc {
-            panic!("Derived struct used in typedef field");
-        }
-
-        let id = id.to_ident();
-        let span = format_ident!("{}", self.span);
-
-        self.code.push(match &decl.desc {
-            ast::DeclDesc::Checksum { .. } => todo!(),
-            ast::DeclDesc::CustomField { width: Some(width), .. } => {
-                let backing_type = types::Integer::new(*width);
-                let put_uint = types::put_uint(
-                    self.endianness,
-                    &quote! { #backing_type::from(self.#id) },
-                    *width,
-                    self.span,
-                );
+        let array_size = match element_width {
+            Some(element_width) => {
+                let element_size = proc_macro2::Literal::usize_unsuffixed(element_width / 8);
+                quote! { self.#id.len() * #element_size }
+            }
+            _ => {
                 quote! {
-                    #put_uint;
+                    self.#id
+                        .iter()
+                        .map(Packet::encoded_len)
+                        .sum::<usize>()
                 }
             }
-            ast::DeclDesc::Struct { .. } => quote! {
-                self.#id.write_to(#span);
-            },
-            _ => unreachable!(),
-        });
-    }
+        };
 
-    fn add_payload_field(&mut self) {
-        if self.shift != 0 && self.endianness == ast::EndiannessValue::BigEndian {
-            panic!("Payload field does not start on an octet boundary");
-        }
-
-        let decl = self.scope.typedef[self.packet_name];
-        let is_packet = matches!(&decl.desc, ast::DeclDesc::Packet { .. });
-
-        let child_ids = self
-            .scope
-            .iter_children(decl)
-            .map(|child| child.id().unwrap().to_ident())
-            .collect::<Vec<_>>();
-
-        let span = format_ident!("{}", self.span);
-        if self.shift == 0 {
-            if is_packet {
-                let packet_data_child = format_ident!("{}DataChild", self.packet_name);
-                self.code.push(quote! {
-                    match &self.child {
-                        #(#packet_data_child::#child_ids(child) => child.write_to(#span),)*
-                        #packet_data_child::Payload(payload) => #span.put_slice(payload),
-                        #packet_data_child::None => {},
-                    }
-                })
-            } else {
-                self.code.push(quote! {
-                    #span.put_slice(&self.payload);
-                });
+        self.tokens.extend(if let Some(padding_size) = padding_size {
+            let padding_octets = padding_size / 8;
+            quote! {
+                let array_size = #array_size;
+                if array_size > #padding_octets {
+                    return Err(EncodeError::SizeOverflow {
+                        packet: #packet_name,
+                        field: #field_name,
+                        size: array_size,
+                        maximum_size: #padding_octets,
+                    })
+                }
+                for elem in &self.#id {
+                    #put_element;
+                }
+                #buf.put_bytes(0, #padding_octets - array_size);
             }
         } else {
-            todo!("Shifted payloads");
+            quote! {
+                for elem in &self.#id {
+                    #put_element;
+                }
+            }
+        });
+
+        self.packet_size.variable.push(array_size)
+    }
+
+    fn encode_field(
+        &mut self,
+        scope: &analyzer::Scope<'_>,
+        schema: &analyzer::Schema,
+        payload: &proc_macro2::TokenStream,
+        field: &ast::Field,
+    ) {
+        match &field.desc {
+            _ if field.cond.is_some() => self.encode_optional_field(scope, schema, field),
+            _ if scope.is_bitfield(field) => self.encode_bit_field(scope, schema, field),
+            ast::FieldDesc::Array { id, width, .. } => self.encode_array_field(
+                scope,
+                schema,
+                id,
+                *width,
+                schema.padded_size(field.key),
+                scope.get_type_declaration(field),
+            ),
+            ast::FieldDesc::Typedef { id, type_id } => {
+                self.encode_typedef_field(scope, schema, id, type_id)
+            }
+            ast::FieldDesc::Payload { .. } | ast::FieldDesc::Body { .. } => {
+                self.tokens.extend(payload.clone());
+                self.packet_size += &self.payload_size
+            }
+            // Padding field handled in serialization of associated array field.
+            ast::FieldDesc::Padding { .. } => (),
+            _ => todo!("Cannot yet serialize {field:?}"),
         }
     }
 }
 
-impl quote::ToTokens for FieldSerializer<'_> {
-    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
-        let code = &self.code;
-        tokens.extend(quote! {
-            #(#code)*
-        });
+fn encode_with_parents(
+    scope: &analyzer::Scope<'_>,
+    schema: &analyzer::Schema,
+    endianness: ast::EndiannessValue,
+    buf: proc_macro2::Ident,
+    decl: &ast::Decl,
+    payload_size: RuntimeSize,
+    payload: proc_macro2::TokenStream,
+) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
+    let packet_name = decl.id().unwrap();
+    let mut encoder = Encoder::new(endianness, packet_name, buf.clone(), payload_size);
+    for field in decl.fields() {
+        encoder.encode_field(scope, schema, &payload, field);
     }
+
+    match scope.get_parent(decl) {
+        Some(parent_decl) => encode_with_parents(
+            scope,
+            schema,
+            endianness,
+            buf,
+            parent_decl,
+            encoder.packet_size,
+            encoder.tokens,
+        ),
+        None => {
+            let packet_size = encoder.packet_size;
+            (encoder.tokens, quote! { #packet_size })
+        }
+    }
+}
+
+pub fn encode(
+    scope: &analyzer::Scope<'_>,
+    schema: &analyzer::Schema,
+    endianness: ast::EndiannessValue,
+    buf: proc_macro2::Ident,
+    decl: &ast::Decl,
+) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
+    encode_with_parents(
+        scope,
+        schema,
+        endianness,
+        buf.clone(),
+        decl,
+        RuntimeSize::payload_size(),
+        quote! { #buf.put_slice(&self.payload); },
+    )
+}
+
+pub fn encode_partial(
+    scope: &analyzer::Scope<'_>,
+    schema: &analyzer::Schema,
+    endianness: ast::EndiannessValue,
+    buf: proc_macro2::Ident,
+    decl: &ast::Decl,
+) -> (proc_macro2::TokenStream, proc_macro2::TokenStream, proc_macro2::TokenStream) {
+    let parent_decl = scope.get_parent(decl).unwrap();
+
+    let mut encoder =
+        Encoder::new(endianness, decl.id().unwrap(), buf.clone(), RuntimeSize::payload_size());
+
+    for field in decl.fields() {
+        encoder.encode_field(scope, schema, &quote! { #buf.put_slice(&self.payload); }, field);
+    }
+
+    let (encode_parents, encoded_len) = encode_with_parents(
+        scope,
+        schema,
+        endianness,
+        buf,
+        parent_decl,
+        encoder.packet_size,
+        quote! { self.encode_partial(buf)?; },
+    );
+
+    (encoder.tokens, encode_parents, encoded_len)
 }
diff --git a/src/bin/generate-canonical-tests.rs b/src/backends/rust/test.rs
similarity index 86%
copy from src/bin/generate-canonical-tests.rs
copy to src/backends/rust/test.rs
index 1e18490..0805024 100644
--- a/src/bin/generate-canonical-tests.rs
+++ b/src/backends/rust/test.rs
@@ -58,14 +58,13 @@
     syn::parse_str::<syn::LitStr>(&format!("r#\" {json} \"#")).unwrap()
 }
 
-fn generate_unit_tests(input: &str, packet_names: &[&str], module_name: &str) {
+fn generate_unit_tests(input: &str, packet_names: &[&str]) -> Result<String, String> {
     eprintln!("Reading test vectors from {input}, will use {} packets", packet_names.len());
 
     let data = std::fs::read_to_string(input)
         .unwrap_or_else(|err| panic!("Could not read {input}: {err}"));
     let packets: Vec<Packet> = serde_json::from_str(&data).expect("Could not parse JSON");
 
-    let module = syn::parse_str::<syn::Path>(module_name).unwrap();
     let mut tests = Vec::new();
     for packet in &packets {
         for (i, test_vector) in packet.tests.iter().enumerate() {
@@ -90,13 +89,12 @@
             );
             let packed = hexadecimal_to_vec(&test_vector.packed);
             let packet_name = format_ident!("{}", test_packet);
-            let builder_name = format_ident!("{}Builder", test_packet);
 
             let object = test_vector.unpacked.as_object().unwrap_or_else(|| {
                 panic!("Expected test vector object, found: {}", test_vector.unpacked)
             });
             let assertions = object.iter().map(|(key, value)| {
-                let getter = format_ident!("get_{key}");
+                let getter = format_ident!("{key}");
                 let expected = format_ident!("expected_{key}");
                 let json = to_json(&value);
                 quote! {
@@ -111,17 +109,16 @@
                 #[test]
                 fn #parse_test_name() {
                     let packed = #packed;
-                    let actual = #module::#packet_name::parse(&packed).unwrap();
+                    let actual = #packet_name::decode_full(&packed).unwrap();
                     #(#assertions)*
                 }
 
                 #[test]
                 fn #serialize_test_name() {
-                    let builder: #module::#builder_name = serde_json::from_str(#json)
-                        .expect("Could not create builder from canonical JSON data");
-                    let packet = builder.build();
+                    let packet: #packet_name = serde_json::from_str(#json)
+                        .expect("Could not create packet from canonical JSON data");
                     let packed: Vec<u8> = #packed;
-                    assert_eq!(packet.to_vec(), packed);
+                    assert_eq!(packet.encode_to_vec(), Ok(packed));
                 }
             });
         }
@@ -129,24 +126,25 @@
 
     // TODO(mgeisler): make the generated code clean from warnings.
     let code = quote! {
-        #![allow(warnings, missing_docs)]
+        #[allow(warnings, missing_docs)]
+        #[cfg(test)]
+        mod test {
+            use pdl_runtime::Packet;
+            use serde_json::json;
+            use super::*;
 
-        use pdl_runtime::Packet;
-        use serde_json::json;
-
-        #(#tests)*
+            #(#tests)*
+        }
     };
     let syntax_tree = syn::parse2::<syn::File>(code).expect("Could not parse {code:#?}");
-    println!("{}", prettyplease::unparse(&syntax_tree));
+    Ok(prettyplease::unparse(&syntax_tree))
 }
 
-fn main() {
-    let input_path = std::env::args().nth(1).expect("Need path to JSON file with test vectors");
-    let module_name = std::env::args().nth(2).expect("Need name for the generated module");
+pub fn generate_tests(input_file: &str) -> Result<String, String> {
     // TODO(mgeisler): remove the `packet_names` argument when we
     // support all canonical packets.
     generate_unit_tests(
-        &input_path,
+        input_file,
         &[
             "EnumChild_A",
             "EnumChild_B",
@@ -174,6 +172,10 @@
             "Packet_Array_Field_UnsizedElement_VariableSize",
             "Packet_Array_Field_SizedElement_VariableSize_Padded",
             "Packet_Array_Field_UnsizedElement_VariableCount_Padded",
+            "Packet_Array_Field_VariableElementSize_ConstantSize",
+            "Packet_Array_Field_VariableElementSize_VariableSize",
+            "Packet_Array_Field_VariableElementSize_VariableCount",
+            "Packet_Array_Field_VariableElementSize_UnknownSize",
             "Packet_Optional_Scalar_Field",
             "Packet_Optional_Enum_Field",
             "Packet_Optional_Struct_Field",
@@ -241,7 +243,13 @@
             "Struct_FixedScalar_Field",
             "Struct_Size_Field",
             "Struct_Struct_Field",
+            "Enum_Incomplete_Truncated_Closed",
+            "Enum_Incomplete_Truncated_Open",
+            "Enum_Incomplete_Truncated_Closed_WithRange",
+            "Enum_Incomplete_Truncated_Open_WithRange",
+            "Enum_Complete_Truncated",
+            "Enum_Complete_Truncated_WithRange",
+            "Enum_Complete_WithRange",
         ],
-        &module_name,
-    );
+    )
 }
diff --git a/src/backends/rust/types.rs b/src/backends/rust/types.rs
index 799cd4e..5c30d10 100644
--- a/src/backends/rust/types.rs
+++ b/src/backends/rust/types.rs
@@ -14,9 +14,8 @@
 
 //! Utility functions for dealing with Rust integer types.
 
-use crate::analyzer::ast as analyzer_ast;
+use crate::ast;
 use crate::backends::rust::ToIdent;
-use crate::{analyzer, ast};
 use quote::{format_ident, quote};
 
 /// A Rust integer type such as `u8`.
@@ -49,7 +48,7 @@
     }
 }
 
-pub fn rust_type(field: &analyzer_ast::Field) -> proc_macro2::TokenStream {
+pub fn rust_type(field: &ast::Field) -> proc_macro2::TokenStream {
     match &field.desc {
         ast::FieldDesc::Scalar { width, .. } if field.cond.is_some() => {
             let field_type = Integer::new(*width);
@@ -90,23 +89,6 @@
     }
 }
 
-pub fn rust_borrow(
-    field: &analyzer_ast::Field,
-    scope: &analyzer::Scope<'_>,
-) -> proc_macro2::TokenStream {
-    match &field.desc {
-        ast::FieldDesc::Scalar { .. } => quote!(),
-        ast::FieldDesc::Typedef { type_id, .. } => match &scope.typedef[type_id].desc {
-            ast::DeclDesc::Enum { .. } => quote!(),
-            ast::DeclDesc::Struct { .. } => quote!(&),
-            ast::DeclDesc::CustomField { .. } => quote!(),
-            desc => unreachable!("unexpected declaration: {desc:?}"),
-        },
-        ast::FieldDesc::Array { .. } => quote!(&),
-        _ => todo!(),
-    }
-}
-
 /// Suffix for `Buf::get_*` and `BufMut::put_*` methods when reading a
 /// value with the given `width`.
 fn endianness_suffix(endianness: ast::EndiannessValue, width: usize) -> &'static str {
@@ -131,14 +113,14 @@
     if value_type.width == width {
         let get_u = format_ident!("get_u{}{}", value_type.width, suffix);
         quote! {
-            #span.get_mut().#get_u()
+            #span.#get_u()
         }
     } else {
         let get_uint = format_ident!("get_uint{}", suffix);
         let value_nbytes = proc_macro2::Literal::usize_unsuffixed(width / 8);
         let cast = (value_type.width < 64).then(|| quote!(as #value_type));
         quote! {
-            #span.get_mut().#get_uint(#value_nbytes) #cast
+            #span.#get_uint(#value_nbytes) #cast
         }
     }
 }
diff --git a/src/backends/rust.rs b/src/backends/rust_legacy/mod.rs
similarity index 93%
rename from src/backends/rust.rs
rename to src/backends/rust_legacy/mod.rs
index 6609482..5883487 100644
--- a/src/backends/rust.rs
+++ b/src/backends/rust_legacy/mod.rs
@@ -21,11 +21,10 @@
 use std::path::Path;
 use syn::LitInt;
 
-use crate::analyzer::ast as analyzer_ast;
-
 mod parser;
 mod preamble;
 mod serializer;
+pub mod test;
 mod types;
 
 use parser::FieldParser;
@@ -54,17 +53,6 @@
     }
 }
 
-/// Generate a block of code.
-///
-/// Like `quote!`, but the code block will be followed by an empty
-/// line of code. This makes the generated code more readable.
-#[macro_export]
-macro_rules! quote_block {
-    ($($tt:tt)*) => {
-        format!("{}\n\n", ::quote::quote!($($tt)*))
-    }
-}
-
 /// Generate a bit-mask which masks out `n` least significant bits.
 ///
 /// Literal integers in Rust default to the `i32` type. For this
@@ -86,14 +74,17 @@
 
 fn generate_packet_size_getter<'a>(
     scope: &analyzer::Scope<'a>,
-    fields: impl Iterator<Item = &'a analyzer_ast::Field>,
+    schema: &analyzer::Schema,
+    fields: impl Iterator<Item = &'a ast::Field>,
     is_packet: bool,
 ) -> (usize, proc_macro2::TokenStream) {
     let mut constant_width = 0;
     let mut dynamic_widths = Vec::new();
 
     for field in fields {
-        if let Some(width) = field.annot.static_() {
+        if let Some(width) =
+            schema.padded_size(field.key).or(schema.field_size(field.key).static_())
+        {
             constant_width += width;
             continue;
         }
@@ -142,7 +133,7 @@
             ast::FieldDesc::Array { id, width, .. } => {
                 let id = id.to_ident();
                 match &decl {
-                    Some(analyzer_ast::Decl {
+                    Some(ast::Decl {
                         desc: ast::DeclDesc::Struct { .. } | ast::DeclDesc::CustomField { .. },
                         ..
                     }) => {
@@ -150,9 +141,7 @@
                             self.#id.iter().map(|elem| elem.get_size()).sum::<usize>()
                         }
                     }
-                    Some(analyzer_ast::Decl {
-                        desc: ast::DeclDesc::Enum { width, .. }, ..
-                    }) => {
+                    Some(ast::Decl { desc: ast::DeclDesc::Enum { width, .. }, .. }) => {
                         let width = syn::Index::from(width / 8);
                         let mul_width = (width.index > 1).then(|| quote!(* #width));
                         quote! {
@@ -188,10 +177,7 @@
     )
 }
 
-fn top_level_packet<'a>(
-    scope: &analyzer::Scope<'a>,
-    packet_name: &'a str,
-) -> &'a analyzer_ast::Decl {
+fn top_level_packet<'a>(scope: &analyzer::Scope<'a>, packet_name: &'a str) -> &'a ast::Decl {
     let mut decl = scope.typedef[packet_name];
     while let ast::DeclDesc::Packet { parent_id: Some(parent_id), .. }
     | ast::DeclDesc::Struct { parent_id: Some(parent_id), .. } = &decl.desc
@@ -209,8 +195,8 @@
 fn find_constrained_parent_fields<'a>(
     scope: &analyzer::Scope<'a>,
     id: &str,
-) -> Vec<&'a analyzer_ast::Field> {
-    let all_parent_fields: HashMap<String, &'a analyzer_ast::Field> = HashMap::from_iter(
+) -> Vec<&'a ast::Field> {
+    let all_parent_fields: HashMap<String, &'a ast::Field> = HashMap::from_iter(
         scope
             .iter_parent_fields(scope.typedef[id])
             .filter_map(|f| f.id().map(|id| (id.to_string(), f))),
@@ -244,6 +230,7 @@
 /// how to parse and serialize its own fields.
 fn generate_data_struct(
     scope: &analyzer::Scope<'_>,
+    schema: &analyzer::Schema,
     endianness: ast::EndiannessValue,
     id: &str,
 ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
@@ -252,8 +239,9 @@
 
     let span = format_ident!("bytes");
     let serializer_span = format_ident!("buffer");
-    let mut field_parser = FieldParser::new(scope, endianness, id, &span);
-    let mut field_serializer = FieldSerializer::new(scope, endianness, id, &serializer_span);
+    let mut field_parser = FieldParser::new(scope, schema, endianness, id, &span);
+    let mut field_serializer =
+        FieldSerializer::new(scope, schema, endianness, id, &serializer_span);
     for field in decl.fields() {
         field_parser.add(field);
         field_serializer.add(field);
@@ -270,7 +258,7 @@
     };
 
     let (constant_width, packet_size) =
-        generate_packet_size_getter(scope, decl.fields(), is_packet);
+        generate_packet_size_getter(scope, schema, decl.fields(), is_packet);
     let conforms = if constant_width == 0 {
         quote! { true }
     } else {
@@ -319,7 +307,7 @@
 
             #visibility fn parse(
                 #span: &[u8] #(, #parse_arg_names: #parse_arg_types)*
-            ) -> Result<Self> {
+            ) -> Result<Self, DecodeError> {
                 let mut cell = Cell::new(#span);
                 let packet = Self::parse_inner(&mut cell #(, #parse_arg_names)*)?;
                 // TODO(mgeisler): communicate back to user if !cell.get().is_empty()?
@@ -328,15 +316,16 @@
 
             fn parse_inner(
                 mut #span: &mut Cell<&[u8]> #(, #parse_arg_names: #parse_arg_types)*
-            ) -> Result<Self> {
+            ) -> Result<Self, DecodeError> {
                 #field_parser
                 Ok(Self {
                     #(#field_names,)*
                 })
             }
 
-            fn write_to(&self, buffer: &mut BytesMut) {
+            fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
                 #field_serializer
+                Ok(())
             }
 
             fn get_total_size(&self) -> usize {
@@ -355,7 +344,7 @@
 /// Turn the constraint into a value (such as `10` or
 /// `SomeEnum::Foo`).
 pub fn constraint_to_value(
-    all_fields: &HashMap<String, &'_ analyzer_ast::Field>,
+    all_fields: &HashMap<String, &'_ ast::Field>,
     constraint: &ast::Constraint,
 ) -> proc_macro2::TokenStream {
     match constraint {
@@ -380,6 +369,7 @@
 /// Generate code for a `ast::Decl::Packet`.
 fn generate_packet_decl(
     scope: &analyzer::Scope<'_>,
+    schema: &analyzer::Schema,
     endianness: ast::EndiannessValue,
     id: &str,
 ) -> proc_macro2::TokenStream {
@@ -587,15 +577,15 @@
             )*
 
             impl TryFrom<#top_level_packet> for #id_packet {
-                type Error = Error;
-                fn try_from(packet: #top_level_packet) -> Result<#id_packet> {
+                type Error = DecodeError;
+                fn try_from(packet: #top_level_packet) -> Result<#id_packet, Self::Error> {
                     #id_packet::new(packet.#top_level_id_lower)
                 }
             }
         }
     });
 
-    let (data_struct_decl, data_struct_impl) = generate_data_struct(scope, endianness, id);
+    let (data_struct_decl, data_struct_impl) = generate_data_struct(scope, schema, endianness, id);
 
     quote! {
         #child_declaration
@@ -621,51 +611,53 @@
         #data_struct_impl
 
         impl Packet for #id_packet {
-            fn to_bytes(self) -> Bytes {
-                let mut buffer = BytesMut::with_capacity(self.#top_level_id_lower.get_size());
-                self.#top_level_id_lower.write_to(&mut buffer);
-                buffer.freeze()
+            fn encoded_len(&self) -> usize {
+                self.get_size()
             }
-
-            fn to_vec(self) -> Vec<u8> {
-                self.to_bytes().to_vec()
+            fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+                self.#top_level_id_lower.write_to(buf)
+            }
+            fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+                unimplemented!("Rust legacy does not implement full packet trait")
             }
         }
 
-        impl From<#id_packet> for Bytes {
-            fn from(packet: #id_packet) -> Self {
-                packet.to_bytes()
+        impl TryFrom<#id_packet> for Bytes {
+            type Error = EncodeError;
+            fn try_from(packet: #id_packet) -> Result<Self, Self::Error> {
+                packet.encode_to_bytes()
             }
         }
 
-        impl From<#id_packet> for Vec<u8> {
-            fn from(packet: #id_packet) -> Self {
-                packet.to_vec()
+        impl TryFrom<#id_packet> for Vec<u8> {
+            type Error = EncodeError;
+            fn try_from(packet: #id_packet) -> Result<Self, Self::Error> {
+                packet.encode_to_vec()
             }
         }
 
         #impl_from_and_try_from
 
         impl #id_packet {
-            pub fn parse(#span: &[u8]) -> Result<Self> {
+            pub fn parse(#span: &[u8]) -> Result<Self, DecodeError> {
                 let mut cell = Cell::new(#span);
                 let packet = Self::parse_inner(&mut cell)?;
                 // TODO(mgeisler): communicate back to user if !cell.get().is_empty()?
                 Ok(packet)
             }
 
-            fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self> {
+            fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
                 let data = #top_level_data::parse_inner(&mut bytes)?;
                 Self::new(data)
             }
 
             #specialize
 
-            fn new(#top_level_id_lower: #top_level_data) -> Result<Self> {
+            fn new(#top_level_id_lower: #top_level_data) -> Result<Self, DecodeError> {
                 #(
                     let #parent_shifted_lower_ids = match &#parent_lower_ids.child {
                         #parent_data_child::#parent_shifted_ids(value) => value.clone(),
-                        _ => return Err(Error::InvalidChildError {
+                        _ => return Err(DecodeError::InvalidChildError {
                             expected: stringify!(#parent_data_child::#parent_shifted_ids),
                             actual: format!("{:?}", &#parent_lower_ids.child),
                         }),
@@ -680,7 +672,7 @@
 
             #get_payload
 
-            fn write_to(&self, buffer: &mut BytesMut) {
+            fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
                 self.#id_lower.write_to(buffer)
             }
 
@@ -709,10 +701,11 @@
 /// Generate code for a `ast::Decl::Struct`.
 fn generate_struct_decl(
     scope: &analyzer::Scope<'_>,
+    schema: &analyzer::Schema,
     endianness: ast::EndiannessValue,
     id: &str,
 ) -> proc_macro2::TokenStream {
-    let (struct_decl, struct_impl) = generate_data_struct(scope, endianness, id);
+    let (struct_decl, struct_impl) = generate_data_struct(scope, schema, endianness, id);
     quote! {
         #struct_decl
         #struct_impl
@@ -904,7 +897,7 @@
 
         impl TryFrom<#backing_type> for #name {
             type Error = #backing_type;
-            fn try_from(value: #backing_type) -> std::result::Result<Self, Self::Error> {
+            fn try_from(value: #backing_type) -> Result<Self, Self::Error> {
                 match value {
                     #(#from_cases,)*
                 }
@@ -982,7 +975,7 @@
 
             impl TryFrom<#backing_type> for #id {
                 type Error = #backing_type;
-                fn try_from(value: #backing_type) -> std::result::Result<Self, Self::Error> {
+                fn try_from(value: #backing_type) -> Result<Self, Self::Error> {
                     if value > #max_value {
                         Err(value)
                     } else {
@@ -996,18 +989,21 @@
 
 fn generate_decl(
     scope: &analyzer::Scope<'_>,
-    file: &analyzer_ast::File,
-    decl: &analyzer_ast::Decl,
+    schema: &analyzer::Schema,
+    file: &ast::File,
+    decl: &ast::Decl,
 ) -> proc_macro2::TokenStream {
     match &decl.desc {
-        ast::DeclDesc::Packet { id, .. } => generate_packet_decl(scope, file.endianness.value, id),
+        ast::DeclDesc::Packet { id, .. } => {
+            generate_packet_decl(scope, schema, file.endianness.value, id)
+        }
         ast::DeclDesc::Struct { id, parent_id: None, .. } => {
             // TODO(mgeisler): handle structs with parents. We could
             // generate code for them, but the code is not useful
             // since it would require the caller to unpack everything
             // manually. We either need to change the API, or
             // implement the recursive (de)serialization.
-            generate_struct_decl(scope, file.endianness.value, id)
+            generate_struct_decl(scope, schema, file.endianness.value, id)
         }
         ast::DeclDesc::Enum { id, tags, width } => generate_enum_decl(id, tags, *width),
         ast::DeclDesc::CustomField { id, width: Some(width), .. } => {
@@ -1023,13 +1019,14 @@
 /// readable source code.
 pub fn generate_tokens(
     sources: &ast::SourceDatabase,
-    file: &analyzer_ast::File,
+    file: &ast::File,
 ) -> proc_macro2::TokenStream {
     let source = sources.get(file.file).expect("could not read source");
     let preamble = preamble::generate(Path::new(source.name()));
 
     let scope = analyzer::Scope::new(file).expect("could not create scope");
-    let decls = file.declarations.iter().map(|decl| generate_decl(&scope, file, decl));
+    let schema = analyzer::Schema::new(file);
+    let decls = file.declarations.iter().map(|decl| generate_decl(&scope, &schema, file, decl));
     quote! {
         #preamble
 
@@ -1041,7 +1038,7 @@
 ///
 /// The code is not formatted, pipe it through `rustfmt` to get
 /// readable source code.
-pub fn generate(sources: &ast::SourceDatabase, file: &analyzer_ast::File) -> String {
+pub fn generate(sources: &ast::SourceDatabase, file: &ast::File) -> String {
     let syntax_tree = syn::parse2(generate_tokens(sources, file)).expect("Could not parse code");
     prettyplease::unparse(&syntax_tree)
 }
@@ -1061,7 +1058,7 @@
     /// # Panics
     ///
     /// Panics on parse errors.
-    pub fn parse_str(text: &str) -> analyzer_ast::File {
+    pub fn parse_str(text: &str) -> ast::File {
         let mut db = ast::SourceDatabase::new();
         let file = parse_inline(&mut db, "stdin", String::from(text)).expect("parse error");
         analyzer::analyze(&file).expect("analyzer error")
@@ -1132,7 +1129,7 @@
                     let file = analyzer::analyze(&file).unwrap();
                     let actual_code = generate(&db, &file);
                     assert_snapshot_eq(
-                        &format!("tests/generated/{name}_{endianness}.rs"),
+                        &format!("tests/generated/rust_legacy/{name}_{endianness}.rs"),
                         &format_rust(&actual_code),
                     );
                 }
diff --git a/src/backends/rust_legacy/parser.rs b/src/backends/rust_legacy/parser.rs
new file mode 100644
index 0000000..0558411
--- /dev/null
+++ b/src/backends/rust_legacy/parser.rs
@@ -0,0 +1,861 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use crate::backends::rust_legacy::{
+    constraint_to_value, find_constrained_parent_fields, mask_bits, types, ToIdent,
+    ToUpperCamelCase,
+};
+use crate::{analyzer, ast};
+use quote::{format_ident, quote};
+use std::collections::{BTreeSet, HashMap};
+
+fn size_field_ident(id: &str) -> proc_macro2::Ident {
+    format_ident!("{}_size", id.trim_matches('_'))
+}
+
+/// A single bit-field.
+struct BitField<'a> {
+    shift: usize, // The shift to apply to this field.
+    field: &'a ast::Field,
+}
+
+pub struct FieldParser<'a> {
+    scope: &'a analyzer::Scope<'a>,
+    schema: &'a analyzer::Schema,
+    endianness: ast::EndiannessValue,
+    decl: &'a ast::Decl,
+    packet_name: &'a str,
+    span: &'a proc_macro2::Ident,
+    chunk: Vec<BitField<'a>>,
+    code: Vec<proc_macro2::TokenStream>,
+    shift: usize,
+    offset: usize,
+}
+
+impl<'a> FieldParser<'a> {
+    pub fn new(
+        scope: &'a analyzer::Scope<'a>,
+        schema: &'a analyzer::Schema,
+        endianness: ast::EndiannessValue,
+        packet_name: &'a str,
+        span: &'a proc_macro2::Ident,
+    ) -> FieldParser<'a> {
+        FieldParser {
+            scope,
+            schema,
+            endianness,
+            decl: scope.typedef[packet_name],
+            packet_name,
+            span,
+            chunk: Vec::new(),
+            code: Vec::new(),
+            shift: 0,
+            offset: 0,
+        }
+    }
+
+    pub fn add(&mut self, field: &'a ast::Field) {
+        match &field.desc {
+            _ if field.cond.is_some() => self.add_optional_field(field),
+            _ if self.scope.is_bitfield(field) => self.add_bit_field(field),
+            ast::FieldDesc::Padding { .. } => (),
+            ast::FieldDesc::Array { id, width, type_id, size, .. } => self.add_array_field(
+                id,
+                *width,
+                type_id.as_deref(),
+                *size,
+                self.schema.padded_size(field.key),
+                self.scope.get_type_declaration(field),
+            ),
+            ast::FieldDesc::Typedef { id, type_id } => self.add_typedef_field(id, type_id),
+            ast::FieldDesc::Payload { size_modifier, .. } => {
+                self.add_payload_field(size_modifier.as_deref())
+            }
+            ast::FieldDesc::Body { .. } => self.add_payload_field(None),
+            _ => todo!("{field:?}"),
+        }
+    }
+
+    fn add_optional_field(&mut self, field: &'a ast::Field) {
+        let cond_id = field.cond.as_ref().unwrap().id.to_ident();
+        let cond_value = syn::parse_str::<syn::LitInt>(&format!(
+            "{}",
+            field.cond.as_ref().unwrap().value.unwrap()
+        ))
+        .unwrap();
+
+        self.code.push(match &field.desc {
+            ast::FieldDesc::Scalar { id, width } => {
+                let id = id.to_ident();
+                let value = types::get_uint(self.endianness, *width, self.span);
+                quote! {
+                    let #id = (#cond_id == #cond_value).then(|| #value);
+                }
+            }
+            ast::FieldDesc::Typedef { id, type_id } => match &self.scope.typedef[type_id].desc {
+                ast::DeclDesc::Enum { width, .. } => {
+                    let name = id;
+                    let type_name = type_id;
+                    let id = id.to_ident();
+                    let type_id = type_id.to_ident();
+                    let decl_id = &self.packet_name;
+                    let value = types::get_uint(self.endianness, *width, self.span);
+                    quote! {
+                        let #id = (#cond_id == #cond_value)
+                            .then(||
+                                #type_id::try_from(#value).map_err(|unknown_val| {
+                                    DecodeError::InvalidEnumValueError {
+                                        obj: #decl_id,
+                                        field: #name,
+                                        value: unknown_val as u64,
+                                        type_: #type_name,
+                                    }
+                                }))
+                            .transpose()?;
+                    }
+                }
+                ast::DeclDesc::Struct { .. } => {
+                    let id = id.to_ident();
+                    let type_id = type_id.to_ident();
+                    let span = self.span;
+                    quote! {
+                        let #id = (#cond_id == #cond_value)
+                            .then(|| #type_id::parse_inner(&mut #span))
+                            .transpose()?;
+                    }
+                }
+                _ => unreachable!(),
+            },
+            _ => unreachable!(),
+        })
+    }
+
+    fn add_bit_field(&mut self, field: &'a ast::Field) {
+        self.chunk.push(BitField { shift: self.shift, field });
+        self.shift += self.schema.field_size(field.key).static_().unwrap();
+        if self.shift % 8 != 0 {
+            return;
+        }
+
+        let size = self.shift / 8;
+        let end_offset = self.offset + size;
+
+        let wanted = proc_macro2::Literal::usize_unsuffixed(size);
+        self.check_size(self.span, &quote!(#wanted));
+
+        let chunk_type = types::Integer::new(self.shift);
+        // TODO(mgeisler): generate Rust variable names which cannot
+        // conflict with PDL field names. An option would be to start
+        // Rust variable names with `_`, but that has a special
+        // semantic in Rust.
+        let chunk_name = format_ident!("chunk");
+
+        let get = types::get_uint(self.endianness, self.shift, self.span);
+        if self.chunk.len() > 1 {
+            // Multiple values: we read into a local variable.
+            self.code.push(quote! {
+                let #chunk_name = #get;
+            });
+        }
+
+        let single_value = self.chunk.len() == 1; // && self.chunk[0].offset == 0;
+        for BitField { shift, field } in self.chunk.drain(..) {
+            let mut v = if single_value {
+                // Single value: read directly.
+                quote! { #get }
+            } else {
+                // Multiple values: read from `chunk_name`.
+                quote! { #chunk_name }
+            };
+
+            if shift > 0 {
+                let shift = proc_macro2::Literal::usize_unsuffixed(shift);
+                v = quote! { (#v >> #shift) }
+            }
+
+            let width = self.schema.field_size(field.key).static_().unwrap();
+            let value_type = types::Integer::new(width);
+            if !single_value && width < value_type.width {
+                // Mask value if we grabbed more than `width` and if
+                // `as #value_type` doesn't already do the masking.
+                let mask = mask_bits(width, "u64");
+                v = quote! { (#v & #mask) };
+            }
+
+            if value_type.width < chunk_type.width {
+                v = quote! { #v as #value_type };
+            }
+
+            self.code.push(match &field.desc {
+                ast::FieldDesc::Scalar { id, .. }
+                | ast::FieldDesc::Flag { id, .. } => {
+                    let id = id.to_ident();
+                    quote! {
+                        let #id = #v;
+                    }
+                }
+                ast::FieldDesc::FixedEnum { enum_id, tag_id, .. } => {
+                    let enum_id = enum_id.to_ident();
+                    let tag_id = tag_id.to_upper_camel_case().to_ident();
+                    quote! {
+                        let fixed_value = #v;
+                        if fixed_value != #value_type::from(#enum_id::#tag_id)  {
+                            return Err(DecodeError::InvalidFixedValue {
+                                expected: #value_type::from(#enum_id::#tag_id) as u64,
+                                actual: fixed_value as u64,
+                            });
+                        }
+                    }
+                }
+                ast::FieldDesc::FixedScalar { value, .. } => {
+                    let value = proc_macro2::Literal::usize_unsuffixed(*value);
+                    quote! {
+                        let fixed_value = #v;
+                        if fixed_value != #value {
+                            return Err(DecodeError::InvalidFixedValue {
+                                expected: #value,
+                                actual: fixed_value as u64,
+                            });
+                        }
+                    }
+                }
+                ast::FieldDesc::Typedef { id, type_id } => {
+                    let field_name = id;
+                    let type_name = type_id;
+                    let packet_name = &self.packet_name;
+                    let id = id.to_ident();
+                    let type_id = type_id.to_ident();
+                    quote! {
+                        let #id = #type_id::try_from(#v).map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                            obj: #packet_name,
+                            field: #field_name,
+                            value: unknown_val as u64,
+                            type_: #type_name,
+                        })?;
+                    }
+                }
+                ast::FieldDesc::Reserved { .. } => {
+                    if single_value {
+                        let span = self.span;
+                        let size = proc_macro2::Literal::usize_unsuffixed(size);
+                        quote! {
+                            #span.get_mut().advance(#size);
+                        }
+                    } else {
+                        //  Otherwise we don't need anything: we will
+                        //  have advanced past the reserved field when
+                        //  reading the chunk above.
+                        quote! {}
+                    }
+                }
+                ast::FieldDesc::Size { field_id, .. } => {
+                    let id = size_field_ident(field_id);
+                    quote! {
+                        let #id = #v as usize;
+                    }
+                }
+                ast::FieldDesc::Count { field_id, .. } => {
+                    let id = format_ident!("{field_id}_count");
+                    quote! {
+                        let #id = #v as usize;
+                    }
+                }
+                _ => todo!(),
+            });
+        }
+
+        self.offset = end_offset;
+        self.shift = 0;
+    }
+
+    fn find_count_field(&self, id: &str) -> Option<proc_macro2::Ident> {
+        match self.decl.array_size(id)?.desc {
+            ast::FieldDesc::Count { .. } => Some(format_ident!("{id}_count")),
+            _ => None,
+        }
+    }
+
+    fn find_size_field(&self, id: &str) -> Option<proc_macro2::Ident> {
+        match self.decl.array_size(id)?.desc {
+            ast::FieldDesc::Size { .. } => Some(size_field_ident(id)),
+            _ => None,
+        }
+    }
+
+    fn payload_field_offset_from_end(&self) -> Option<usize> {
+        let decl = self.scope.typedef[self.packet_name];
+        let mut fields = decl.fields();
+        fields.find(|f| {
+            matches!(f.desc, ast::FieldDesc::Body { .. } | ast::FieldDesc::Payload { .. })
+        })?;
+
+        let mut offset = 0;
+        for field in fields {
+            if let Some(width) =
+                self.schema.padded_size(field.key).or(self.schema.field_size(field.key).static_())
+            {
+                offset += width;
+            } else {
+                return None;
+            }
+        }
+
+        Some(offset)
+    }
+
+    fn check_size(&mut self, span: &proc_macro2::Ident, wanted: &proc_macro2::TokenStream) {
+        let packet_name = &self.packet_name;
+        self.code.push(quote! {
+            if #span.get().remaining() < #wanted {
+                return Err(DecodeError::InvalidLengthError {
+                    obj: #packet_name,
+                    wanted: #wanted,
+                    got: #span.get().remaining(),
+                });
+            }
+        });
+    }
+
+    fn add_array_field(
+        &mut self,
+        id: &str,
+        // `width`: the width in bits of the array elements (if Some).
+        width: Option<usize>,
+        // `type_id`: the enum type of the array elements (if Some).
+        // Mutually exclusive with `width`.
+        type_id: Option<&str>,
+        // `size`: the size of the array in number of elements (if
+        // known). If None, the array is a Vec with a dynamic size.
+        size: Option<usize>,
+        padding_size: Option<usize>,
+        decl: Option<&ast::Decl>,
+    ) {
+        enum ElementWidth {
+            Static(usize), // Static size in bytes.
+            Unknown,
+        }
+        let element_width =
+            match width.or_else(|| self.schema.total_size(decl.unwrap().key).static_()) {
+                Some(w) => {
+                    assert_eq!(w % 8, 0, "Array element size ({w}) is not a multiple of 8");
+                    ElementWidth::Static(w / 8)
+                }
+                None => ElementWidth::Unknown,
+            };
+
+        // The "shape" of the array, i.e., the number of elements
+        // given via a static count, a count field, a size field, or
+        // unknown.
+        enum ArrayShape {
+            Static(usize),                  // Static count
+            CountField(proc_macro2::Ident), // Count based on count field
+            SizeField(proc_macro2::Ident),  // Count based on size and field
+            Unknown,                        // Variable count based on remaining bytes
+        }
+        let array_shape = if let Some(count) = size {
+            ArrayShape::Static(count)
+        } else if let Some(count_field) = self.find_count_field(id) {
+            ArrayShape::CountField(count_field)
+        } else if let Some(size_field) = self.find_size_field(id) {
+            ArrayShape::SizeField(size_field)
+        } else {
+            ArrayShape::Unknown
+        };
+
+        // TODO size modifier
+
+        let span = match padding_size {
+            Some(padding_size) => {
+                let span = self.span;
+                let padding_octets = padding_size / 8;
+                self.check_size(span, &quote!(#padding_octets));
+                self.code.push(quote! {
+                    let (head, tail) = #span.get().split_at(#padding_octets);
+                    let mut head = &mut Cell::new(head);
+                    #span.replace(tail);
+                });
+                format_ident!("head")
+            }
+            None => self.span.clone(),
+        };
+
+        let id = id.to_ident();
+
+        let parse_element = self.parse_array_element(&span, width, type_id, decl);
+        match (element_width, &array_shape) {
+            (ElementWidth::Unknown, ArrayShape::SizeField(size_field)) => {
+                // The element width is not known, but the array full
+                // octet size is known by size field. Parse elements
+                // item by item as a vector.
+                self.check_size(&span, &quote!(#size_field));
+                let parse_element =
+                    self.parse_array_element(&format_ident!("head"), width, type_id, decl);
+                self.code.push(quote! {
+                    let (head, tail) = #span.get().split_at(#size_field);
+                    let mut head = &mut Cell::new(head);
+                    #span.replace(tail);
+                    let mut #id = Vec::new();
+                    while !head.get().is_empty() {
+                        #id.push(#parse_element?);
+                    }
+                });
+            }
+            (ElementWidth::Unknown, ArrayShape::Static(count)) => {
+                // The element width is not known, but the array
+                // element count is known statically. Parse elements
+                // item by item as an array.
+                let count = syn::Index::from(*count);
+                self.code.push(quote! {
+                    // TODO(mgeisler): use
+                    // https://doc.rust-lang.org/std/array/fn.try_from_fn.html
+                    // when stabilized.
+                    let #id = (0..#count)
+                        .map(|_| #parse_element)
+                        .collect::<Result<Vec<_>, DecodeError>>()?
+                        .try_into()
+                        .map_err(|_| DecodeError::InvalidPacketError)?;
+                });
+            }
+            (ElementWidth::Unknown, ArrayShape::CountField(count_field)) => {
+                // The element width is not known, but the array
+                // element count is known by the count field. Parse
+                // elements item by item as a vector.
+                self.code.push(quote! {
+                    let #id = (0..#count_field)
+                        .map(|_| #parse_element)
+                        .collect::<Result<Vec<_>, DecodeError>>()?;
+                });
+            }
+            (ElementWidth::Unknown, ArrayShape::Unknown) => {
+                // Neither the count not size is known, parse elements
+                // until the end of the span.
+                self.code.push(quote! {
+                    let mut #id = Vec::new();
+                    while !#span.get().is_empty() {
+                        #id.push(#parse_element?);
+                    }
+                });
+            }
+            (ElementWidth::Static(element_width), ArrayShape::Static(count)) => {
+                // The element width is known, and the array element
+                // count is known statically.
+                let count = syn::Index::from(*count);
+                // This creates a nicely formatted size.
+                let array_size = if element_width == 1 {
+                    quote!(#count)
+                } else {
+                    let element_width = syn::Index::from(element_width);
+                    quote!(#count * #element_width)
+                };
+                self.check_size(&span, &quote! { #array_size });
+                self.code.push(quote! {
+                    // TODO(mgeisler): use
+                    // https://doc.rust-lang.org/std/array/fn.try_from_fn.html
+                    // when stabilized.
+                    let #id = (0..#count)
+                        .map(|_| #parse_element)
+                        .collect::<Result<Vec<_>, DecodeError>>()?
+                        .try_into()
+                        .map_err(|_| DecodeError::InvalidPacketError)?;
+                });
+            }
+            (ElementWidth::Static(element_width), ArrayShape::CountField(count_field)) => {
+                // The element width is known, and the array element
+                // count is known dynamically by the count field.
+                self.check_size(&span, &quote!(#count_field * #element_width));
+                self.code.push(quote! {
+                    let #id = (0..#count_field)
+                        .map(|_| #parse_element)
+                        .collect::<Result<Vec<_>, DecodeError>>()?;
+                });
+            }
+            (ElementWidth::Static(element_width), ArrayShape::SizeField(_))
+            | (ElementWidth::Static(element_width), ArrayShape::Unknown) => {
+                // The element width is known, and the array full size
+                // is known by size field, or unknown (in which case
+                // it is the remaining span length).
+                let array_size = if let ArrayShape::SizeField(size_field) = &array_shape {
+                    self.check_size(&span, &quote!(#size_field));
+                    quote!(#size_field)
+                } else {
+                    quote!(#span.get().remaining())
+                };
+                let count_field = format_ident!("{id}_count");
+                let array_count = if element_width != 1 {
+                    let element_width = syn::Index::from(element_width);
+                    self.code.push(quote! {
+                        if #array_size % #element_width != 0 {
+                            return Err(DecodeError::InvalidArraySize {
+                                array: #array_size,
+                                element: #element_width,
+                            });
+                        }
+                        let #count_field = #array_size / #element_width;
+                    });
+                    quote!(#count_field)
+                } else {
+                    array_size
+                };
+
+                self.code.push(quote! {
+                    let mut #id = Vec::with_capacity(#array_count);
+                    for _ in 0..#array_count {
+                        #id.push(#parse_element?);
+                    }
+                });
+            }
+        }
+    }
+
+    /// Parse typedef fields.
+    ///
+    /// This is only for non-enum fields: enums are parsed via
+    /// add_bit_field.
+    fn add_typedef_field(&mut self, id: &str, type_id: &str) {
+        assert_eq!(self.shift, 0, "Typedef field does not start on an octet boundary");
+
+        let decl = self.scope.typedef[type_id];
+        if let ast::DeclDesc::Struct { parent_id: Some(_), .. } = &decl.desc {
+            panic!("Derived struct used in typedef field");
+        }
+
+        let span = self.span;
+        let id = id.to_ident();
+        let type_id = type_id.to_ident();
+
+        self.code.push(match self.schema.decl_size(decl.key) {
+            analyzer::Size::Unknown | analyzer::Size::Dynamic => quote! {
+                let #id = #type_id::parse_inner(&mut #span)?;
+            },
+            analyzer::Size::Static(width) => {
+                assert_eq!(width % 8, 0, "Typedef field type size is not a multiple of 8");
+                match &decl.desc {
+                    ast::DeclDesc::Checksum { .. } => todo!(),
+                    ast::DeclDesc::CustomField { .. } if [8, 16, 32, 64].contains(&width) => {
+                        let get_uint = types::get_uint(self.endianness, width, span);
+                        quote! {
+                            let #id = #get_uint.into();
+                        }
+                    }
+                    ast::DeclDesc::CustomField { .. } => {
+                        let get_uint = types::get_uint(self.endianness, width, span);
+                        quote! {
+                            let #id = (#get_uint)
+                                .try_into()
+                                .unwrap(); // Value is masked and conversion must succeed.
+                        }
+                    }
+                    ast::DeclDesc::Struct { .. } => {
+                        let width = syn::Index::from(width / 8);
+                        quote! {
+                            let (head, tail) = #span.get().split_at(#width);
+                            #span.replace(tail);
+                            let #id = #type_id::parse(head)?;
+                        }
+                    }
+                    _ => unreachable!(),
+                }
+            }
+        });
+    }
+
+    /// Parse body and payload fields.
+    fn add_payload_field(&mut self, size_modifier: Option<&str>) {
+        let span = self.span;
+        let payload_size_field = self.decl.payload_size();
+        let offset_from_end = self.payload_field_offset_from_end();
+
+        if self.shift != 0 {
+            todo!("Unexpected non byte aligned payload");
+        }
+
+        if let Some(ast::FieldDesc::Size { field_id, .. }) = &payload_size_field.map(|f| &f.desc) {
+            // The payload or body has a known size. Consume the
+            // 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(DecodeError::InvalidLengthError {
+                            obj: #packet_name,
+                            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];
+                #span.get_mut().advance(#size_field);
+            });
+        } else if offset_from_end == Some(0) {
+            // The payload or body is the last field of a packet,
+            // consume the remaining span.
+            self.code.push(quote! {
+                let payload = #span.get();
+                #span.get_mut().advance(payload.len());
+            });
+        } else if let Some(offset_from_end) = offset_from_end {
+            // The payload or body is followed by fields of static
+            // size. Consume the span that is not reserved for the
+            // following fields.
+            assert_eq!(
+                offset_from_end % 8,
+                0,
+                "Payload field offset from end of packet is not a multiple of 8"
+            );
+            let offset_from_end = syn::Index::from(offset_from_end / 8);
+            self.check_size(self.span, &quote!(#offset_from_end));
+            self.code.push(quote! {
+                let payload = &#span.get()[..#span.get().len() - #offset_from_end];
+                #span.get_mut().advance(payload.len());
+            });
+        }
+
+        let decl = self.scope.typedef[self.packet_name];
+        if let ast::DeclDesc::Struct { .. } = &decl.desc {
+            self.code.push(quote! {
+                let payload = Vec::from(payload);
+            });
+        }
+    }
+
+    /// Parse a single array field element from `span`.
+    fn parse_array_element(
+        &self,
+        span: &proc_macro2::Ident,
+        width: Option<usize>,
+        type_id: Option<&str>,
+        decl: Option<&ast::Decl>,
+    ) -> proc_macro2::TokenStream {
+        if let Some(width) = width {
+            let get_uint = types::get_uint(self.endianness, width, span);
+            return quote! {
+                Ok::<_, DecodeError>(#get_uint)
+            };
+        }
+
+        if let Some(ast::DeclDesc::Enum { id, width, .. }) = decl.map(|decl| &decl.desc) {
+            let get_uint = types::get_uint(self.endianness, *width, span);
+            let type_id = id.to_ident();
+            let packet_name = &self.packet_name;
+            return quote! {
+                #type_id::try_from(#get_uint).map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                    obj: #packet_name,
+                    field: "", // TODO(mgeisler): fill out or remove
+                    value: unknown_val as u64,
+                    type_: #id,
+                })
+            };
+        }
+
+        let type_id = type_id.unwrap().to_ident();
+        quote! {
+            #type_id::parse_inner(#span)
+        }
+    }
+
+    pub fn done(&mut self) {
+        let decl = self.scope.typedef[self.packet_name];
+        if let ast::DeclDesc::Struct { .. } = &decl.desc {
+            return; // Structs don't parse the child structs recursively.
+        }
+
+        let children = self.scope.iter_children(decl).collect::<Vec<_>>();
+        if children.is_empty() && self.decl.payload().is_none() {
+            return;
+        }
+
+        let all_fields = HashMap::<String, _>::from_iter(
+            self.scope.iter_fields(decl).filter_map(|f| f.id().map(|id| (id.to_string(), f))),
+        );
+
+        // Gather fields that are constrained in immediate child declarations.
+        // Keep the fields sorted by name.
+        // TODO: fields that are only matched in grand children will not be included.
+        let constrained_fields = children
+            .iter()
+            .flat_map(|child| child.constraints().map(|c| &c.id))
+            .collect::<BTreeSet<_>>();
+
+        let mut match_values = Vec::new();
+        let mut child_parse_args = Vec::new();
+        let mut child_ids_data = Vec::new();
+        let mut child_ids = Vec::new();
+
+        let get_constraint_value = |mut constraints: std::slice::Iter<'_, ast::Constraint>,
+                                    id: &str|
+         -> Option<proc_macro2::TokenStream> {
+            constraints.find(|c| c.id == id).map(|c| constraint_to_value(&all_fields, c))
+        };
+
+        for child in children.iter() {
+            let tuple_values = constrained_fields
+                .iter()
+                .map(|id| {
+                    get_constraint_value(child.constraints(), id).map(|v| vec![v]).unwrap_or_else(
+                        || {
+                            self.scope
+                                .file
+                                .iter_children(child)
+                                .filter_map(|d| get_constraint_value(d.constraints(), id))
+                                .collect()
+                        },
+                    )
+                })
+                .collect::<Vec<_>>();
+
+            // If no constraint values are found for the tuple just skip the child
+            // packet as it would capture unwanted input packets.
+            if tuple_values.iter().all(|v| v.is_empty()) {
+                continue;
+            }
+
+            let tuple_values = tuple_values
+                .iter()
+                .map(|v| v.is_empty().then_some(quote!(_)).unwrap_or_else(|| quote!( #(#v)|* )))
+                .collect::<Vec<_>>();
+
+            let fields = find_constrained_parent_fields(self.scope, child.id().unwrap())
+                .iter()
+                .map(|field| field.id().unwrap().to_ident())
+                .collect::<Vec<_>>();
+
+            match_values.push(quote!( (#(#tuple_values),*) ));
+            child_parse_args.push(quote!( #(, #fields)*));
+            child_ids_data.push(format_ident!("{}Data", child.id().unwrap()));
+            child_ids.push(child.id().unwrap().to_ident());
+        }
+
+        let constrained_field_idents = constrained_fields.iter().map(|field| field.to_ident());
+        let packet_data_child = format_ident!("{}DataChild", self.packet_name);
+
+        // Parsing of packet children requires having a payload field;
+        // it is allowed to inherit from a packet with empty payload, in this
+        // case generate an empty payload value.
+        if !decl
+            .fields()
+            .any(|f| matches!(&f.desc, ast::FieldDesc::Payload { .. } | ast::FieldDesc::Body))
+        {
+            self.code.push(quote! {
+                let payload: &[u8] = &[];
+            })
+        }
+        self.code.push(quote! {
+            let child = match (#(#constrained_field_idents),*) {
+                #(#match_values if #child_ids_data::conforms(&payload) => {
+                    let mut cell = Cell::new(payload);
+                    let child_data = #child_ids_data::parse_inner(&mut cell #child_parse_args)?;
+                    // TODO(mgeisler): communicate back to user if !cell.get().is_empty()?
+                    #packet_data_child::#child_ids(child_data)
+                }),*
+                _ if !payload.is_empty() => {
+                    #packet_data_child::Payload(Bytes::copy_from_slice(payload))
+                }
+                _ => #packet_data_child::None,
+            };
+        });
+    }
+}
+
+impl quote::ToTokens for FieldParser<'_> {
+    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
+        let code = &self.code;
+        tokens.extend(quote! {
+            #(#code)*
+        });
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::analyzer;
+    use crate::ast;
+    use crate::parser::parse_inline;
+
+    /// Parse a string fragment as a PDL file.
+    ///
+    /// # Panics
+    ///
+    /// Panics on parse errors.
+    pub fn parse_str(text: &str) -> ast::File {
+        let mut db = ast::SourceDatabase::new();
+        let file = parse_inline(&mut db, "stdin", String::from(text)).expect("parse error");
+        analyzer::analyze(&file).expect("analyzer error")
+    }
+
+    #[test]
+    fn test_find_fields_static() {
+        let code = "
+              little_endian_packets
+              packet P {
+                a: 24[3],
+              }
+            ";
+        let file = parse_str(code);
+        let scope = analyzer::Scope::new(&file).unwrap();
+        let schema = analyzer::Schema::new(&file);
+        let span = format_ident!("bytes");
+        let parser = FieldParser::new(&scope, &schema, file.endianness.value, "P", &span);
+        assert_eq!(parser.find_size_field("a"), None);
+        assert_eq!(parser.find_count_field("a"), None);
+    }
+
+    #[test]
+    fn test_find_fields_dynamic_count() {
+        let code = "
+              little_endian_packets
+              packet P {
+                _count_(b): 24,
+                b: 16[],
+              }
+            ";
+        let file = parse_str(code);
+        let scope = analyzer::Scope::new(&file).unwrap();
+        let schema = analyzer::Schema::new(&file);
+        let span = format_ident!("bytes");
+        let parser = FieldParser::new(&scope, &schema, file.endianness.value, "P", &span);
+        assert_eq!(parser.find_size_field("b"), None);
+        assert_eq!(parser.find_count_field("b"), Some(format_ident!("b_count")));
+    }
+
+    #[test]
+    fn test_find_fields_dynamic_size() {
+        let code = "
+              little_endian_packets
+              packet P {
+                _size_(c): 8,
+                c: 24[],
+              }
+            ";
+        let file = parse_str(code);
+        let scope = analyzer::Scope::new(&file).unwrap();
+        let schema = analyzer::Schema::new(&file);
+        let span = format_ident!("bytes");
+        let parser = FieldParser::new(&scope, &schema, file.endianness.value, "P", &span);
+        assert_eq!(parser.find_size_field("c"), Some(format_ident!("c_size")));
+        assert_eq!(parser.find_count_field("c"), None);
+    }
+}
diff --git a/src/backends/rust_legacy/preamble.rs b/src/backends/rust_legacy/preamble.rs
new file mode 100644
index 0000000..b2647bb
--- /dev/null
+++ b/src/backends/rust_legacy/preamble.rs
@@ -0,0 +1,93 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use quote::quote;
+use std::path::Path;
+
+/// Generate the file preamble.
+pub fn generate(path: &Path) -> proc_macro2::TokenStream {
+    // TODO(mgeisler): Make the  generated code free from warnings.
+    //
+    // The code either needs
+    //
+    // clippy_lints: "none",
+    // lints: "none",
+    //
+    // in the Android.bp file, or we need to add
+    //
+    // #![allow(warnings, missing_docs)]
+    //
+    // to the generated code. We cannot add the module-level attribute
+    // here because of how the generated code is used with include! in
+    // lmp/src/packets.rs.
+    let filename = path.file_name().unwrap().to_str().expect("non UTF-8 filename");
+    let module_doc_string = format!(" @generated rust packets from {filename}.");
+    // TODO(mgeisler): the doc comment below should be an outer
+    // comment (#![doc = ...]). However, people include the generated
+    // code in the middle of another module via include_str!:
+    //
+    // fn before() {}
+    // include_str!("generated.rs")
+    // fn after() {}
+    //
+    // It is illegal to have a //! comment in the middle of a file. We
+    // should refactor such usages to instead look like this:
+    //
+    // fn before() {}
+    // mod foo { include_str!("generated.rs") }
+    // use foo::*;
+    // fn after() {}
+    quote! {
+        #[doc = #module_doc_string]
+
+        use bytes::{Buf, BufMut, Bytes, BytesMut};
+        use std::convert::{TryFrom, TryInto};
+        use std::cell::Cell;
+        use std::fmt;
+        use std::result::Result;
+        use pdl_runtime::{DecodeError, EncodeError, Packet};
+
+        /// 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(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
+            }
+        }
+
+        impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                T::fmt(&self.0, f)
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::test_utils::{assert_snapshot_eq, format_rust};
+
+    #[test]
+    fn test_generate_preamble() {
+        let actual_code = generate(Path::new("some/path/foo.pdl")).to_string();
+        assert_snapshot_eq("tests/generated/rust_legacy/preamble.rs", &format_rust(&actual_code));
+    }
+}
diff --git a/src/backends/rust_legacy/serializer.rs b/src/backends/rust_legacy/serializer.rs
new file mode 100644
index 0000000..2262d27
--- /dev/null
+++ b/src/backends/rust_legacy/serializer.rs
@@ -0,0 +1,519 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use crate::backends::rust_legacy::{mask_bits, types, ToIdent, ToUpperCamelCase};
+use crate::{analyzer, ast};
+use quote::{format_ident, quote};
+
+/// A single bit-field value.
+struct BitField {
+    value: proc_macro2::TokenStream, // An expression which produces a value.
+    field_type: types::Integer,      // The type of the value.
+    shift: usize,                    // A bit-shift to apply to `value`.
+}
+
+pub struct FieldSerializer<'a> {
+    scope: &'a analyzer::Scope<'a>,
+    schema: &'a analyzer::Schema,
+    endianness: ast::EndiannessValue,
+    packet_name: &'a str,
+    span: &'a proc_macro2::Ident,
+    chunk: Vec<BitField>,
+    code: Vec<proc_macro2::TokenStream>,
+    shift: usize,
+}
+
+impl<'a> FieldSerializer<'a> {
+    pub fn new(
+        scope: &'a analyzer::Scope<'a>,
+        schema: &'a analyzer::Schema,
+        endianness: ast::EndiannessValue,
+        packet_name: &'a str,
+        span: &'a proc_macro2::Ident,
+    ) -> FieldSerializer<'a> {
+        FieldSerializer {
+            scope,
+            schema,
+            endianness,
+            packet_name,
+            span,
+            chunk: Vec::new(),
+            code: Vec::new(),
+            shift: 0,
+        }
+    }
+
+    pub fn add(&mut self, field: &ast::Field) {
+        match &field.desc {
+            _ if field.cond.is_some() => self.add_optional_field(field),
+            _ if self.scope.is_bitfield(field) => self.add_bit_field(field),
+            ast::FieldDesc::Array { id, width, .. } => self.add_array_field(
+                id,
+                *width,
+                self.schema.padded_size(field.key),
+                self.scope.get_type_declaration(field),
+            ),
+            ast::FieldDesc::Typedef { id, type_id } => {
+                self.add_typedef_field(id, type_id);
+            }
+            ast::FieldDesc::Payload { .. } | ast::FieldDesc::Body { .. } => {
+                self.add_payload_field();
+            }
+            // Padding field handled in serialization of associated array field.
+            ast::FieldDesc::Padding { .. } => (),
+            _ => todo!("Cannot yet serialize {field:?}"),
+        }
+    }
+
+    fn add_optional_field(&mut self, field: &ast::Field) {
+        self.code.push(match &field.desc {
+            ast::FieldDesc::Scalar { id, width } => {
+                let name = id;
+                let id = id.to_ident();
+                let backing_type = types::Integer::new(*width);
+                let write = types::put_uint(self.endianness, &quote!(*#id), *width, self.span);
+
+                let range_check = (backing_type.width > *width).then(|| {
+                    let packet_name = &self.packet_name;
+                    let max_value = mask_bits(*width, "u64");
+
+                    quote! {
+                        if *#id > #max_value {
+                            return Err(EncodeError::InvalidScalarValue {
+                                packet: #packet_name,
+                                field: #name,
+                                value: *#id as u64,
+                                maximum_value: #max_value as u64,
+                            })
+                        }
+                    }
+                });
+
+                quote! {
+                    if let Some(#id) = &self.#id {
+                        #range_check
+                        #write
+                    }
+                }
+            }
+            ast::FieldDesc::Typedef { id, type_id } => match &self.scope.typedef[type_id].desc {
+                ast::DeclDesc::Enum { width, .. } => {
+                    let id = id.to_ident();
+                    let backing_type = types::Integer::new(*width);
+                    let write = types::put_uint(
+                        self.endianness,
+                        &quote!(#backing_type::from(#id)),
+                        *width,
+                        self.span,
+                    );
+                    quote! {
+                        if let Some(#id) = &self.#id {
+                            #write
+                        }
+                    }
+                }
+                ast::DeclDesc::Struct { .. } => {
+                    let id = id.to_ident();
+                    let span = self.span;
+                    quote! {
+                        if let Some(#id) = &self.#id {
+                            #id.write_to(#span)?;
+                        }
+                    }
+                }
+                _ => unreachable!(),
+            },
+            _ => unreachable!(),
+        })
+    }
+
+    fn add_bit_field(&mut self, field: &ast::Field) {
+        let width = self.schema.field_size(field.key).static_().unwrap();
+        let shift = self.shift;
+
+        match &field.desc {
+            ast::FieldDesc::Flag { optional_field_id, set_value, .. } => {
+                let optional_field_id = optional_field_id.to_ident();
+                let cond_value_present =
+                    syn::parse_str::<syn::LitInt>(&format!("{}", set_value)).unwrap();
+                let cond_value_absent =
+                    syn::parse_str::<syn::LitInt>(&format!("{}", 1 - set_value)).unwrap();
+                self.chunk.push(BitField {
+                    value: quote! {
+                        if self.#optional_field_id.is_some() {
+                            #cond_value_present
+                        } else {
+                            #cond_value_absent
+                        }
+                    },
+                    field_type: types::Integer::new(1),
+                    shift,
+                });
+            }
+            ast::FieldDesc::Scalar { id, width } => {
+                let field_name = id.to_ident();
+                let field_type = types::Integer::new(*width);
+                if field_type.width > *width {
+                    let packet_name = &self.packet_name;
+                    let max_value = mask_bits(*width, "u64");
+                    self.code.push(quote! {
+                        if self.#field_name > #max_value {
+                            return Err(EncodeError::InvalidScalarValue {
+                                packet: #packet_name,
+                                field: #id,
+                                value: self.#field_name as u64,
+                                maximum_value: #max_value,
+                            })
+                        }
+                    });
+                }
+                self.chunk.push(BitField { value: quote!(self.#field_name), field_type, shift });
+            }
+            ast::FieldDesc::FixedEnum { enum_id, tag_id, .. } => {
+                let field_type = types::Integer::new(width);
+                let enum_id = enum_id.to_ident();
+                let tag_id = format_ident!("{}", tag_id.to_upper_camel_case());
+                self.chunk.push(BitField {
+                    value: quote!(#field_type::from(#enum_id::#tag_id)),
+                    field_type,
+                    shift,
+                });
+            }
+            ast::FieldDesc::FixedScalar { value, .. } => {
+                let field_type = types::Integer::new(width);
+                let value = proc_macro2::Literal::usize_unsuffixed(*value);
+                self.chunk.push(BitField { value: quote!(#value), field_type, shift });
+            }
+            ast::FieldDesc::Typedef { id, .. } => {
+                let field_name = id.to_ident();
+                let field_type = types::Integer::new(width);
+                self.chunk.push(BitField {
+                    value: quote!(#field_type::from(self.#field_name)),
+                    field_type,
+                    shift,
+                });
+            }
+            ast::FieldDesc::Reserved { .. } => {
+                // Nothing to do here.
+            }
+            ast::FieldDesc::Size { field_id, width, .. } => {
+                let packet_name = &self.packet_name;
+                let max_value = mask_bits(*width, "usize");
+
+                let decl = self.scope.typedef.get(self.packet_name).unwrap();
+                let value_field = self
+                    .scope
+                    .iter_fields(decl)
+                    .find(|field| match &field.desc {
+                        ast::FieldDesc::Payload { .. } => field_id == "_payload_",
+                        ast::FieldDesc::Body { .. } => field_id == "_body_",
+                        _ => field.id() == Some(field_id),
+                    })
+                    .unwrap();
+
+                let field_name = field_id.to_ident();
+                let field_type = types::Integer::new(*width);
+                // TODO: size modifier
+
+                let value_field_decl = self.scope.get_type_declaration(value_field);
+
+                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() }
+                        } else {
+                            quote! { self.payload.len() }
+                        }
+                    }
+                    (ast::FieldDesc::Array { width: Some(width), .. }, _)
+                    | (ast::FieldDesc::Array { .. }, Some(ast::DeclDesc::Enum { width, .. })) => {
+                        let byte_width = syn::Index::from(width / 8);
+                        if byte_width.index == 1 {
+                            quote! { self.#field_name.len() }
+                        } else {
+                            quote! { (self.#field_name.len() * #byte_width) }
+                        }
+                    }
+                    (ast::FieldDesc::Array { .. }, _) => {
+                        self.code.push(quote! {
+                            let #field_size_name = self.#field_name
+                                .iter()
+                                .map(|elem| elem.get_size())
+                                .sum::<usize>();
+                        });
+                        quote! { #field_size_name }
+                    }
+                    _ => panic!("Unexpected size field: {field:?}"),
+                };
+
+                self.code.push(quote! {
+                    if #array_size > #max_value {
+                        return Err(EncodeError::SizeOverflow {
+                            packet: #packet_name,
+                            field: #field_id,
+                            size: #array_size,
+                            maximum_size: #max_value,
+                        })
+                    }
+                });
+
+                self.chunk.push(BitField {
+                    value: quote!(#array_size as #field_type),
+                    field_type,
+                    shift,
+                });
+            }
+            ast::FieldDesc::Count { field_id, width, .. } => {
+                let field_name = field_id.to_ident();
+                let field_type = types::Integer::new(*width);
+                if field_type.width > *width {
+                    let packet_name = &self.packet_name;
+                    let max_value = mask_bits(*width, "usize");
+                    self.code.push(quote! {
+                        if self.#field_name.len() > #max_value {
+                            return Err(EncodeError::CountOverflow {
+                                packet: #packet_name,
+                                field: #field_id,
+                                count: self.#field_name.len(),
+                                maximum_count: #max_value,
+                            })
+                        }
+                    });
+                }
+                self.chunk.push(BitField {
+                    value: quote!(self.#field_name.len() as #field_type),
+                    field_type,
+                    shift,
+                });
+            }
+            _ => todo!("{field:?}"),
+        }
+
+        self.shift += width;
+        if self.shift % 8 == 0 {
+            self.pack_bit_fields()
+        }
+    }
+
+    fn pack_bit_fields(&mut self) {
+        assert_eq!(self.shift % 8, 0);
+        let chunk_type = types::Integer::new(self.shift);
+        let values = self
+            .chunk
+            .drain(..)
+            .map(|BitField { mut value, field_type, shift }| {
+                if field_type.width != chunk_type.width {
+                    // We will be combining values with `|`, so we
+                    // need to cast them first.
+                    value = quote! { (#value as #chunk_type) };
+                }
+                if shift > 0 {
+                    let op = quote!(<<);
+                    let shift = proc_macro2::Literal::usize_unsuffixed(shift);
+                    value = quote! { (#value #op #shift) };
+                }
+                value
+            })
+            .collect::<Vec<_>>();
+
+        match values.as_slice() {
+            [] => {
+                let span = format_ident!("{}", self.span);
+                let count = syn::Index::from(self.shift / 8);
+                self.code.push(quote! {
+                    #span.put_bytes(0, #count);
+                });
+            }
+            [value] => {
+                let put = types::put_uint(self.endianness, value, self.shift, self.span);
+                self.code.push(quote! {
+                    #put;
+                });
+            }
+            _ => {
+                let put = types::put_uint(self.endianness, &quote!(value), self.shift, self.span);
+                self.code.push(quote! {
+                    let value = #(#values)|*;
+                    #put;
+                });
+            }
+        }
+
+        self.shift = 0;
+    }
+
+    fn add_array_field(
+        &mut self,
+        id: &str,
+        width: Option<usize>,
+        padding_size: Option<usize>,
+        decl: Option<&ast::Decl>,
+    ) {
+        let span = format_ident!("{}", self.span);
+        let serialize = match width {
+            Some(width) => {
+                let value = quote!(*elem);
+                types::put_uint(self.endianness, &value, width, self.span)
+            }
+            None => {
+                if let Some(ast::DeclDesc::Enum { width, .. }) = decl.map(|decl| &decl.desc) {
+                    let element_type = types::Integer::new(*width);
+                    types::put_uint(
+                        self.endianness,
+                        &quote!(#element_type::from(elem)),
+                        *width,
+                        self.span,
+                    )
+                } else {
+                    quote! {
+                        elem.write_to(#span)?
+                    }
+                }
+            }
+        };
+
+        let packet_name = self.packet_name;
+        let name = id;
+        let id = id.to_ident();
+
+        if let Some(padding_size) = padding_size {
+            let padding_octets = padding_size / 8;
+            let element_width = match &width {
+                Some(width) => Some(*width),
+                None => self.schema.decl_size(decl.unwrap().key).static_(),
+            };
+
+            let array_size = match element_width {
+                Some(element_width) => {
+                    let element_size = proc_macro2::Literal::usize_unsuffixed(element_width / 8);
+                    quote! { self.#id.len() * #element_size }
+                }
+                _ => {
+                    quote! { self.#id.iter().fold(0, |size, elem| size + elem.get_size()) }
+                }
+            };
+
+            self.code.push(quote! {
+                let array_size = #array_size;
+                if array_size > #padding_octets {
+                    return Err(EncodeError::SizeOverflow {
+                        packet: #packet_name,
+                        field: #name,
+                        size: array_size,
+                        maximum_size: #padding_octets,
+                    })
+                }
+                for elem in &self.#id {
+                    #serialize;
+                }
+                #span.put_bytes(0, #padding_octets - array_size);
+            });
+        } else {
+            self.code.push(quote! {
+                for elem in &self.#id {
+                    #serialize;
+                }
+            });
+        }
+    }
+
+    fn add_typedef_field(&mut self, id: &str, type_id: &str) {
+        assert_eq!(self.shift, 0, "Typedef field does not start on an octet boundary");
+        let decl = self.scope.typedef[type_id];
+        if let ast::DeclDesc::Struct { parent_id: Some(_), .. } = &decl.desc {
+            panic!("Derived struct used in typedef field");
+        }
+
+        let id = id.to_ident();
+        let span = format_ident!("{}", self.span);
+
+        self.code.push(match &decl.desc {
+            ast::DeclDesc::Checksum { .. } => todo!(),
+            ast::DeclDesc::CustomField { width: Some(width), .. } => {
+                let backing_type = types::Integer::new(*width);
+                let put_uint = types::put_uint(
+                    self.endianness,
+                    &quote! { #backing_type::from(self.#id) },
+                    *width,
+                    self.span,
+                );
+                quote! {
+                    #put_uint;
+                }
+            }
+            ast::DeclDesc::Struct { .. } => quote! {
+                self.#id.write_to(#span)?;
+            },
+            _ => unreachable!(),
+        });
+    }
+
+    fn add_payload_field(&mut self) {
+        if self.shift != 0 && self.endianness == ast::EndiannessValue::BigEndian {
+            panic!("Payload field does not start on an octet boundary");
+        }
+
+        let decl = self.scope.typedef[self.packet_name];
+        let is_packet = matches!(&decl.desc, ast::DeclDesc::Packet { .. });
+
+        let child_ids = self
+            .scope
+            .iter_children(decl)
+            .map(|child| child.id().unwrap().to_ident())
+            .collect::<Vec<_>>();
+
+        let span = format_ident!("{}", self.span);
+        if self.shift == 0 {
+            if is_packet {
+                let packet_data_child = format_ident!("{}DataChild", self.packet_name);
+                self.code.push(quote! {
+                    match &self.child {
+                        #(#packet_data_child::#child_ids(child) => child.write_to(#span)?,)*
+                        #packet_data_child::Payload(payload) => #span.put_slice(payload),
+                        #packet_data_child::None => {},
+                    }
+                })
+            } else {
+                self.code.push(quote! {
+                    #span.put_slice(&self.payload);
+                });
+            }
+        } else {
+            todo!("Shifted payloads");
+        }
+    }
+}
+
+impl quote::ToTokens for FieldSerializer<'_> {
+    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
+        let code = &self.code;
+        tokens.extend(quote! {
+            #(#code)*
+        });
+    }
+}
diff --git a/src/bin/generate-canonical-tests.rs b/src/backends/rust_legacy/test.rs
similarity index 90%
rename from src/bin/generate-canonical-tests.rs
rename to src/backends/rust_legacy/test.rs
index 1e18490..77bfe2a 100644
--- a/src/bin/generate-canonical-tests.rs
+++ b/src/backends/rust_legacy/test.rs
@@ -58,14 +58,13 @@
     syn::parse_str::<syn::LitStr>(&format!("r#\" {json} \"#")).unwrap()
 }
 
-fn generate_unit_tests(input: &str, packet_names: &[&str], module_name: &str) {
+fn generate_unit_tests(input: &str, packet_names: &[&str]) -> Result<String, String> {
     eprintln!("Reading test vectors from {input}, will use {} packets", packet_names.len());
 
     let data = std::fs::read_to_string(input)
         .unwrap_or_else(|err| panic!("Could not read {input}: {err}"));
     let packets: Vec<Packet> = serde_json::from_str(&data).expect("Could not parse JSON");
 
-    let module = syn::parse_str::<syn::Path>(module_name).unwrap();
     let mut tests = Vec::new();
     for packet in &packets {
         for (i, test_vector) in packet.tests.iter().enumerate() {
@@ -111,17 +110,17 @@
                 #[test]
                 fn #parse_test_name() {
                     let packed = #packed;
-                    let actual = #module::#packet_name::parse(&packed).unwrap();
+                    let actual = #packet_name::parse(&packed).unwrap();
                     #(#assertions)*
                 }
 
                 #[test]
                 fn #serialize_test_name() {
-                    let builder: #module::#builder_name = serde_json::from_str(#json)
+                    let builder: #builder_name = serde_json::from_str(#json)
                         .expect("Could not create builder from canonical JSON data");
                     let packet = builder.build();
                     let packed: Vec<u8> = #packed;
-                    assert_eq!(packet.to_vec(), packed);
+                    assert_eq!(packet.encode_to_vec(), Ok(packed));
                 }
             });
         }
@@ -129,24 +128,25 @@
 
     // TODO(mgeisler): make the generated code clean from warnings.
     let code = quote! {
-        #![allow(warnings, missing_docs)]
+        #[allow(warnings, missing_docs)]
+        #[cfg(test)]
+        mod test {
+            use pdl_runtime::Packet;
+            use serde_json::json;
+            use super::*;
 
-        use pdl_runtime::Packet;
-        use serde_json::json;
-
-        #(#tests)*
+            #(#tests)*
+        }
     };
     let syntax_tree = syn::parse2::<syn::File>(code).expect("Could not parse {code:#?}");
-    println!("{}", prettyplease::unparse(&syntax_tree));
+    Ok(prettyplease::unparse(&syntax_tree))
 }
 
-fn main() {
-    let input_path = std::env::args().nth(1).expect("Need path to JSON file with test vectors");
-    let module_name = std::env::args().nth(2).expect("Need name for the generated module");
+pub fn generate_tests(input_file: &str) -> Result<String, String> {
     // TODO(mgeisler): remove the `packet_names` argument when we
     // support all canonical packets.
     generate_unit_tests(
-        &input_path,
+        input_file,
         &[
             "EnumChild_A",
             "EnumChild_B",
@@ -241,7 +241,13 @@
             "Struct_FixedScalar_Field",
             "Struct_Size_Field",
             "Struct_Struct_Field",
+            "Enum_Incomplete_Truncated_Closed",
+            "Enum_Incomplete_Truncated_Open",
+            "Enum_Incomplete_Truncated_Closed_WithRange",
+            "Enum_Incomplete_Truncated_Open_WithRange",
+            "Enum_Complete_Truncated",
+            "Enum_Complete_Truncated_WithRange",
+            "Enum_Complete_WithRange",
         ],
-        &module_name,
-    );
+    )
 }
diff --git a/src/backends/rust_legacy/types.rs b/src/backends/rust_legacy/types.rs
new file mode 100644
index 0000000..ed746a1
--- /dev/null
+++ b/src/backends/rust_legacy/types.rs
@@ -0,0 +1,186 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Utility functions for dealing with Rust integer types.
+
+use crate::backends::rust_legacy::ToIdent;
+use crate::{analyzer, ast};
+use quote::{format_ident, quote};
+
+/// A Rust integer type such as `u8`.
+#[derive(Copy, Clone)]
+pub struct Integer {
+    pub width: usize,
+}
+
+impl Integer {
+    /// Get the Rust integer type for the given bit width.
+    ///
+    /// This will round up the size to the nearest Rust integer size.
+    /// PDL supports integers up to 64 bit, so it is an error to call
+    /// this with a width larger than 64.
+    pub fn new(width: usize) -> Integer {
+        for integer_width in [8, 16, 32, 64] {
+            if width <= integer_width {
+                return Integer { width: integer_width };
+            }
+        }
+        panic!("Cannot construct Integer with width: {width}")
+    }
+}
+
+impl quote::ToTokens for Integer {
+    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
+        let t: syn::Type = syn::parse_str(&format!("u{}", self.width))
+            .expect("Could not parse integer, unsupported width?");
+        t.to_tokens(tokens);
+    }
+}
+
+pub fn rust_type(field: &ast::Field) -> proc_macro2::TokenStream {
+    match &field.desc {
+        ast::FieldDesc::Scalar { width, .. } if field.cond.is_some() => {
+            let field_type = Integer::new(*width);
+            quote!(Option<#field_type>)
+        }
+        ast::FieldDesc::Scalar { width, .. } => {
+            let field_type = Integer::new(*width);
+            quote!(#field_type)
+        }
+        ast::FieldDesc::Typedef { type_id, .. } if field.cond.is_some() => {
+            let field_type = type_id.to_ident();
+            quote!(Option<#field_type>)
+        }
+        ast::FieldDesc::Typedef { type_id, .. } => {
+            let field_type = type_id.to_ident();
+            quote!(#field_type)
+        }
+        ast::FieldDesc::Array { width: Some(width), size: Some(size), .. } => {
+            let field_type = Integer::new(*width);
+            let size = proc_macro2::Literal::usize_unsuffixed(*size);
+            quote!([#field_type; #size])
+        }
+        ast::FieldDesc::Array { width: Some(width), size: None, .. } => {
+            let field_type = Integer::new(*width);
+            quote!(Vec<#field_type>)
+        }
+        ast::FieldDesc::Array { type_id: Some(type_id), size: Some(size), .. } => {
+            let field_type = type_id.to_ident();
+            let size = proc_macro2::Literal::usize_unsuffixed(*size);
+            quote!([#field_type; #size])
+        }
+        ast::FieldDesc::Array { type_id: Some(type_id), size: None, .. } => {
+            let field_type = type_id.to_ident();
+            quote!(Vec<#field_type>)
+        }
+        //ast::Field::Size { .. } | ast::Field::Count { .. } => quote!(),
+        _ => todo!("{field:?}"),
+    }
+}
+
+pub fn rust_borrow(field: &ast::Field, scope: &analyzer::Scope<'_>) -> proc_macro2::TokenStream {
+    match &field.desc {
+        ast::FieldDesc::Scalar { .. } => quote!(),
+        ast::FieldDesc::Typedef { type_id, .. } => match &scope.typedef[type_id].desc {
+            ast::DeclDesc::Enum { .. } => quote!(),
+            ast::DeclDesc::Struct { .. } => quote!(&),
+            ast::DeclDesc::CustomField { .. } => quote!(),
+            desc => unreachable!("unexpected declaration: {desc:?}"),
+        },
+        ast::FieldDesc::Array { .. } => quote!(&),
+        _ => todo!(),
+    }
+}
+
+/// Suffix for `Buf::get_*` and `BufMut::put_*` methods when reading a
+/// value with the given `width`.
+fn endianness_suffix(endianness: ast::EndiannessValue, width: usize) -> &'static str {
+    if width > 8 && endianness == ast::EndiannessValue::LittleEndian {
+        "_le"
+    } else {
+        ""
+    }
+}
+
+/// Parse an unsigned integer with the given `width`.
+///
+/// The generated code requires that `span` is a mutable `bytes::Buf`
+/// value.
+pub fn get_uint(
+    endianness: ast::EndiannessValue,
+    width: usize,
+    span: &proc_macro2::Ident,
+) -> proc_macro2::TokenStream {
+    let suffix = endianness_suffix(endianness, width);
+    let value_type = Integer::new(width);
+    if value_type.width == width {
+        let get_u = format_ident!("get_u{}{}", value_type.width, suffix);
+        quote! {
+            #span.get_mut().#get_u()
+        }
+    } else {
+        let get_uint = format_ident!("get_uint{}", suffix);
+        let value_nbytes = proc_macro2::Literal::usize_unsuffixed(width / 8);
+        let cast = (value_type.width < 64).then(|| quote!(as #value_type));
+        quote! {
+            #span.get_mut().#get_uint(#value_nbytes) #cast
+        }
+    }
+}
+
+/// Write an unsigned integer `value` to `span`.
+///
+/// The generated code requires that `span` is a mutable
+/// `bytes::BufMut` value.
+pub fn put_uint(
+    endianness: ast::EndiannessValue,
+    value: &proc_macro2::TokenStream,
+    width: usize,
+    span: &proc_macro2::Ident,
+) -> proc_macro2::TokenStream {
+    let suffix = endianness_suffix(endianness, width);
+    let value_type = Integer::new(width);
+    if value_type.width == width {
+        let put_u = format_ident!("put_u{}{}", width, suffix);
+        quote! {
+            #span.#put_u(#value)
+        }
+    } else {
+        let put_uint = format_ident!("put_uint{}", suffix);
+        let value_nbytes = proc_macro2::Literal::usize_unsuffixed(width / 8);
+        let cast = (value_type.width < 64).then(|| quote!(as u64));
+        quote! {
+            #span.#put_uint(#value #cast, #value_nbytes)
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_integer_new() {
+        assert_eq!(Integer::new(0).width, 8);
+        assert_eq!(Integer::new(8).width, 8);
+        assert_eq!(Integer::new(9).width, 16);
+        assert_eq!(Integer::new(64).width, 64);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_integer_new_panics_on_large_width() {
+        Integer::new(65);
+    }
+}
diff --git a/src/backends/rust_no_allocation/mod.rs b/src/backends/rust_no_allocation/mod.rs
index c98bc12..8bf7e57 100644
--- a/src/backends/rust_no_allocation/mod.rs
+++ b/src/backends/rust_no_allocation/mod.rs
@@ -37,7 +37,6 @@
 use quote::quote;
 
 use crate::ast;
-use crate::parser;
 
 use self::{
     enums::generate_enum, packet_parser::generate_packet,
@@ -46,7 +45,7 @@
 
 use super::intermediate::Schema;
 
-pub fn generate(file: &parser::ast::File, schema: &Schema) -> Result<String, String> {
+pub fn generate(file: &ast::File, schema: &Schema) -> Result<String, String> {
     match file.endianness.value {
         ast::EndiannessValue::LittleEndian => {}
         _ => unimplemented!("Only little_endian endianness supported"),
@@ -80,7 +79,7 @@
 }
 
 fn generate_decl(
-    decl: &parser::ast::Decl,
+    decl: &ast::Decl,
     schema: &Schema,
     children: &HashMap<&str, Vec<&str>>,
 ) -> Result<TokenStream, String> {
diff --git a/src/backends/rust_no_allocation/packet_parser.rs b/src/backends/rust_no_allocation/packet_parser.rs
index bd07630..1f9fc0f 100644
--- a/src/backends/rust_no_allocation/packet_parser.rs
+++ b/src/backends/rust_no_allocation/packet_parser.rs
@@ -18,7 +18,6 @@
 use quote::{format_ident, quote};
 
 use crate::ast;
-use crate::parser;
 
 use crate::backends::intermediate::{
     ComputedOffsetId, ComputedValueId, PacketOrStruct, PacketOrStructLength, Schema,
@@ -29,7 +28,7 @@
 
 pub fn generate_packet(
     id: &str,
-    fields: &[parser::ast::Field],
+    fields: &[ast::Field],
     parent_id: Option<&str>,
     schema: &Schema,
     curr_schema: &PacketOrStruct,
diff --git a/src/backends/rust_no_allocation/packet_serializer.rs b/src/backends/rust_no_allocation/packet_serializer.rs
index c088b75..7b06944 100644
--- a/src/backends/rust_no_allocation/packet_serializer.rs
+++ b/src/backends/rust_no_allocation/packet_serializer.rs
@@ -23,7 +23,6 @@
         intermediate::{ComputedValue, ComputedValueId, PacketOrStruct, Schema},
         rust_no_allocation::utils::get_integer_type,
     },
-    parser,
 };
 
 fn standardize_child(id: &str) -> &str {
@@ -36,7 +35,7 @@
 pub fn generate_packet_serializer(
     id: &str,
     parent_id: Option<&str>,
-    fields: &[parser::ast::Field],
+    fields: &[ast::Field],
     schema: &Schema,
     curr_schema: &PacketOrStruct,
     children: &HashMap<&str, Vec<&str>>,
diff --git a/src/backends/rust_no_allocation/utils.rs b/src/backends/rust_no_allocation/utils.rs
index a9286de..ffb7cb0 100644
--- a/src/backends/rust_no_allocation/utils.rs
+++ b/src/backends/rust_no_allocation/utils.rs
@@ -23,3 +23,14 @@
         .unwrap_or_else(|| panic!("width {width} is too large"));
     format_ident!("u{best_width}")
 }
+
+/// Generate a block of code.
+///
+/// Like `quote!`, but the code block will be followed by an empty
+/// line of code. This makes the generated code more readable.
+#[macro_export]
+macro_rules! quote_block {
+    ($($tt:tt)*) => {
+        format!("{}\n\n", ::quote::quote!($($tt)*))
+    }
+}
diff --git a/src/main.rs b/src/main.rs
index 8992d29..e8fce66 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -24,8 +24,8 @@
 enum OutputFormat {
     JSON,
     Rust,
+    RustLegacy,
     RustNoAlloc,
-    RustNoAllocTest,
 }
 
 impl std::str::FromStr for OutputFormat {
@@ -35,8 +35,8 @@
         match input.to_lowercase().as_str() {
             "json" => Ok(Self::JSON),
             "rust" => Ok(Self::Rust),
+            "rust_legacy" => Ok(Self::RustLegacy),
             "rust_no_alloc" => Ok(Self::RustNoAlloc),
-            "rust_no_alloc_test" => Ok(Self::RustNoAllocTest),
             _ => Err(format!("could not parse {:?}, valid option are 'json', 'rust', 'rust_no_alloc', and 'rust_no_alloc_test'.", input)),
         }
     }
@@ -50,10 +50,18 @@
     version: bool,
 
     #[argh(option, default = "OutputFormat::JSON")]
-    /// generate output in this format ("json", "rust", "rust_no_alloc", "rust_no_alloc_test"). The output
-    /// will be printed on stdout in both cases.
+    /// generate output in this format ("json", "rust", "rust_legacy", "rust_no_alloc").
+    /// The output will be printed on stdout in all cases.
+    /// The input file is the source PDL file.
     output_format: OutputFormat,
 
+    #[argh(switch)]
+    /// generate tests for the selected output format.
+    /// Valid for the output formats "rust_legacy", "rust_no_alloc".
+    /// The input file must point to a JSON formatterd file with the list of
+    /// test vectors.
+    tests: bool,
+
     #[argh(positional)]
     /// input file.
     input_file: String,
@@ -61,13 +69,15 @@
     #[argh(option)]
     /// exclude declarations from the generated output.
     exclude_declaration: Vec<String>,
+
+    #[argh(option)]
+    /// custom_field import paths.
+    /// For the rust backend this is a path e.g. "module::CustomField" or "super::CustomField".
+    custom_field: Vec<String>,
 }
 
 /// Remove declarations listed in the input filter.
-fn filter_declarations(
-    file: parser::ast::File,
-    exclude_declarations: &[String],
-) -> parser::ast::File {
+fn filter_declarations(file: ast::File, exclude_declarations: &[String]) -> ast::File {
     ast::File {
         declarations: file
             .declarations
@@ -80,14 +90,7 @@
     }
 }
 
-fn main() -> Result<(), String> {
-    let opt: Opt = argh::from_env();
-
-    if opt.version {
-        println!("Packet Description Language parser version 1.0");
-        return Ok(());
-    }
-
+fn generate_backend(opt: &Opt) -> Result<(), String> {
     let mut sources = ast::SourceDatabase::new();
     match parser::parse_file(&mut sources, &opt.input_file) {
         Ok(file) => {
@@ -111,18 +114,18 @@
                     println!("{}", backends::json::generate(&file).unwrap())
                 }
                 OutputFormat::Rust => {
-                    println!("{}", backends::rust::generate(&sources, &analyzed_file))
+                    println!(
+                        "{}",
+                        backends::rust::generate(&sources, &analyzed_file, &opt.custom_field)
+                    )
+                }
+                OutputFormat::RustLegacy => {
+                    println!("{}", backends::rust_legacy::generate(&sources, &analyzed_file))
                 }
                 OutputFormat::RustNoAlloc => {
                     let schema = backends::intermediate::generate(&file).unwrap();
                     println!("{}", backends::rust_no_allocation::generate(&file, &schema).unwrap())
                 }
-                OutputFormat::RustNoAllocTest => {
-                    println!(
-                        "{}",
-                        backends::rust_no_allocation::test::generate_test_file().unwrap()
-                    )
-                }
             }
             Ok(())
         }
@@ -135,3 +138,39 @@
         }
     }
 }
+
+fn generate_tests(opt: &Opt) -> Result<(), String> {
+    match opt.output_format {
+        OutputFormat::Rust => {
+            println!("{}", backends::rust::test::generate_tests(&opt.input_file)?)
+        }
+        OutputFormat::RustLegacy => {
+            println!("{}", backends::rust_legacy::test::generate_tests(&opt.input_file)?)
+        }
+        OutputFormat::RustNoAlloc => {
+            println!("{}", backends::rust_no_allocation::test::generate_test_file()?)
+        }
+        _ => {
+            return Err(format!(
+                "Canonical tests cannot be generated for the format {:?}",
+                opt.output_format
+            ))
+        }
+    }
+    Ok(())
+}
+
+fn main() -> Result<(), String> {
+    let opt: Opt = argh::from_env();
+
+    if opt.version {
+        println!("Packet Description Language parser version 1.0");
+        return Ok(());
+    }
+
+    if opt.tests {
+        generate_tests(&opt)
+    } else {
+        generate_backend(&opt)
+    }
+}
diff --git a/src/parser.rs b/src/parser.rs
index 29407ff..57b42b4 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -12,28 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+use crate::ast;
 use codespan_reporting::diagnostic::Diagnostic;
 use codespan_reporting::files;
 use pest::iterators::{Pair, Pairs};
 use pest::{Parser, Token};
 use std::iter::{Filter, Peekable};
 
-pub mod ast {
-    use serde::Serialize;
-
-    #[derive(Debug, Serialize, Clone, Default, PartialEq, Eq)]
-    pub struct Annotation;
-
-    impl crate::ast::Annotation for Annotation {
-        type FieldAnnotation = ();
-        type DeclAnnotation = ();
-    }
-
-    pub type Field = crate::ast::Field<Annotation>;
-    pub type Decl = crate::ast::Decl<Annotation>;
-    pub type File = crate::ast::File<Annotation>;
-}
-
 // Generate the PDL parser.
 //
 // TODO:
@@ -191,26 +176,40 @@
 
 type Node<'i> = Pair<'i, Rule>;
 type NodeIterator<'i> = Peekable<Filter<Pairs<'i, Rule>, fn(&Node<'i>) -> bool>>;
-type Context<'a> = (crate::ast::FileId, &'a Vec<usize>);
+struct Context<'a> {
+    file: ast::FileId,
+    line_starts: &'a Vec<usize>,
+    key: std::cell::Cell<usize>,
+}
 
 trait Helpers<'i> {
     fn children(self) -> NodeIterator<'i>;
-    fn as_loc(&self, context: &Context) -> crate::ast::SourceRange;
+    fn as_loc(&self, context: &Context) -> ast::SourceRange;
     fn as_string(&self) -> String;
     fn as_usize(&self) -> Result<usize, String>;
 }
 
+impl<'a> Context<'a> {
+    fn field_key(&self) -> ast::FieldKey {
+        ast::FieldKey(self.key.replace(self.key.get() + 1))
+    }
+
+    fn decl_key(&self) -> ast::DeclKey {
+        ast::DeclKey(self.key.replace(self.key.get() + 1))
+    }
+}
+
 impl<'i> Helpers<'i> for Node<'i> {
     fn children(self) -> NodeIterator<'i> {
         self.into_inner().filter((|n| n.as_rule() != Rule::COMMENT) as fn(&Self) -> bool).peekable()
     }
 
-    fn as_loc(&self, context: &Context) -> crate::ast::SourceRange {
+    fn as_loc(&self, context: &Context) -> ast::SourceRange {
         let span = self.as_span();
-        crate::ast::SourceRange {
-            file: context.0,
-            start: crate::ast::SourceLocation::new(span.start_pos().pos(), context.1),
-            end: crate::ast::SourceLocation::new(span.end_pos().pos(), context.1),
+        ast::SourceRange {
+            file: context.file,
+            start: ast::SourceLocation::new(span.start_pos().pos(), context.line_starts),
+            end: ast::SourceLocation::new(span.end_pos().pos(), context.line_starts),
         }
     }
 
@@ -297,22 +296,22 @@
     maybe(iter, Rule::size_modifier).map(|n| n.as_string())
 }
 
-fn parse_endianness(node: Node<'_>, context: &Context) -> Result<crate::ast::Endianness, String> {
+fn parse_endianness(node: Node<'_>, context: &Context) -> Result<ast::Endianness, String> {
     if node.as_rule() != Rule::endianness_declaration {
         err_unexpected_rule(Rule::endianness_declaration, node.as_rule())
     } else {
-        Ok(crate::ast::Endianness {
+        Ok(ast::Endianness {
             loc: node.as_loc(context),
             value: match node.as_str().trim() {
-                "little_endian_packets" => crate::ast::EndiannessValue::LittleEndian,
-                "big_endian_packets" => crate::ast::EndiannessValue::BigEndian,
+                "little_endian_packets" => ast::EndiannessValue::LittleEndian,
+                "big_endian_packets" => ast::EndiannessValue::BigEndian,
                 _ => unreachable!(),
             },
         })
     }
 }
 
-fn parse_constraint(node: Node<'_>, context: &Context) -> Result<crate::ast::Constraint, String> {
+fn parse_constraint(node: Node<'_>, context: &Context) -> Result<ast::Constraint, String> {
     if node.as_rule() != Rule::constraint {
         err_unexpected_rule(Rule::constraint, node.as_rule())
     } else {
@@ -320,19 +319,19 @@
         let mut children = node.children();
         let id = parse_identifier(&mut children)?;
         let (tag_id, value) = parse_identifier_or_integer(&mut children)?;
-        Ok(crate::ast::Constraint { id, loc, value, tag_id })
+        Ok(ast::Constraint { id, loc, value, tag_id })
     }
 }
 
 fn parse_constraint_list_opt(
     iter: &mut NodeIterator<'_>,
     context: &Context,
-) -> Result<Vec<crate::ast::Constraint>, String> {
+) -> Result<Vec<ast::Constraint>, String> {
     maybe(iter, Rule::constraint_list)
         .map_or(Ok(vec![]), |n| n.children().map(|n| parse_constraint(n, context)).collect())
 }
 
-fn parse_enum_value(node: Node<'_>, context: &Context) -> Result<crate::ast::TagValue, String> {
+fn parse_enum_value(node: Node<'_>, context: &Context) -> Result<ast::TagValue, String> {
     if node.as_rule() != Rule::enum_value {
         err_unexpected_rule(Rule::enum_value, node.as_rule())
     } else {
@@ -340,19 +339,19 @@
         let mut children = node.children();
         let id = parse_identifier(&mut children)?;
         let value = parse_integer(&mut children)?;
-        Ok(crate::ast::TagValue { id, loc, value })
+        Ok(ast::TagValue { id, loc, value })
     }
 }
 
 fn parse_enum_value_list_opt(
     iter: &mut NodeIterator<'_>,
     context: &Context,
-) -> Result<Vec<crate::ast::TagValue>, String> {
+) -> Result<Vec<ast::TagValue>, String> {
     maybe(iter, Rule::enum_value_list)
         .map_or(Ok(vec![]), |n| n.children().map(|n| parse_enum_value(n, context)).collect())
 }
 
-fn parse_enum_range(node: Node<'_>, context: &Context) -> Result<crate::ast::TagRange, String> {
+fn parse_enum_range(node: Node<'_>, context: &Context) -> Result<ast::TagRange, String> {
     if node.as_rule() != Rule::enum_range {
         err_unexpected_rule(Rule::enum_range, node.as_rule())
     } else {
@@ -362,34 +361,34 @@
         let start = parse_integer(&mut children)?;
         let end = parse_integer(&mut children)?;
         let tags = parse_enum_value_list_opt(&mut children, context)?;
-        Ok(crate::ast::TagRange { id, loc, range: start..=end, tags })
+        Ok(ast::TagRange { id, loc, range: start..=end, tags })
     }
 }
 
-fn parse_enum_other(node: Node<'_>, context: &Context) -> Result<crate::ast::TagOther, String> {
+fn parse_enum_other(node: Node<'_>, context: &Context) -> Result<ast::TagOther, String> {
     if node.as_rule() != Rule::enum_other {
         err_unexpected_rule(Rule::enum_other, node.as_rule())
     } else {
         let loc = node.as_loc(context);
         let mut children = node.children();
         let id = parse_identifier(&mut children)?;
-        Ok(crate::ast::TagOther { id, loc })
+        Ok(ast::TagOther { id, loc })
     }
 }
 
-fn parse_enum_tag(node: Node<'_>, context: &Context) -> Result<crate::ast::Tag, String> {
+fn parse_enum_tag(node: Node<'_>, context: &Context) -> Result<ast::Tag, String> {
     if node.as_rule() != Rule::enum_tag {
         err_unexpected_rule(Rule::enum_tag, node.as_rule())
     } else {
         match node.children().next() {
             Some(node) if node.as_rule() == Rule::enum_value => {
-                Ok(crate::ast::Tag::Value(parse_enum_value(node, context)?))
+                Ok(ast::Tag::Value(parse_enum_value(node, context)?))
             }
             Some(node) if node.as_rule() == Rule::enum_range => {
-                Ok(crate::ast::Tag::Range(parse_enum_range(node, context)?))
+                Ok(ast::Tag::Range(parse_enum_range(node, context)?))
             }
             Some(node) if node.as_rule() == Rule::enum_other => {
-                Ok(crate::ast::Tag::Other(parse_enum_other(node, context)?))
+                Ok(ast::Tag::Other(parse_enum_other(node, context)?))
             }
             Some(node) => Err(format!(
                 "expected rule {:?} or {:?}, got {:?}",
@@ -409,7 +408,7 @@
 fn parse_enum_tag_list(
     iter: &mut NodeIterator<'_>,
     context: &Context,
-) -> Result<Vec<crate::ast::Tag>, String> {
+) -> Result<Vec<ast::Tag>, String> {
     expect(iter, Rule::enum_tag_list)
         .and_then(|n| n.children().map(|n| parse_enum_tag(n, context)).collect())
 }
@@ -421,18 +420,18 @@
     let cond = children.next();
     let rule = desc.as_rule();
     let mut children = desc.children();
-    Ok(crate::ast::Field {
+    Ok(ast::Field {
         loc,
-        annot: Default::default(),
+        key: context.field_key(),
         cond: cond.map(|constraint| parse_constraint(constraint, context)).transpose()?,
         desc: match rule {
             Rule::checksum_field => {
                 let field_id = parse_identifier(&mut children)?;
-                crate::ast::FieldDesc::Checksum { field_id }
+                ast::FieldDesc::Checksum { field_id }
             }
             Rule::padding_field => {
                 let size = parse_integer(&mut children)?;
-                crate::ast::FieldDesc::Padding { size }
+                ast::FieldDesc::Padding { size }
             }
             Rule::size_field => {
                 let field_id = match children.next() {
@@ -443,39 +442,39 @@
                     None => err_missing_rule(Rule::identifier)?,
                 };
                 let width = parse_integer(&mut children)?;
-                crate::ast::FieldDesc::Size { field_id, width }
+                ast::FieldDesc::Size { field_id, width }
             }
             Rule::count_field => {
                 let field_id = parse_identifier(&mut children)?;
                 let width = parse_integer(&mut children)?;
-                crate::ast::FieldDesc::Count { field_id, width }
+                ast::FieldDesc::Count { field_id, width }
             }
             Rule::elementsize_field => {
                 let field_id = parse_identifier(&mut children)?;
                 let width = parse_integer(&mut children)?;
-                crate::ast::FieldDesc::ElementSize { field_id, width }
+                ast::FieldDesc::ElementSize { field_id, width }
             }
-            Rule::body_field => crate::ast::FieldDesc::Body,
+            Rule::body_field => ast::FieldDesc::Body,
             Rule::payload_field => {
                 let size_modifier = parse_size_modifier_opt(&mut children);
-                crate::ast::FieldDesc::Payload { size_modifier }
+                ast::FieldDesc::Payload { size_modifier }
             }
             Rule::fixed_field => match children.next() {
                 Some(n) if n.as_rule() == Rule::integer => {
                     let value = n.as_usize()?;
                     let width = parse_integer(&mut children)?;
-                    crate::ast::FieldDesc::FixedScalar { width, value }
+                    ast::FieldDesc::FixedScalar { width, value }
                 }
                 Some(n) if n.as_rule() == Rule::identifier => {
                     let tag_id = n.as_string();
                     let enum_id = parse_identifier(&mut children)?;
-                    crate::ast::FieldDesc::FixedEnum { enum_id, tag_id }
+                    ast::FieldDesc::FixedEnum { enum_id, tag_id }
                 }
                 _ => unreachable!(),
             },
             Rule::reserved_field => {
                 let width = parse_integer(&mut children)?;
-                crate::ast::FieldDesc::Reserved { width }
+                ast::FieldDesc::Reserved { width }
             }
             Rule::array_field => {
                 let id = parse_identifier(&mut children)?;
@@ -493,22 +492,22 @@
                     }
                     None => (None, None),
                 };
-                crate::ast::FieldDesc::Array { id, type_id, width, size, size_modifier }
+                ast::FieldDesc::Array { id, type_id, width, size, size_modifier }
             }
             Rule::scalar_field => {
                 let id = parse_identifier(&mut children)?;
                 let width = parse_integer(&mut children)?;
-                crate::ast::FieldDesc::Scalar { id, width }
+                ast::FieldDesc::Scalar { id, width }
             }
             Rule::typedef_field => {
                 let id = parse_identifier(&mut children)?;
                 let type_id = parse_identifier(&mut children)?;
-                crate::ast::FieldDesc::Typedef { id, type_id }
+                ast::FieldDesc::Typedef { id, type_id }
             }
             Rule::group_field => {
                 let group_id = parse_identifier(&mut children)?;
                 let constraints = parse_constraint_list_opt(&mut children, context)?;
-                crate::ast::FieldDesc::Group { group_id, constraints }
+                ast::FieldDesc::Group { group_id, constraints }
             }
             _ => return Err(format!("expected rule *_field, got {:?}", rule)),
         },
@@ -530,7 +529,7 @@
 
 fn parse_toplevel(root: Node<'_>, context: &Context) -> Result<ast::File, String> {
     let mut toplevel_comments = vec![];
-    let mut file = crate::ast::File::new(context.0);
+    let mut file = ast::File::new(context.file);
 
     let mut comment_start = vec![];
     for token in root.clone().tokens() {
@@ -538,11 +537,11 @@
             Token::Start { rule: Rule::COMMENT, pos } => comment_start.push(pos),
             Token::End { rule: Rule::COMMENT, pos } => {
                 let start_pos = comment_start.pop().unwrap();
-                file.comments.push(crate::ast::Comment {
-                    loc: crate::ast::SourceRange {
-                        file: context.0,
-                        start: crate::ast::SourceLocation::new(start_pos.pos(), context.1),
-                        end: crate::ast::SourceLocation::new(pos.pos(), context.1),
+                file.comments.push(ast::Comment {
+                    loc: ast::SourceRange {
+                        file: context.file,
+                        start: ast::SourceLocation::new(start_pos.pos(), context.line_starts),
+                        end: ast::SourceLocation::new(pos.pos(), context.line_starts),
                     },
                     text: start_pos.span(&pos).as_str().to_owned(),
                 })
@@ -562,10 +561,11 @@
                 let id = parse_identifier(&mut children)?;
                 let width = parse_integer(&mut children)?;
                 let function = parse_string(&mut children)?;
-                file.declarations.push(crate::ast::Decl::new(
+                file.declarations.push(ast::Decl {
                     loc,
-                    crate::ast::DeclDesc::Checksum { id, function, width },
-                ))
+                    key: context.decl_key(),
+                    desc: ast::DeclDesc::Checksum { id, function, width },
+                })
             }
             Rule::custom_field_declaration => {
                 let mut children = node.children();
@@ -573,10 +573,11 @@
                 let id = parse_identifier(&mut children)?;
                 let width = parse_integer_opt(&mut children)?;
                 let function = parse_string(&mut children)?;
-                file.declarations.push(crate::ast::Decl::new(
+                file.declarations.push(ast::Decl {
                     loc,
-                    crate::ast::DeclDesc::CustomField { id, function, width },
-                ))
+                    key: context.decl_key(),
+                    desc: ast::DeclDesc::CustomField { id, function, width },
+                })
             }
             Rule::enum_declaration => {
                 let mut children = node.children();
@@ -584,10 +585,11 @@
                 let id = parse_identifier(&mut children)?;
                 let width = parse_integer(&mut children)?;
                 let tags = parse_enum_tag_list(&mut children, context)?;
-                file.declarations.push(crate::ast::Decl::new(
+                file.declarations.push(ast::Decl {
                     loc,
-                    crate::ast::DeclDesc::Enum { id, width, tags },
-                ))
+                    key: context.decl_key(),
+                    desc: ast::DeclDesc::Enum { id, width, tags },
+                })
             }
             Rule::packet_declaration => {
                 let mut children = node.children();
@@ -596,10 +598,11 @@
                 let parent_id = parse_identifier_opt(&mut children)?;
                 let constraints = parse_constraint_list_opt(&mut children, context)?;
                 let fields = parse_field_list_opt(&mut children, context)?;
-                file.declarations.push(crate::ast::Decl::new(
+                file.declarations.push(ast::Decl {
                     loc,
-                    crate::ast::DeclDesc::Packet { id, parent_id, constraints, fields },
-                ))
+                    key: context.decl_key(),
+                    desc: ast::DeclDesc::Packet { id, parent_id, constraints, fields },
+                })
             }
             Rule::struct_declaration => {
                 let mut children = node.children();
@@ -608,18 +611,22 @@
                 let parent_id = parse_identifier_opt(&mut children)?;
                 let constraints = parse_constraint_list_opt(&mut children, context)?;
                 let fields = parse_field_list_opt(&mut children, context)?;
-                file.declarations.push(crate::ast::Decl::new(
+                file.declarations.push(ast::Decl {
                     loc,
-                    crate::ast::DeclDesc::Struct { id, parent_id, constraints, fields },
-                ))
+                    key: context.decl_key(),
+                    desc: ast::DeclDesc::Struct { id, parent_id, constraints, fields },
+                })
             }
             Rule::group_declaration => {
                 let mut children = node.children();
                 expect(&mut children, Rule::GROUP)?;
                 let id = parse_identifier(&mut children)?;
                 let fields = parse_field_list(&mut children, context)?;
-                file.declarations
-                    .push(crate::ast::Decl::new(loc, crate::ast::DeclDesc::Group { id, fields }))
+                file.declarations.push(ast::Decl {
+                    loc,
+                    key: context.decl_key(),
+                    desc: ast::DeclDesc::Group { id, fields },
+                })
             }
             Rule::test_declaration => {}
             Rule::EOI => (),
@@ -627,6 +634,7 @@
         }
     }
     file.comments.append(&mut toplevel_comments);
+    file.max_key = context.key.get();
     Ok(file)
 }
 
@@ -635,10 +643,10 @@
 /// The file is added to the compilation database under the provided
 /// name.
 pub fn parse_inline(
-    sources: &mut crate::ast::SourceDatabase,
+    sources: &mut ast::SourceDatabase,
     name: &str,
     source: String,
-) -> Result<ast::File, Diagnostic<crate::ast::FileId>> {
+) -> Result<ast::File, Diagnostic<ast::FileId>> {
     let root = PDLParser::parse(Rule::file, &source)
         .map_err(|e| {
             Diagnostic::error()
@@ -648,7 +656,8 @@
         .unwrap();
     let line_starts: Vec<_> = files::line_starts(&source).collect();
     let file = sources.add(name.to_owned(), source.clone());
-    parse_toplevel(root, &(file, &line_starts)).map_err(|e| Diagnostic::error().with_message(e))
+    parse_toplevel(root, &Context { file, line_starts: &line_starts, key: std::cell::Cell::new(0) })
+        .map_err(|e| Diagnostic::error().with_message(e))
 }
 
 /// Parse a new source file.
@@ -657,9 +666,9 @@
 /// database. Returns the constructed AST, or a descriptive error
 /// message in case of syntax error.
 pub fn parse_file(
-    sources: &mut crate::ast::SourceDatabase,
+    sources: &mut ast::SourceDatabase,
     name: &str,
-) -> Result<ast::File, Diagnostic<crate::ast::FileId>> {
+) -> Result<ast::File, Diagnostic<ast::FileId>> {
     let source = std::fs::read_to_string(name).map_err(|e| {
         Diagnostic::error().with_message(format!("failed to read input file '{}': {}", name, e))
     })?;
@@ -674,10 +683,10 @@
     fn endianness_is_set() {
         // The file starts out with a placeholder little-endian value.
         // This tests that we update it while parsing.
-        let mut db = crate::ast::SourceDatabase::new();
+        let mut db = ast::SourceDatabase::new();
         let file = parse_inline(&mut db, "stdin", String::from("  big_endian_packets  ")).unwrap();
-        assert_eq!(file.endianness.value, crate::ast::EndiannessValue::BigEndian);
-        assert_ne!(file.endianness.loc, crate::ast::SourceRange::default());
+        assert_eq!(file.endianness.value, ast::EndiannessValue::BigEndian);
+        assert_ne!(file.endianness.loc, ast::SourceRange::default());
     }
 
     #[test]
@@ -709,7 +718,7 @@
     fn test_no_whitespace_between_keywords() {
         // Validate that the parser rejects inputs where whitespaces
         // are not applied between alphabetical keywords and identifiers.
-        let mut db = crate::ast::SourceDatabase::new();
+        let mut db = ast::SourceDatabase::new();
         assert!(parse_inline(
             &mut db,
             "test",
diff --git a/tests/canonical/le_rust_test_file.pdl b/tests/canonical/le_rust_test_file.pdl
deleted file mode 100644
index cdb20b3..0000000
--- a/tests/canonical/le_rust_test_file.pdl
+++ /dev/null
@@ -1,573 +0,0 @@
-little_endian_packets
-
-// Preliminary definitions
-
-enum MaxDiscriminantEnum : 64 {
-     Max = 0xffffffffffffffff,
-}
-
-enum Enum7 : 7 {
-    A = 1,
-    B = 2,
-}
-
-enum Enum16 : 16 {
-    A = 0xaabb,
-    B = 0xccdd,
-}
-
-struct SizedStruct {
-    a: 8,
-}
-
-struct UnsizedStruct {
-    _size_(array): 2,
-    _reserved_: 6,
-    array: 8[],
-}
-
-packet ScalarParent {
-    a: 8,
-    _size_(_payload_): 8,
-    _payload_
-}
-
-packet EnumParent {
-    a: Enum16,
-    _size_(_payload_): 8,
-    _payload_
-}
-
-// Packet bit fields
-
-// The parser must be able to handle bit fields with scalar values
-// up to 64 bits wide.  The parser should generate a static size guard.
-packet Packet_Scalar_Field {
-    a: 7,
-    c: 57,
-}
-
-// The parser must be able to handle bit fields with enum values
-// up to 64 bits wide.  The parser should generate a static size guard.
-packet Packet_Enum_Field {
-    a: Enum7,
-    c: 57,
-}
-
-// The parser must be able to handle bit fields with reserved fields
-// up to 64 bits wide.  The parser should generate a static size guard.
-packet Packet_Reserved_Field {
-    a: 7,
-    _reserved_: 2,
-    c: 55,
-}
-
-// The parser must be able to handle bit fields with size fields
-// up to 64 bits wide.  The parser should generate a static size guard.
-packet Packet_Size_Field {
-    _size_(b): 3,
-    a: 61,
-    b: 8[],
-}
-
-// The parser must be able to handle bit fields with count fields
-// up to 64 bits wide.  The parser should generate a static size guard.
-packet Packet_Count_Field {
-    _count_(b): 3,
-    a: 61,
-    b: 8[],
-}
-
-// The parser must be able to handle bit fields with fixed scalar values
-// up to 64 bits wide.  The parser should generate a static size guard.
-packet Packet_FixedScalar_Field {
-    _fixed_ = 7 : 7,
-    b: 57,
-}
-
-// The parser must be able to handle bit fields with fixed enum values
-// up to 64 bits wide. The parser should generate a static size guard.
-packet Packet_FixedEnum_Field {
-    _fixed_ = A : Enum7,
-    b: 57,
-}
-
-// Packet payload fields
-
-// The parser must be able to handle sized payload fields without
-// size modifier.
-packet Packet_Payload_Field_VariableSize {
-    _size_(_payload_): 3,
-    _reserved_: 5,
-    _payload_
-}
-
-// The parser must be able to handle payload fields of unkonwn size followed
-// by fields of statically known size. The remaining span is integrated
-// in the packet.
-packet Packet_Payload_Field_UnknownSize {
-    _payload_,
-    a: 16,
-}
-
-// The parser must be able to handle payload fields of unkonwn size.
-// The remaining span is integrated in the packet.
-packet Packet_Payload_Field_UnknownSize_Terminal {
-    a: 16,
-    _payload_,
-}
-
-// Packet body fields
-
-// The parser must be able to handle sized body fields without
-// size modifier when the packet has no children.
-packet Packet_Body_Field_VariableSize {
-    _size_(_body_): 3,
-    _reserved_: 5,
-    _body_
-}
-
-// The parser must be able to handle body fields of unkonwn size followed
-// by fields of statically known size. The remaining span is integrated
-// in the packet.
-packet Packet_Body_Field_UnknownSize {
-    _body_,
-    a: 16,
-}
-
-// The parser must be able to handle body fields of unkonwn size.
-// The remaining span is integrated in the packet.
-packet Packet_Body_Field_UnknownSize_Terminal {
-    a: 16,
-    _body_,
-}
-
-// Packet typedef fields
-
-// The parser must be able to handle struct fields.
-// The size guard is generated by the Struct parser.
-packet Packet_Struct_Field {
-    a: SizedStruct,
-    b: UnsizedStruct,
-}
-
-
-// Array field configurations.
-// Add constructs for all configurations of type, size, and padding:
-//
-// - type: u8, u16, enum, struct with static size, struct with dynamic size
-// - size: constant, with size field, with count field, unspecified
-//
-// The type u8 is tested separately since it is likely to be handled
-// idiomatically by the specific language generators.
-packet Packet_Array_Field_ByteElement_ConstantSize {
-    array: 8[4],
-}
-
-packet Packet_Array_Field_ByteElement_VariableSize {
-    _size_(array) : 4,
-    _reserved_: 4,
-    array: 8[],
-}
-
-packet Packet_Array_Field_ByteElement_VariableCount {
-    _count_(array) : 4,
-    _reserved_: 4,
-    array: 8[],
-}
-
-packet Packet_Array_Field_ByteElement_UnknownSize {
-    array: 8[],
-}
-
-packet Packet_Array_Field_ScalarElement_ConstantSize {
-    array: 16[4],
-}
-
-packet Packet_Array_Field_ScalarElement_VariableSize {
-    _size_(array) : 4,
-    _reserved_: 4,
-    array: 16[],
-}
-
-packet Packet_Array_Field_ScalarElement_VariableCount {
-    _count_(array) : 4,
-    _reserved_: 4,
-    array: 16[],
-}
-
-packet Packet_Array_Field_ScalarElement_UnknownSize {
-    array: 16[],
-}
-
-packet Packet_Array_Field_EnumElement_ConstantSize {
-    array: Enum16[4],
-}
-
-packet Packet_Array_Field_EnumElement_VariableSize {
-    _size_(array) : 4,
-    _reserved_: 4,
-    array: Enum16[],
-}
-
-packet Packet_Array_Field_EnumElement_VariableCount {
-    _count_(array) : 4,
-    _reserved_: 4,
-    array: Enum16[],
-}
-
-packet Packet_Array_Field_EnumElement_UnknownSize {
-    array: Enum16[],
-}
-
-packet Packet_Array_Field_SizedElement_ConstantSize {
-    array: SizedStruct[4],
-}
-
-packet Packet_Array_Field_SizedElement_VariableSize {
-    _size_(array) : 4,
-    _reserved_: 4,
-    array: SizedStruct[],
-}
-
-packet Packet_Array_Field_SizedElement_VariableCount {
-    _count_(array) : 4,
-    _reserved_: 4,
-    array: SizedStruct[],
-}
-
-packet Packet_Array_Field_SizedElement_UnknownSize {
-    array: SizedStruct[],
-}
-
-packet Packet_Array_Field_UnsizedElement_ConstantSize {
-    array: UnsizedStruct[4],
-}
-
-packet Packet_Array_Field_UnsizedElement_VariableSize {
-    _size_(array) : 4,
-    _reserved_: 4,
-    array: UnsizedStruct[],
-}
-
-packet Packet_Array_Field_UnsizedElement_VariableCount {
-    _count_(array) : 4,
-    _reserved_: 4,
-    array: UnsizedStruct[],
-}
-
-packet Packet_Array_Field_UnsizedElement_UnknownSize {
-    array: UnsizedStruct[],
-}
-
-// The parser must be able to handle arrays with padded size.
-packet Packet_Array_Field_SizedElement_VariableSize_Padded {
-    _size_(array) : 4,
-    _reserved_: 4,
-    array: 16[],
-    _padding_ [16],
-}
-
-// The parser must be able to handle arrays with padded size.
-packet Packet_Array_Field_UnsizedElement_VariableCount_Padded {
-    _count_(array) : 8,
-    array: UnsizedStruct[],
-    _padding_ [16],
-}
-
-// Packet inheritance
-
-// The parser must handle specialization into
-// any child packet of a parent packet with scalar constraints.
-packet ScalarChild_A : ScalarParent (a = 0) {
-    b: 8,
-}
-
-// The parser must handle specialization into
-// any child packet of a parent packet with scalar constraints.
-packet ScalarChild_B : ScalarParent (a = 1) {
-    c: 16,
-}
-
-// The parser must handle specialization into
-// any child packet of a parent packet with enum constraints.
-packet EnumChild_A : EnumParent (a = A) {
-    b: 8,
-}
-
-// The parser must handle specialization into
-// any child packet of a parent packet with enum constraints.
-packet EnumChild_B : EnumParent (a = B) {
-    c: 16,
-}
-
-// Struct bit fields
-
-// The parser must be able to handle bit fields with scalar values
-// up to 64 bits wide.  The parser should generate a static size guard.
-struct Struct_Scalar_Field {
-    a: 7,
-    c: 57,
-}
-
-// The parser must be able to handle bit fields with enum values
-// up to 64 bits wide.  The parser should generate a static size guard.
-struct Struct_Enum_Field_ {
-    a: Enum7,
-    c: 57,
-}
-packet Struct_Enum_Field {
-    s: Struct_Enum_Field_,
-}
-
-// The parser must be able to handle bit fields with reserved fields
-// up to 64 bits wide.  The parser should generate a static size guard.
-struct Struct_Reserved_Field_ {
-    a: 7,
-    _reserved_: 2,
-    c: 55,
-}
-packet Struct_Reserved_Field {
-    s: Struct_Reserved_Field_,
-}
-
-// The parser must be able to handle bit fields with size fields
-// up to 64 bits wide.  The parser should generate a static size guard.
-struct Struct_Size_Field_ {
-    _size_(b): 3,
-    a: 61,
-    b: 8[],
-}
-packet Struct_Size_Field {
-    s: Struct_Size_Field_,
-}
-
-// The parser must be able to handle bit fields with count fields
-// up to 64 bits wide.  The parser should generate a static size guard.
-struct Struct_Count_Field_ {
-    _count_(b): 3,
-    a: 61,
-    b: 8[],
-}
-packet Struct_Count_Field {
-    s: Struct_Count_Field_,
-}
-// The parser must be able to handle bit fields with fixed scalar values
-// up to 64 bits wide.  The parser should generate a static size guard.
-struct Struct_FixedScalar_Field_ {
-    _fixed_ = 7 : 7,
-    b: 57,
-}
-packet Struct_FixedScalar_Field {
-    s: Struct_FixedScalar_Field_,
-}
-
-// The parser must be able to handle bit fields with fixed enum values
-// up to 64 bits wide. The parser should generate a static size guard.
-struct Struct_FixedEnum_Field_ {
-    _fixed_ = A : Enum7,
-    b: 57,
-}
-packet Struct_FixedEnum_Field {
-    s: Struct_FixedEnum_Field_,
-}
-
-// Struct typedef fields
-
-// The parser must be able to handle struct fields.
-// The size guard is generated by the Struct parser.
-packet Struct_Struct_Field {
-    a: SizedStruct,
-    b: UnsizedStruct,
-}
-
-// Array field configurations.
-// Add constructs for all configurations of type, size, and padding:
-//
-// - type: u8, u16, enum, struct with static size, struct with dynamic size
-// - size: constant, with size field, with count field, unspecified
-//
-// The type u8 is tested separately since it is likely to be handled
-// idiomatically by the specific language generators.
-
-struct Struct_Array_Field_ByteElement_ConstantSize_ {
-    array: 8[4],
-}
-packet Struct_Array_Field_ByteElement_ConstantSize {
-    s: Struct_Array_Field_ByteElement_ConstantSize_,
-}
-
-
-struct Struct_Array_Field_ByteElement_VariableSize_ {
-    _size_(array) : 4,
-    _reserved_: 4,
-    array: 8[],
-}
-packet Struct_Array_Field_ByteElement_VariableSize {
-    s: Struct_Array_Field_ByteElement_VariableSize_,
-}
-
-struct Struct_Array_Field_ByteElement_VariableCount_ {
-    _count_(array) : 4,
-    _reserved_: 4,
-    array: 8[],
-}
-packet Struct_Array_Field_ByteElement_VariableCount {
-    s: Struct_Array_Field_ByteElement_VariableCount_,
-}
-
-struct Struct_Array_Field_ByteElement_UnknownSize_ {
-    array: 8[],
-}
-packet Struct_Array_Field_ByteElement_UnknownSize {
-    s: Struct_Array_Field_ByteElement_UnknownSize_,
-}
-
-struct Struct_Array_Field_ScalarElement_ConstantSize_ {
-    array: 16[4],
-}
-packet Struct_Array_Field_ScalarElement_ConstantSize {
-    s: Struct_Array_Field_ScalarElement_ConstantSize_,
-}
-
-struct Struct_Array_Field_ScalarElement_VariableSize_ {
-    _size_(array) : 4,
-    _reserved_: 4,
-    array: 16[],
-}
-packet Struct_Array_Field_ScalarElement_VariableSize {
-    s: Struct_Array_Field_ScalarElement_VariableSize_,
-}
-
-struct Struct_Array_Field_ScalarElement_VariableCount_ {
-    _count_(array) : 4,
-    _reserved_: 4,
-    array: 16[],
-}
-packet Struct_Array_Field_ScalarElement_VariableCount {
-    s: Struct_Array_Field_ScalarElement_VariableCount_,
-}
-
-struct Struct_Array_Field_ScalarElement_UnknownSize_ {
-    array: 16[],
-}
-packet Struct_Array_Field_ScalarElement_UnknownSize {
-    s: Struct_Array_Field_ScalarElement_UnknownSize_,
-}
-
-struct Struct_Array_Field_EnumElement_ConstantSize_ {
-    array: Enum16[4],
-}
-packet Struct_Array_Field_EnumElement_ConstantSize {
-    s: Struct_Array_Field_EnumElement_ConstantSize_,
-}
-
-struct Struct_Array_Field_EnumElement_VariableSize_ {
-    _size_(array) : 4,
-    _reserved_: 4,
-    array: Enum16[],
-}
-packet Struct_Array_Field_EnumElement_VariableSize {
-    s: Struct_Array_Field_EnumElement_VariableSize_,
-}
-
-struct Struct_Array_Field_EnumElement_VariableCount_ {
-    _count_(array) : 4,
-    _reserved_: 4,
-    array: Enum16[],
-}
-packet Struct_Array_Field_EnumElement_VariableCount {
-    s: Struct_Array_Field_EnumElement_VariableCount_,
-}
-
-struct Struct_Array_Field_EnumElement_UnknownSize_ {
-    array: Enum16[],
-}
-packet Struct_Array_Field_EnumElement_UnknownSize {
-    s: Struct_Array_Field_EnumElement_UnknownSize_,
-}
-
-struct Struct_Array_Field_SizedElement_ConstantSize_ {
-    array: SizedStruct[4],
-}
-packet Struct_Array_Field_SizedElement_ConstantSize {
-    s: Struct_Array_Field_SizedElement_ConstantSize_,
-}
-
-struct Struct_Array_Field_SizedElement_VariableSize_ {
-    _size_(array) : 4,
-    _reserved_: 4,
-    array: SizedStruct[],
-}
-packet Struct_Array_Field_SizedElement_VariableSize {
-    s: Struct_Array_Field_SizedElement_VariableSize_,
-}
-
-struct Struct_Array_Field_SizedElement_VariableCount_ {
-    _count_(array) : 4,
-    _reserved_: 4,
-    array: SizedStruct[],
-}
-packet Struct_Array_Field_SizedElement_VariableCount {
-    s: Struct_Array_Field_SizedElement_VariableCount_,
-}
-
-struct Struct_Array_Field_SizedElement_UnknownSize_ {
-    array: SizedStruct[],
-}
-packet Struct_Array_Field_SizedElement_UnknownSize {
-    s: Struct_Array_Field_SizedElement_UnknownSize_,
-}
-
-struct Struct_Array_Field_UnsizedElement_ConstantSize_ {
-    array: UnsizedStruct[4],
-}
-packet Struct_Array_Field_UnsizedElement_ConstantSize {
-    s: Struct_Array_Field_UnsizedElement_ConstantSize_,
-}
-
-struct Struct_Array_Field_UnsizedElement_VariableSize_ {
-    _size_(array) : 4,
-    _reserved_: 4,
-    array: UnsizedStruct[],
-}
-packet Struct_Array_Field_UnsizedElement_VariableSize {
-    s: Struct_Array_Field_UnsizedElement_VariableSize_,
-}
-
-struct Struct_Array_Field_UnsizedElement_VariableCount_ {
-    _count_(array) : 4,
-    _reserved_: 4,
-    array: UnsizedStruct[],
-}
-packet Struct_Array_Field_UnsizedElement_VariableCount {
-    s: Struct_Array_Field_UnsizedElement_VariableCount_,
-}
-
-struct Struct_Array_Field_UnsizedElement_UnknownSize_ {
-    array: UnsizedStruct[],
-}
-packet Struct_Array_Field_UnsizedElement_UnknownSize {
-    s: Struct_Array_Field_UnsizedElement_UnknownSize_,
-}
-
-// The parser must be able to handle arrays with padded size.
-struct Struct_Array_Field_SizedElement_VariableSize_Padded_ {
-    _size_(array) : 4,
-    _reserved_: 4,
-    array: 16[],
-    _padding_ [16],
-}
-packet Struct_Array_Field_SizedElement_VariableSize_Padded {
-    s: Struct_Array_Field_SizedElement_VariableSize_Padded_,
-}
-
-// The parser must be able to handle arrays with padded size.
-struct Struct_Array_Field_UnsizedElement_VariableCount_Padded_ {
-    _count_(array) : 8,
-    array: UnsizedStruct[],
-    _padding_ [16],
-}
-packet Struct_Array_Field_UnsizedElement_VariableCount_Padded {
-    s: Struct_Array_Field_UnsizedElement_VariableCount_Padded_,
-}
diff --git a/tests/canonical/le_test_file.pdl b/tests/canonical/le_test_file.pdl
index fa87314..86f9c86 100644
--- a/tests/canonical/le_test_file.pdl
+++ b/tests/canonical/le_test_file.pdl
@@ -26,6 +26,10 @@
     array: 8[],
 }
 
+struct UnknownSizeStruct {
+    array: 8[],
+}
+
 group ScalarGroup {
     a: 16
 }
@@ -362,6 +366,36 @@
     _padding_ [16],
 }
 
+packet Packet_Array_Field_VariableElementSize_ConstantSize {
+    _elementsize_(array): 4,
+    _reserved_: 4,
+    array: UnknownSizeStruct[4],
+}
+
+packet Packet_Array_Field_VariableElementSize_VariableSize {
+    _size_(array) : 4,
+    _reserved_: 4,
+    _elementsize_(array): 4,
+    _reserved_: 4,
+    array: UnknownSizeStruct[],
+    tail: 8[],
+}
+
+packet Packet_Array_Field_VariableElementSize_VariableCount {
+    _count_(array) : 4,
+    _reserved_: 4,
+    _elementsize_(array): 4,
+    _reserved_: 4,
+    array: UnknownSizeStruct[],
+    tail: 8[],
+}
+
+packet Packet_Array_Field_VariableElementSize_UnknownSize {
+    _elementsize_(array): 4,
+    _reserved_: 4,
+    array: UnknownSizeStruct[],
+}
+
 packet Packet_Optional_Scalar_Field {
     c0: 1,
     c1: 1,
@@ -838,3 +872,101 @@
 packet Struct_Optional_Struct_Field {
     s: Struct_Optional_Struct_Field_,
 }
+
+// Enum declarations
+//
+// Test enum declarations with exhaustive configurations for the
+// following criterias:
+//
+//  1. truncated: is the enum width a multiple of 8 or not ?
+//     this characteristic has an impact for some language generators
+//  2. complete: does the enum define all possible values ?
+//  3. open: does the enum allow for unknown or undefined values ?
+//  4. with range: does the enum use a tag range declarations ?
+
+enum Enum_Incomplete_Truncated_Closed_ : 3 {
+    A = 0,
+    B = 1,
+}
+
+packet Enum_Incomplete_Truncated_Closed {
+    e: Enum_Incomplete_Truncated_Closed_,
+    _reserved_ : 5,
+}
+
+enum Enum_Incomplete_Truncated_Open_ : 3 {
+    A = 0,
+    B = 1,
+    UNKNOWN = ..
+}
+
+packet Enum_Incomplete_Truncated_Open {
+    e: Enum_Incomplete_Truncated_Open_,
+    _reserved_ : 5,
+}
+
+enum Enum_Incomplete_Truncated_Closed_WithRange_ : 3 {
+    A = 0,
+    B = 1..6 {
+        X = 1,
+        Y = 2,
+    }
+}
+
+packet Enum_Incomplete_Truncated_Closed_WithRange {
+    e: Enum_Incomplete_Truncated_Closed_WithRange_,
+    _reserved_ : 5,
+}
+
+enum Enum_Incomplete_Truncated_Open_WithRange_ : 3 {
+    A = 0,
+    B = 1..6 {
+        X = 1,
+        Y = 2,
+    },
+    UNKNOWN = ..
+}
+
+packet Enum_Incomplete_Truncated_Open_WithRange {
+    e: Enum_Incomplete_Truncated_Open_WithRange_,
+    _reserved_ : 5,
+}
+
+enum Enum_Complete_Truncated_ : 3 {
+    A = 0,
+    B = 1,
+    C = 2,
+    D = 3,
+    E = 4,
+    F = 5,
+    G = 6,
+    H = 7,
+}
+
+packet Enum_Complete_Truncated {
+    e: Enum_Complete_Truncated_,
+    _reserved_ : 5,
+}
+
+enum Enum_Complete_Truncated_WithRange_ : 3 {
+    A = 0,
+    B = 1..7 {
+        X = 1,
+        Y = 2,
+    }
+}
+
+packet Enum_Complete_Truncated_WithRange {
+    e: Enum_Complete_Truncated_WithRange_,
+    _reserved_ : 5,
+}
+
+enum Enum_Complete_WithRange_ : 8 {
+    A = 0,
+    B = 1,
+    C = 2..255,
+}
+
+packet Enum_Complete_WithRange {
+    e: Enum_Complete_WithRange_,
+}
diff --git a/tests/canonical/le_test_vectors.json b/tests/canonical/le_test_vectors.json
index 9ddff45..287c664 100644
--- a/tests/canonical/le_test_vectors.json
+++ b/tests/canonical/le_test_vectors.json
@@ -2155,6 +2155,164 @@
     ]
   },
   {
+    "packet": "Packet_Array_Field_VariableElementSize_ConstantSize",
+    "tests": [
+      {
+        "packed": "012a2b2c2d",
+        "unpacked": {
+          "array": [
+            {
+              "array": [42]
+            },
+            {
+              "array": [43]
+            },
+            {
+              "array": [44]
+            },
+            {
+              "array": [45]
+            }
+          ]
+        }
+      },
+      {
+        "packed": "022a2b2c2d2e2f3031",
+        "unpacked": {
+          "array": [
+            {
+              "array": [42, 43]
+            },
+            {
+              "array": [44, 45]
+            },
+            {
+              "array": [46, 47]
+            },
+            {
+              "array": [48, 49]
+            }
+          ]
+        }
+      }
+    ]
+  },
+  {
+    "packet": "Packet_Array_Field_VariableElementSize_VariableSize",
+    "tests": [
+      {
+        "packed": "01012a2b2c",
+        "unpacked": {
+          "array": [
+            {
+              "array": [42]
+            }
+          ],
+          "tail": [43, 44]
+        }
+      },
+      {
+        "packed": "02012a2b",
+        "unpacked": {
+          "array": [
+            {
+              "array": [42]
+            },
+            {
+              "array": [43]
+            }
+          ],
+          "tail": []
+        }
+      },
+      {
+        "packed": "02022a2b2c",
+        "unpacked": {
+          "array": [
+            {
+              "array": [42, 43]
+            }
+          ],
+          "tail": [44]
+        }
+      }
+    ]
+  },
+  {
+    "packet": "Packet_Array_Field_VariableElementSize_VariableCount",
+    "tests": [
+      {
+        "packed": "03012a2b2c2d",
+        "unpacked": {
+          "array": [
+            {
+              "array": [42]
+            },
+            {
+              "array": [43]
+            },
+            {
+              "array": [44]
+            }
+          ],
+          "tail": [45]
+        }
+      },
+      {
+        "packed": "02022a2b2c2d",
+        "unpacked": {
+          "array": [
+            {
+              "array": [42, 43]
+            },
+            {
+              "array": [44, 45]
+            }
+          ],
+          "tail": []
+        }
+      }
+    ]
+  },
+  {
+    "packet": "Packet_Array_Field_VariableElementSize_UnknownSize",
+    "tests": [
+      {
+        "packed": "012a",
+        "unpacked": {
+          "array": [
+            {
+              "array": [42]
+            }
+          ]
+        }
+      },
+      {
+        "packed": "012a2b",
+        "unpacked": {
+          "array": [
+            {
+              "array": [42]
+            },
+            {
+              "array": [43]
+            }
+          ]
+        }
+      },
+      {
+        "packed": "022a2b",
+        "unpacked": {
+          "array": [
+            {
+              "array": [42, 43]
+            }
+          ]
+        }
+      }
+    ]
+  },
+  {
     "packet": "Packet_Optional_Scalar_Field",
     "tests": [
       {
@@ -5095,5 +5253,232 @@
         }
       }
     ]
+  },
+  {
+    "packet": "Enum_Incomplete_Truncated_Closed",
+    "tests": [
+      {
+        "packed": "00",
+        "unpacked": {
+          "e": 0
+        }
+      },
+      {
+        "packed": "01",
+        "unpacked": {
+          "e": 1
+        }
+      }
+    ]
+  },
+  {
+    "packet": "Enum_Incomplete_Truncated_Open",
+    "tests": [
+      {
+        "packed": "00",
+        "unpacked": {
+          "e": 0
+        }
+      },
+      {
+        "packed": "01",
+        "unpacked": {
+          "e": 1
+        }
+      },
+      {
+        "packed": "02",
+        "unpacked": {
+          "e": 2
+        }
+      }
+    ]
+  },
+  {
+    "packet": "Enum_Incomplete_Truncated_Closed_WithRange",
+    "tests": [
+      {
+        "packed": "00",
+        "unpacked": {
+          "e": 0
+        }
+      },
+      {
+        "packed": "01",
+        "unpacked": {
+          "e": 1
+        }
+      },
+      {
+        "packed": "02",
+        "unpacked": {
+          "e": 2
+        }
+      }
+    ]
+  },
+  {
+    "packet": "Enum_Incomplete_Truncated_Open_WithRange",
+    "tests": [
+      {
+        "packed": "00",
+        "unpacked": {
+          "e": 0
+        }
+      },
+      {
+        "packed": "01",
+        "unpacked": {
+          "e": 1
+        }
+      },
+      {
+        "packed": "02",
+        "unpacked": {
+          "e": 2
+        }
+      },
+      {
+        "packed": "03",
+        "unpacked": {
+          "e": 3
+        }
+      }
+    ]
+  },
+  {
+    "packet": "Enum_Complete_Truncated",
+    "tests": [
+      {
+        "packed": "00",
+        "unpacked": {
+          "e": 0
+        }
+      },
+      {
+        "packed": "01",
+        "unpacked": {
+          "e": 1
+        }
+      },
+      {
+        "packed": "02",
+        "unpacked": {
+          "e": 2
+        }
+      },
+      {
+        "packed": "03",
+        "unpacked": {
+          "e": 3
+        }
+      },
+      {
+        "packed": "04",
+        "unpacked": {
+          "e": 4
+        }
+      },
+      {
+        "packed": "05",
+        "unpacked": {
+          "e": 5
+        }
+      },
+      {
+        "packed": "06",
+        "unpacked": {
+          "e": 6
+        }
+      },
+      {
+        "packed": "07",
+        "unpacked": {
+          "e": 7
+        }
+      }
+    ]
+  },
+  {
+    "packet": "Enum_Complete_Truncated_WithRange",
+    "tests": [
+      {
+        "packed": "00",
+        "unpacked": {
+          "e": 0
+        }
+      },
+      {
+        "packed": "01",
+        "unpacked": {
+          "e": 1
+        }
+      },
+      {
+        "packed": "02",
+        "unpacked": {
+          "e": 2
+        }
+      },
+      {
+        "packed": "03",
+        "unpacked": {
+          "e": 3
+        }
+      },
+      {
+        "packed": "04",
+        "unpacked": {
+          "e": 4
+        }
+      },
+      {
+        "packed": "05",
+        "unpacked": {
+          "e": 5
+        }
+      },
+      {
+        "packed": "06",
+        "unpacked": {
+          "e": 6
+        }
+      },
+      {
+        "packed": "07",
+        "unpacked": {
+          "e": 7
+        }
+      }
+    ]
+  },
+  {
+    "packet": "Enum_Complete_WithRange",
+    "tests": [
+      {
+        "packed": "00",
+        "unpacked": {
+          "e": 0
+        }
+      },
+      {
+        "packed": "01",
+        "unpacked": {
+          "e": 1
+        }
+      },
+      {
+        "packed": "02",
+        "unpacked": {
+          "e": 2
+        }
+      },
+      {
+        "packed": "ff",
+        "unpacked": {
+          "e": 255
+        }
+      }
+    ]
   }
 ]
diff --git a/tests/compile_rust_generated_files.sh b/tests/compile_rust_generated_files.sh
new file mode 100755
index 0000000..8cdd6aa
--- /dev/null
+++ b/tests/compile_rust_generated_files.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+
+set -euxo pipefail
+
+mkdir -p out/
+OUT_DIR="$(pwd)/out"
+
+# move to `pdl-compiler` directory
+cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." &> /dev/null
+
+mkdir -p "$OUT_DIR/generated_test/src"
+./tests/generated_files_compile.sh tests/generated/rust/*.rs > "$OUT_DIR/generated_test/src/lib.rs"
+
+cat <<EOT > "$OUT_DIR/generated_test/Cargo.toml"
+[package]
+name = "generated_test"
+version = "0.0.0"
+publish = false
+edition = "2021"
+
+[features]
+default = ["serde"]
+
+[dependencies]
+bytes = {version = "1.4.0", features = ["serde"]}
+thiserror = "1.0.47"
+serde_json = "1.0.86"
+
+[dependencies.serde]
+version = "1.0.145"
+features = ["default", "derive", "serde_derive", "std", "rc"]
+optional = true
+
+[dependencies.pdl-runtime]
+path = "../../pdl-runtime"
+
+[workspace]
+EOT
+
+cd "$OUT_DIR/generated_test"
+RUSTFLAGS=-Awarnings cargo build
diff --git a/tests/compile_rust_legacy_generated_files.sh b/tests/compile_rust_legacy_generated_files.sh
new file mode 100755
index 0000000..a461b8d
--- /dev/null
+++ b/tests/compile_rust_legacy_generated_files.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+
+set -euxo pipefail
+
+mkdir -p out/
+OUT_DIR="$(pwd)/out"
+
+# move to `pdl-compiler` directory
+cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." &> /dev/null
+
+mkdir -p "$OUT_DIR/generated_test/src"
+./tests/generated_files_compile.sh tests/generated/rust_legacy/*.rs > "$OUT_DIR/generated_test/src/lib.rs"
+
+cat <<EOT > "$OUT_DIR/generated_test/Cargo.toml"
+[package]
+name = "generated_test"
+version = "0.0.0"
+publish = false
+edition = "2021"
+
+[features]
+default = ["serde"]
+
+[dependencies]
+bytes = {version = "1.4.0", features = ["serde"]}
+thiserror = "1.0.47"
+serde_json = "1.0.86"
+
+[dependencies.serde]
+version = "1.0.145"
+features = ["default", "derive", "serde_derive", "std", "rc"]
+optional = true
+
+[dependencies.pdl-runtime]
+path = "../../pdl-runtime"
+
+[workspace]
+EOT
+
+cd "$OUT_DIR/generated_test"
+RUSTFLAGS=-Awarnings cargo build
diff --git a/tests/generated/custom_field_declaration_little_endian.rs b/tests/generated/custom_field_declaration_little_endian.rs
deleted file mode 100644
index eb70e2f..0000000
--- a/tests/generated/custom_field_declaration_little_endian.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-#![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, Copy, Hash, Eq, PartialEq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(from = "u32", into = "u32"))]
-pub struct ExactSize(u32);
-impl From<&ExactSize> for u32 {
-    fn from(value: &ExactSize) -> u32 {
-        value.0
-    }
-}
-impl From<ExactSize> for u32 {
-    fn from(value: ExactSize) -> u32 {
-        value.0
-    }
-}
-impl From<u32> for ExactSize {
-    fn from(value: u32) -> Self {
-        ExactSize(value)
-    }
-}
-#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(try_from = "u32", into = "u32"))]
-pub struct TruncatedSize(u32);
-impl From<&TruncatedSize> for u32 {
-    fn from(value: &TruncatedSize) -> u32 {
-        value.0
-    }
-}
-impl From<TruncatedSize> for u32 {
-    fn from(value: TruncatedSize) -> u32 {
-        value.0
-    }
-}
-impl TryFrom<u32> for TruncatedSize {
-    type Error = u32;
-    fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
-        if value > 0xff_ffff { Err(value) } else { Ok(TruncatedSize(value)) }
-    }
-}
diff --git a/tests/generated/enum_declaration_little_endian.rs b/tests/generated/enum_declaration_little_endian.rs
deleted file mode 100644
index bd90591..0000000
--- a/tests/generated/enum_declaration_little_endian.rs
+++ /dev/null
@@ -1,516 +0,0 @@
-#![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
-    }
-}
-#[repr(u64)]
-#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
-pub enum IncompleteTruncatedClosed {
-    A = 0x0,
-    B = 0x1,
-}
-impl TryFrom<u8> for IncompleteTruncatedClosed {
-    type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
-        match value {
-            0x0 => Ok(IncompleteTruncatedClosed::A),
-            0x1 => Ok(IncompleteTruncatedClosed::B),
-            _ => Err(value),
-        }
-    }
-}
-impl From<&IncompleteTruncatedClosed> for u8 {
-    fn from(value: &IncompleteTruncatedClosed) -> Self {
-        match value {
-            IncompleteTruncatedClosed::A => 0x0,
-            IncompleteTruncatedClosed::B => 0x1,
-        }
-    }
-}
-impl From<IncompleteTruncatedClosed> for u8 {
-    fn from(value: IncompleteTruncatedClosed) -> Self {
-        (&value).into()
-    }
-}
-impl From<IncompleteTruncatedClosed> for i8 {
-    fn from(value: IncompleteTruncatedClosed) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedClosed> for i16 {
-    fn from(value: IncompleteTruncatedClosed) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedClosed> for i32 {
-    fn from(value: IncompleteTruncatedClosed) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedClosed> for i64 {
-    fn from(value: IncompleteTruncatedClosed) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedClosed> for u16 {
-    fn from(value: IncompleteTruncatedClosed) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedClosed> for u32 {
-    fn from(value: IncompleteTruncatedClosed) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedClosed> for u64 {
-    fn from(value: IncompleteTruncatedClosed) -> Self {
-        u8::from(value) as Self
-    }
-}
-#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
-pub enum IncompleteTruncatedOpen {
-    A,
-    B,
-    Unknown(Private<u8>),
-}
-impl TryFrom<u8> for IncompleteTruncatedOpen {
-    type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
-        match value {
-            0x0 => Ok(IncompleteTruncatedOpen::A),
-            0x1 => Ok(IncompleteTruncatedOpen::B),
-            0..=0x7 => Ok(IncompleteTruncatedOpen::Unknown(Private(value))),
-            _ => Err(value),
-        }
-    }
-}
-impl From<&IncompleteTruncatedOpen> for u8 {
-    fn from(value: &IncompleteTruncatedOpen) -> Self {
-        match value {
-            IncompleteTruncatedOpen::A => 0x0,
-            IncompleteTruncatedOpen::B => 0x1,
-            IncompleteTruncatedOpen::Unknown(Private(value)) => *value,
-        }
-    }
-}
-impl From<IncompleteTruncatedOpen> for u8 {
-    fn from(value: IncompleteTruncatedOpen) -> Self {
-        (&value).into()
-    }
-}
-impl From<IncompleteTruncatedOpen> for i8 {
-    fn from(value: IncompleteTruncatedOpen) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedOpen> for i16 {
-    fn from(value: IncompleteTruncatedOpen) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedOpen> for i32 {
-    fn from(value: IncompleteTruncatedOpen) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedOpen> for i64 {
-    fn from(value: IncompleteTruncatedOpen) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedOpen> for u16 {
-    fn from(value: IncompleteTruncatedOpen) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedOpen> for u32 {
-    fn from(value: IncompleteTruncatedOpen) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedOpen> for u64 {
-    fn from(value: IncompleteTruncatedOpen) -> Self {
-        u8::from(value) as Self
-    }
-}
-#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
-pub enum IncompleteTruncatedClosedWithRange {
-    A,
-    X,
-    Y,
-    B(Private<u8>),
-}
-impl TryFrom<u8> for IncompleteTruncatedClosedWithRange {
-    type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
-        match value {
-            0x0 => Ok(IncompleteTruncatedClosedWithRange::A),
-            0x1 => Ok(IncompleteTruncatedClosedWithRange::X),
-            0x2 => Ok(IncompleteTruncatedClosedWithRange::Y),
-            0x1..=0x6 => Ok(IncompleteTruncatedClosedWithRange::B(Private(value))),
-            _ => Err(value),
-        }
-    }
-}
-impl From<&IncompleteTruncatedClosedWithRange> for u8 {
-    fn from(value: &IncompleteTruncatedClosedWithRange) -> Self {
-        match value {
-            IncompleteTruncatedClosedWithRange::A => 0x0,
-            IncompleteTruncatedClosedWithRange::X => 0x1,
-            IncompleteTruncatedClosedWithRange::Y => 0x2,
-            IncompleteTruncatedClosedWithRange::B(Private(value)) => *value,
-        }
-    }
-}
-impl From<IncompleteTruncatedClosedWithRange> for u8 {
-    fn from(value: IncompleteTruncatedClosedWithRange) -> Self {
-        (&value).into()
-    }
-}
-impl From<IncompleteTruncatedClosedWithRange> for i8 {
-    fn from(value: IncompleteTruncatedClosedWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedClosedWithRange> for i16 {
-    fn from(value: IncompleteTruncatedClosedWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedClosedWithRange> for i32 {
-    fn from(value: IncompleteTruncatedClosedWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedClosedWithRange> for i64 {
-    fn from(value: IncompleteTruncatedClosedWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedClosedWithRange> for u16 {
-    fn from(value: IncompleteTruncatedClosedWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedClosedWithRange> for u32 {
-    fn from(value: IncompleteTruncatedClosedWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedClosedWithRange> for u64 {
-    fn from(value: IncompleteTruncatedClosedWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
-pub enum IncompleteTruncatedOpenWithRange {
-    A,
-    X,
-    Y,
-    B(Private<u8>),
-    Unknown(Private<u8>),
-}
-impl TryFrom<u8> for IncompleteTruncatedOpenWithRange {
-    type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
-        match value {
-            0x0 => Ok(IncompleteTruncatedOpenWithRange::A),
-            0x1 => Ok(IncompleteTruncatedOpenWithRange::X),
-            0x2 => Ok(IncompleteTruncatedOpenWithRange::Y),
-            0x1..=0x6 => Ok(IncompleteTruncatedOpenWithRange::B(Private(value))),
-            0..=0x7 => Ok(IncompleteTruncatedOpenWithRange::Unknown(Private(value))),
-            _ => Err(value),
-        }
-    }
-}
-impl From<&IncompleteTruncatedOpenWithRange> for u8 {
-    fn from(value: &IncompleteTruncatedOpenWithRange) -> Self {
-        match value {
-            IncompleteTruncatedOpenWithRange::A => 0x0,
-            IncompleteTruncatedOpenWithRange::X => 0x1,
-            IncompleteTruncatedOpenWithRange::Y => 0x2,
-            IncompleteTruncatedOpenWithRange::B(Private(value)) => *value,
-            IncompleteTruncatedOpenWithRange::Unknown(Private(value)) => *value,
-        }
-    }
-}
-impl From<IncompleteTruncatedOpenWithRange> for u8 {
-    fn from(value: IncompleteTruncatedOpenWithRange) -> Self {
-        (&value).into()
-    }
-}
-impl From<IncompleteTruncatedOpenWithRange> for i8 {
-    fn from(value: IncompleteTruncatedOpenWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedOpenWithRange> for i16 {
-    fn from(value: IncompleteTruncatedOpenWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedOpenWithRange> for i32 {
-    fn from(value: IncompleteTruncatedOpenWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedOpenWithRange> for i64 {
-    fn from(value: IncompleteTruncatedOpenWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedOpenWithRange> for u16 {
-    fn from(value: IncompleteTruncatedOpenWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedOpenWithRange> for u32 {
-    fn from(value: IncompleteTruncatedOpenWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<IncompleteTruncatedOpenWithRange> for u64 {
-    fn from(value: IncompleteTruncatedOpenWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-#[repr(u64)]
-#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
-pub enum CompleteTruncated {
-    A = 0x0,
-    B = 0x1,
-    C = 0x2,
-    D = 0x3,
-    E = 0x4,
-    F = 0x5,
-    G = 0x6,
-    H = 0x7,
-}
-impl TryFrom<u8> for CompleteTruncated {
-    type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
-        match value {
-            0x0 => Ok(CompleteTruncated::A),
-            0x1 => Ok(CompleteTruncated::B),
-            0x2 => Ok(CompleteTruncated::C),
-            0x3 => Ok(CompleteTruncated::D),
-            0x4 => Ok(CompleteTruncated::E),
-            0x5 => Ok(CompleteTruncated::F),
-            0x6 => Ok(CompleteTruncated::G),
-            0x7 => Ok(CompleteTruncated::H),
-            _ => Err(value),
-        }
-    }
-}
-impl From<&CompleteTruncated> for u8 {
-    fn from(value: &CompleteTruncated) -> Self {
-        match value {
-            CompleteTruncated::A => 0x0,
-            CompleteTruncated::B => 0x1,
-            CompleteTruncated::C => 0x2,
-            CompleteTruncated::D => 0x3,
-            CompleteTruncated::E => 0x4,
-            CompleteTruncated::F => 0x5,
-            CompleteTruncated::G => 0x6,
-            CompleteTruncated::H => 0x7,
-        }
-    }
-}
-impl From<CompleteTruncated> for u8 {
-    fn from(value: CompleteTruncated) -> Self {
-        (&value).into()
-    }
-}
-impl From<CompleteTruncated> for i8 {
-    fn from(value: CompleteTruncated) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<CompleteTruncated> for i16 {
-    fn from(value: CompleteTruncated) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<CompleteTruncated> for i32 {
-    fn from(value: CompleteTruncated) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<CompleteTruncated> for i64 {
-    fn from(value: CompleteTruncated) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<CompleteTruncated> for u16 {
-    fn from(value: CompleteTruncated) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<CompleteTruncated> for u32 {
-    fn from(value: CompleteTruncated) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<CompleteTruncated> for u64 {
-    fn from(value: CompleteTruncated) -> Self {
-        u8::from(value) as Self
-    }
-}
-#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
-pub enum CompleteTruncatedWithRange {
-    A,
-    X,
-    Y,
-    B(Private<u8>),
-}
-impl TryFrom<u8> for CompleteTruncatedWithRange {
-    type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
-        match value {
-            0x0 => Ok(CompleteTruncatedWithRange::A),
-            0x1 => Ok(CompleteTruncatedWithRange::X),
-            0x2 => Ok(CompleteTruncatedWithRange::Y),
-            0x1..=0x7 => Ok(CompleteTruncatedWithRange::B(Private(value))),
-            _ => Err(value),
-        }
-    }
-}
-impl From<&CompleteTruncatedWithRange> for u8 {
-    fn from(value: &CompleteTruncatedWithRange) -> Self {
-        match value {
-            CompleteTruncatedWithRange::A => 0x0,
-            CompleteTruncatedWithRange::X => 0x1,
-            CompleteTruncatedWithRange::Y => 0x2,
-            CompleteTruncatedWithRange::B(Private(value)) => *value,
-        }
-    }
-}
-impl From<CompleteTruncatedWithRange> for u8 {
-    fn from(value: CompleteTruncatedWithRange) -> Self {
-        (&value).into()
-    }
-}
-impl From<CompleteTruncatedWithRange> for i8 {
-    fn from(value: CompleteTruncatedWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<CompleteTruncatedWithRange> for i16 {
-    fn from(value: CompleteTruncatedWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<CompleteTruncatedWithRange> for i32 {
-    fn from(value: CompleteTruncatedWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<CompleteTruncatedWithRange> for i64 {
-    fn from(value: CompleteTruncatedWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<CompleteTruncatedWithRange> for u16 {
-    fn from(value: CompleteTruncatedWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<CompleteTruncatedWithRange> for u32 {
-    fn from(value: CompleteTruncatedWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<CompleteTruncatedWithRange> for u64 {
-    fn from(value: CompleteTruncatedWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
-pub enum CompleteWithRange {
-    A,
-    B,
-    C(Private<u8>),
-}
-impl TryFrom<u8> for CompleteWithRange {
-    type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
-        match value {
-            0x0 => Ok(CompleteWithRange::A),
-            0x1 => Ok(CompleteWithRange::B),
-            0x2..=0xff => Ok(CompleteWithRange::C(Private(value))),
-        }
-    }
-}
-impl From<&CompleteWithRange> for u8 {
-    fn from(value: &CompleteWithRange) -> Self {
-        match value {
-            CompleteWithRange::A => 0x0,
-            CompleteWithRange::B => 0x1,
-            CompleteWithRange::C(Private(value)) => *value,
-        }
-    }
-}
-impl From<CompleteWithRange> for u8 {
-    fn from(value: CompleteWithRange) -> Self {
-        (&value).into()
-    }
-}
-impl From<CompleteWithRange> for i16 {
-    fn from(value: CompleteWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<CompleteWithRange> for i32 {
-    fn from(value: CompleteWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<CompleteWithRange> for i64 {
-    fn from(value: CompleteWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<CompleteWithRange> for u16 {
-    fn from(value: CompleteWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<CompleteWithRange> for u32 {
-    fn from(value: CompleteWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<CompleteWithRange> for u64 {
-    fn from(value: CompleteWithRange) -> Self {
-        u8::from(value) as Self
-    }
-}
diff --git a/tests/generated/packet_decl_24bit_scalar_array_big_endian.rs b/tests/generated/packet_decl_24bit_scalar_array_big_endian.rs
deleted file mode 100644
index a0a810a..0000000
--- a/tests/generated/packet_decl_24bit_scalar_array_big_endian.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-#![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 struct FooData {
-    x: [u32; 5],
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {
-    pub x: [u32; 5],
-}
-impl FooData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 15
-    }
-    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() < 5 * 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 5 * 3,
-                got: bytes.get().remaining(),
-            });
-        }
-        let x = (0..5)
-            .map(|_| Ok::<_, Error>(bytes.get_mut().get_uint(3) as u32))
-            .collect::<Result<Vec<_>>>()?
-            .try_into()
-            .map_err(|_| Error::InvalidPacketError)?;
-        Ok(Self { x })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        for elem in &self.x {
-            buffer.put_uint(*elem as u64, 3);
-        }
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        15
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    pub fn get_x(&self) -> &[u32; 5] {
-        &self.foo.x
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData { x: self.x };
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_24bit_scalar_array_little_endian.rs b/tests/generated/packet_decl_24bit_scalar_array_little_endian.rs
deleted file mode 100644
index adbdff4..0000000
--- a/tests/generated/packet_decl_24bit_scalar_array_little_endian.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-#![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 struct FooData {
-    x: [u32; 5],
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {
-    pub x: [u32; 5],
-}
-impl FooData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 15
-    }
-    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() < 5 * 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 5 * 3,
-                got: bytes.get().remaining(),
-            });
-        }
-        let x = (0..5)
-            .map(|_| Ok::<_, Error>(bytes.get_mut().get_uint_le(3) as u32))
-            .collect::<Result<Vec<_>>>()?
-            .try_into()
-            .map_err(|_| Error::InvalidPacketError)?;
-        Ok(Self { x })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        for elem in &self.x {
-            buffer.put_uint_le(*elem as u64, 3);
-        }
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        15
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    pub fn get_x(&self) -> &[u32; 5] {
-        &self.foo.x
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData { x: self.x };
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_24bit_scalar_big_endian.rs b/tests/generated/packet_decl_24bit_scalar_big_endian.rs
deleted file mode 100644
index 2bbdde0..0000000
--- a/tests/generated/packet_decl_24bit_scalar_big_endian.rs
+++ /dev/null
@@ -1,123 +0,0 @@
-#![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 struct FooData {
-    x: u32,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {
-    pub x: u32,
-}
-impl FooData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 3
-    }
-    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() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 3,
-                got: bytes.get().remaining(),
-            });
-        }
-        let x = bytes.get_mut().get_uint(3) as u32;
-        Ok(Self { x })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        if self.x > 0xff_ffff {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "x", self.x, 0xff_ffff);
-        }
-        buffer.put_uint(self.x as u64, 3);
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        3
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    pub fn get_x(&self) -> u32 {
-        self.foo.x
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData { x: self.x };
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_24bit_scalar_little_endian.rs b/tests/generated/packet_decl_24bit_scalar_little_endian.rs
deleted file mode 100644
index fce2122..0000000
--- a/tests/generated/packet_decl_24bit_scalar_little_endian.rs
+++ /dev/null
@@ -1,123 +0,0 @@
-#![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 struct FooData {
-    x: u32,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {
-    pub x: u32,
-}
-impl FooData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 3
-    }
-    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() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 3,
-                got: bytes.get().remaining(),
-            });
-        }
-        let x = bytes.get_mut().get_uint_le(3) as u32;
-        Ok(Self { x })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        if self.x > 0xff_ffff {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "x", self.x, 0xff_ffff);
-        }
-        buffer.put_uint_le(self.x as u64, 3);
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        3
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    pub fn get_x(&self) -> u32 {
-        self.foo.x
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData { x: self.x };
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_64bit_scalar_array_big_endian.rs b/tests/generated/packet_decl_64bit_scalar_array_big_endian.rs
deleted file mode 100644
index 261e4dd..0000000
--- a/tests/generated/packet_decl_64bit_scalar_array_big_endian.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-#![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 struct FooData {
-    x: [u64; 7],
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {
-    pub x: [u64; 7],
-}
-impl FooData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 56
-    }
-    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() < 7 * 8 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 7 * 8,
-                got: bytes.get().remaining(),
-            });
-        }
-        let x = (0..7)
-            .map(|_| Ok::<_, Error>(bytes.get_mut().get_u64()))
-            .collect::<Result<Vec<_>>>()?
-            .try_into()
-            .map_err(|_| Error::InvalidPacketError)?;
-        Ok(Self { x })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        for elem in &self.x {
-            buffer.put_u64(*elem);
-        }
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        56
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    pub fn get_x(&self) -> &[u64; 7] {
-        &self.foo.x
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData { x: self.x };
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_64bit_scalar_array_little_endian.rs b/tests/generated/packet_decl_64bit_scalar_array_little_endian.rs
deleted file mode 100644
index f60c64c..0000000
--- a/tests/generated/packet_decl_64bit_scalar_array_little_endian.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-#![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 struct FooData {
-    x: [u64; 7],
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {
-    pub x: [u64; 7],
-}
-impl FooData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 56
-    }
-    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() < 7 * 8 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 7 * 8,
-                got: bytes.get().remaining(),
-            });
-        }
-        let x = (0..7)
-            .map(|_| Ok::<_, Error>(bytes.get_mut().get_u64_le()))
-            .collect::<Result<Vec<_>>>()?
-            .try_into()
-            .map_err(|_| Error::InvalidPacketError)?;
-        Ok(Self { x })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        for elem in &self.x {
-            buffer.put_u64_le(*elem);
-        }
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        56
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    pub fn get_x(&self) -> &[u64; 7] {
-        &self.foo.x
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData { x: self.x };
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_8bit_enum_little_endian.rs b/tests/generated/packet_decl_8bit_enum_little_endian.rs
deleted file mode 100644
index 03bec5d..0000000
--- a/tests/generated/packet_decl_8bit_enum_little_endian.rs
+++ /dev/null
@@ -1,187 +0,0 @@
-#![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
-    }
-}
-#[repr(u64)]
-#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
-pub enum Foo {
-    A = 0x1,
-    B = 0x2,
-}
-impl TryFrom<u8> for Foo {
-    type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
-        match value {
-            0x1 => Ok(Foo::A),
-            0x2 => Ok(Foo::B),
-            _ => Err(value),
-        }
-    }
-}
-impl From<&Foo> for u8 {
-    fn from(value: &Foo) -> Self {
-        match value {
-            Foo::A => 0x1,
-            Foo::B => 0x2,
-        }
-    }
-}
-impl From<Foo> for u8 {
-    fn from(value: Foo) -> Self {
-        (&value).into()
-    }
-}
-impl From<Foo> for i16 {
-    fn from(value: Foo) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<Foo> for i32 {
-    fn from(value: Foo) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<Foo> for i64 {
-    fn from(value: Foo) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<Foo> for u16 {
-    fn from(value: Foo) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<Foo> for u32 {
-    fn from(value: Foo) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<Foo> for u64 {
-    fn from(value: Foo) -> Self {
-        u8::from(value) as Self
-    }
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct BarData {
-    x: Foo,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Bar {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    bar: BarData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct BarBuilder {
-    pub x: Foo,
-}
-impl BarData {
-    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: "Bar".to_string(),
-                wanted: 1,
-                got: bytes.get().remaining(),
-            });
-        }
-        let x = Foo::try_from(bytes.get_mut().get_u8())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Bar".to_string(),
-                field: "x".to_string(),
-                value: unknown_val as u64,
-                type_: "Foo".to_string(),
-            })?;
-        Ok(Self { x })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        buffer.put_u8(u8::from(self.x));
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        1
-    }
-}
-impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.bar.get_size());
-        self.bar.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
-    }
-}
-impl Bar {
-    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 = BarData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(bar: BarData) -> Result<Self> {
-        Ok(Self { bar })
-    }
-    pub fn get_x(&self) -> Foo {
-        self.bar.x
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.bar.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.bar.get_size()
-    }
-}
-impl BarBuilder {
-    pub fn build(self) -> Bar {
-        let bar = BarData { x: self.x };
-        Bar::new(bar).unwrap()
-    }
-}
-impl From<BarBuilder> for Bar {
-    fn from(builder: BarBuilder) -> Bar {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_8bit_scalar_array_big_endian.rs b/tests/generated/packet_decl_8bit_scalar_array_big_endian.rs
deleted file mode 100644
index 74099b0..0000000
--- a/tests/generated/packet_decl_8bit_scalar_array_big_endian.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-#![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 struct FooData {
-    x: [u8; 3],
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {
-    pub x: [u8; 3],
-}
-impl FooData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 3
-    }
-    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() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 3,
-                got: bytes.get().remaining(),
-            });
-        }
-        let x = (0..3)
-            .map(|_| Ok::<_, Error>(bytes.get_mut().get_u8()))
-            .collect::<Result<Vec<_>>>()?
-            .try_into()
-            .map_err(|_| Error::InvalidPacketError)?;
-        Ok(Self { x })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        for elem in &self.x {
-            buffer.put_u8(*elem);
-        }
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        3
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    pub fn get_x(&self) -> &[u8; 3] {
-        &self.foo.x
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData { x: self.x };
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_8bit_scalar_array_little_endian.rs b/tests/generated/packet_decl_8bit_scalar_array_little_endian.rs
deleted file mode 100644
index 74099b0..0000000
--- a/tests/generated/packet_decl_8bit_scalar_array_little_endian.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-#![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 struct FooData {
-    x: [u8; 3],
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {
-    pub x: [u8; 3],
-}
-impl FooData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 3
-    }
-    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() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 3,
-                got: bytes.get().remaining(),
-            });
-        }
-        let x = (0..3)
-            .map(|_| Ok::<_, Error>(bytes.get_mut().get_u8()))
-            .collect::<Result<Vec<_>>>()?
-            .try_into()
-            .map_err(|_| Error::InvalidPacketError)?;
-        Ok(Self { x })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        for elem in &self.x {
-            buffer.put_u8(*elem);
-        }
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        3
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    pub fn get_x(&self) -> &[u8; 3] {
-        &self.foo.x
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData { x: self.x };
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_8bit_scalar_little_endian.rs b/tests/generated/packet_decl_8bit_scalar_little_endian.rs
deleted file mode 100644
index de13f31..0000000
--- a/tests/generated/packet_decl_8bit_scalar_little_endian.rs
+++ /dev/null
@@ -1,120 +0,0 @@
-#![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 struct FooData {
-    x: u8,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {
-    pub x: u8,
-}
-impl FooData {
-    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: "Foo".to_string(),
-                wanted: 1,
-                got: bytes.get().remaining(),
-            });
-        }
-        let x = bytes.get_mut().get_u8();
-        Ok(Self { x })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        buffer.put_u8(self.x);
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        1
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    pub fn get_x(&self) -> u8 {
-        self.foo.x
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData { x: self.x };
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_array_dynamic_count_big_endian.rs b/tests/generated/packet_decl_array_dynamic_count_big_endian.rs
deleted file mode 100644
index 074443c..0000000
--- a/tests/generated/packet_decl_array_dynamic_count_big_endian.rs
+++ /dev/null
@@ -1,152 +0,0 @@
-#![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 struct FooData {
-    padding: u8,
-    x: Vec<u32>,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {
-    pub padding: u8,
-    pub x: Vec<u32>,
-}
-impl FooData {
-    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: "Foo".to_string(),
-                wanted: 1,
-                got: bytes.get().remaining(),
-            });
-        }
-        let chunk = bytes.get_mut().get_u8();
-        let x_count = (chunk & 0x1f) as usize;
-        let padding = ((chunk >> 5) & 0x7);
-        if bytes.get().remaining() < x_count * 3usize {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: x_count * 3usize,
-                got: bytes.get().remaining(),
-            });
-        }
-        let x = (0..x_count)
-            .map(|_| Ok::<_, Error>(bytes.get_mut().get_uint(3) as u32))
-            .collect::<Result<Vec<_>>>()?;
-        Ok(Self { padding, x })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        if self.x.len() > 0x1f {
-            panic!("Invalid length for {}::{}: {} > {}", "Foo", "x", self.x.len(), 0x1f);
-        }
-        if self.padding > 0x7 {
-            panic!(
-                "Invalid value for {}::{}: {} > {}", "Foo", "padding", self.padding, 0x7
-            );
-        }
-        let value = self.x.len() as u8 | (self.padding << 5);
-        buffer.put_u8(value);
-        for elem in &self.x {
-            buffer.put_uint(*elem as u64, 3);
-        }
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        1 + self.x.len() * 3
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    pub fn get_padding(&self) -> u8 {
-        self.foo.padding
-    }
-    pub fn get_x(&self) -> &Vec<u32> {
-        &self.foo.x
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData {
-            padding: self.padding,
-            x: self.x,
-        };
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_array_dynamic_count_little_endian.rs b/tests/generated/packet_decl_array_dynamic_count_little_endian.rs
deleted file mode 100644
index e6429b4..0000000
--- a/tests/generated/packet_decl_array_dynamic_count_little_endian.rs
+++ /dev/null
@@ -1,152 +0,0 @@
-#![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 struct FooData {
-    padding: u8,
-    x: Vec<u32>,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {
-    pub padding: u8,
-    pub x: Vec<u32>,
-}
-impl FooData {
-    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: "Foo".to_string(),
-                wanted: 1,
-                got: bytes.get().remaining(),
-            });
-        }
-        let chunk = bytes.get_mut().get_u8();
-        let x_count = (chunk & 0x1f) as usize;
-        let padding = ((chunk >> 5) & 0x7);
-        if bytes.get().remaining() < x_count * 3usize {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: x_count * 3usize,
-                got: bytes.get().remaining(),
-            });
-        }
-        let x = (0..x_count)
-            .map(|_| Ok::<_, Error>(bytes.get_mut().get_uint_le(3) as u32))
-            .collect::<Result<Vec<_>>>()?;
-        Ok(Self { padding, x })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        if self.x.len() > 0x1f {
-            panic!("Invalid length for {}::{}: {} > {}", "Foo", "x", self.x.len(), 0x1f);
-        }
-        if self.padding > 0x7 {
-            panic!(
-                "Invalid value for {}::{}: {} > {}", "Foo", "padding", self.padding, 0x7
-            );
-        }
-        let value = self.x.len() as u8 | (self.padding << 5);
-        buffer.put_u8(value);
-        for elem in &self.x {
-            buffer.put_uint_le(*elem as u64, 3);
-        }
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        1 + self.x.len() * 3
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    pub fn get_padding(&self) -> u8 {
-        self.foo.padding
-    }
-    pub fn get_x(&self) -> &Vec<u32> {
-        &self.foo.x
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData {
-            padding: self.padding,
-            x: self.x,
-        };
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_array_unknown_element_width_dynamic_count_big_endian.rs b/tests/generated/packet_decl_array_unknown_element_width_dynamic_count_big_endian.rs
deleted file mode 100644
index d542792..0000000
--- a/tests/generated/packet_decl_array_unknown_element_width_dynamic_count_big_endian.rs
+++ /dev/null
@@ -1,186 +0,0 @@
-#![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 struct Foo {
-    pub a: Vec<u16>,
-}
-impl Foo {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 5
-    }
-    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> {
-        if bytes.get().remaining() < 5 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 5,
-                got: bytes.get().remaining(),
-            });
-        }
-        let a_count = bytes.get_mut().get_uint(5) as usize;
-        if bytes.get().remaining() < a_count * 2usize {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: a_count * 2usize,
-                got: bytes.get().remaining(),
-            });
-        }
-        let a = (0..a_count)
-            .map(|_| Ok::<_, Error>(bytes.get_mut().get_u16()))
-            .collect::<Result<Vec<_>>>()?;
-        Ok(Self { a })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        if self.a.len() > 0xff_ffff_ffff_usize {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Foo", "a", self.a.len(),
-                0xff_ffff_ffff_usize
-            );
-        }
-        buffer.put_uint(self.a.len() as u64, 5);
-        for elem in &self.a {
-            buffer.put_u16(*elem);
-        }
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        5 + self.a.len() * 2
-    }
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct BarData {
-    x: Vec<Foo>,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Bar {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    bar: BarData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct BarBuilder {
-    pub x: Vec<Foo>,
-}
-impl BarData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 5
-    }
-    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() < 5 {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
-                wanted: 5,
-                got: bytes.get().remaining(),
-            });
-        }
-        let x_count = bytes.get_mut().get_uint(5) as usize;
-        let x = (0..x_count)
-            .map(|_| Foo::parse_inner(bytes))
-            .collect::<Result<Vec<_>>>()?;
-        Ok(Self { x })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        if self.x.len() > 0xff_ffff_ffff_usize {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Bar", "x", self.x.len(),
-                0xff_ffff_ffff_usize
-            );
-        }
-        buffer.put_uint(self.x.len() as u64, 5);
-        for elem in &self.x {
-            elem.write_to(buffer);
-        }
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        5 + self.x.iter().map(|elem| elem.get_size()).sum::<usize>()
-    }
-}
-impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.bar.get_size());
-        self.bar.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
-    }
-}
-impl Bar {
-    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 = BarData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(bar: BarData) -> Result<Self> {
-        Ok(Self { bar })
-    }
-    pub fn get_x(&self) -> &Vec<Foo> {
-        &self.bar.x
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.bar.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.bar.get_size()
-    }
-}
-impl BarBuilder {
-    pub fn build(self) -> Bar {
-        let bar = BarData { x: self.x };
-        Bar::new(bar).unwrap()
-    }
-}
-impl From<BarBuilder> for Bar {
-    fn from(builder: BarBuilder) -> Bar {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_array_unknown_element_width_dynamic_count_little_endian.rs b/tests/generated/packet_decl_array_unknown_element_width_dynamic_count_little_endian.rs
deleted file mode 100644
index 767671f..0000000
--- a/tests/generated/packet_decl_array_unknown_element_width_dynamic_count_little_endian.rs
+++ /dev/null
@@ -1,186 +0,0 @@
-#![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 struct Foo {
-    pub a: Vec<u16>,
-}
-impl Foo {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 5
-    }
-    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> {
-        if bytes.get().remaining() < 5 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 5,
-                got: bytes.get().remaining(),
-            });
-        }
-        let a_count = bytes.get_mut().get_uint_le(5) as usize;
-        if bytes.get().remaining() < a_count * 2usize {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: a_count * 2usize,
-                got: bytes.get().remaining(),
-            });
-        }
-        let a = (0..a_count)
-            .map(|_| Ok::<_, Error>(bytes.get_mut().get_u16_le()))
-            .collect::<Result<Vec<_>>>()?;
-        Ok(Self { a })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        if self.a.len() > 0xff_ffff_ffff_usize {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Foo", "a", self.a.len(),
-                0xff_ffff_ffff_usize
-            );
-        }
-        buffer.put_uint_le(self.a.len() as u64, 5);
-        for elem in &self.a {
-            buffer.put_u16_le(*elem);
-        }
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        5 + self.a.len() * 2
-    }
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct BarData {
-    x: Vec<Foo>,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Bar {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    bar: BarData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct BarBuilder {
-    pub x: Vec<Foo>,
-}
-impl BarData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 5
-    }
-    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() < 5 {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
-                wanted: 5,
-                got: bytes.get().remaining(),
-            });
-        }
-        let x_count = bytes.get_mut().get_uint_le(5) as usize;
-        let x = (0..x_count)
-            .map(|_| Foo::parse_inner(bytes))
-            .collect::<Result<Vec<_>>>()?;
-        Ok(Self { x })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        if self.x.len() > 0xff_ffff_ffff_usize {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Bar", "x", self.x.len(),
-                0xff_ffff_ffff_usize
-            );
-        }
-        buffer.put_uint_le(self.x.len() as u64, 5);
-        for elem in &self.x {
-            elem.write_to(buffer);
-        }
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        5 + self.x.iter().map(|elem| elem.get_size()).sum::<usize>()
-    }
-}
-impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.bar.get_size());
-        self.bar.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
-    }
-}
-impl Bar {
-    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 = BarData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(bar: BarData) -> Result<Self> {
-        Ok(Self { bar })
-    }
-    pub fn get_x(&self) -> &Vec<Foo> {
-        &self.bar.x
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.bar.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.bar.get_size()
-    }
-}
-impl BarBuilder {
-    pub fn build(self) -> Bar {
-        let bar = BarData { x: self.x };
-        Bar::new(bar).unwrap()
-    }
-}
-impl From<BarBuilder> for Bar {
-    fn from(builder: BarBuilder) -> Bar {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_array_with_padding_big_endian.rs b/tests/generated/packet_decl_array_with_padding_big_endian.rs
deleted file mode 100644
index 0231b64..0000000
--- a/tests/generated/packet_decl_array_with_padding_big_endian.rs
+++ /dev/null
@@ -1,190 +0,0 @@
-#![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 struct Foo {
-    pub a: Vec<u16>,
-}
-impl Foo {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 5
-    }
-    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> {
-        if bytes.get().remaining() < 5 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 5,
-                got: bytes.get().remaining(),
-            });
-        }
-        let a_count = bytes.get_mut().get_uint(5) as usize;
-        if bytes.get().remaining() < a_count * 2usize {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: a_count * 2usize,
-                got: bytes.get().remaining(),
-            });
-        }
-        let a = (0..a_count)
-            .map(|_| Ok::<_, Error>(bytes.get_mut().get_u16()))
-            .collect::<Result<Vec<_>>>()?;
-        Ok(Self { a })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        if self.a.len() > 0xff_ffff_ffff_usize {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Foo", "a", self.a.len(),
-                0xff_ffff_ffff_usize
-            );
-        }
-        buffer.put_uint(self.a.len() as u64, 5);
-        for elem in &self.a {
-            buffer.put_u16(*elem);
-        }
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        5 + self.a.len() * 2
-    }
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct BarData {
-    a: Vec<Foo>,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Bar {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    bar: BarData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct BarBuilder {
-    pub a: Vec<Foo>,
-}
-impl BarData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 128
-    }
-    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() < 128usize {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
-                wanted: 128usize,
-                got: bytes.get().remaining(),
-            });
-        }
-        let (head, tail) = bytes.get().split_at(128usize);
-        let mut head = &mut Cell::new(head);
-        bytes.replace(tail);
-        let mut a = Vec::new();
-        while !head.get().is_empty() {
-            a.push(Foo::parse_inner(head)?);
-        }
-        Ok(Self { a })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        let current_size = buffer.len();
-        for elem in &self.a {
-            elem.write_to(buffer);
-        }
-        let array_size = buffer.len() - current_size;
-        if array_size > 128usize {
-            panic!(
-                "attempted to serialize an array larger than the enclosing padding size"
-            );
-        }
-        buffer.put_bytes(0, 128usize - array_size);
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        128
-    }
-}
-impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.bar.get_size());
-        self.bar.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
-    }
-}
-impl Bar {
-    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 = BarData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(bar: BarData) -> Result<Self> {
-        Ok(Self { bar })
-    }
-    pub fn get_a(&self) -> &Vec<Foo> {
-        &self.bar.a
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.bar.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.bar.get_size()
-    }
-}
-impl BarBuilder {
-    pub fn build(self) -> Bar {
-        let bar = BarData { a: self.a };
-        Bar::new(bar).unwrap()
-    }
-}
-impl From<BarBuilder> for Bar {
-    fn from(builder: BarBuilder) -> Bar {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_array_with_padding_little_endian.rs b/tests/generated/packet_decl_array_with_padding_little_endian.rs
deleted file mode 100644
index 6aee602..0000000
--- a/tests/generated/packet_decl_array_with_padding_little_endian.rs
+++ /dev/null
@@ -1,190 +0,0 @@
-#![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 struct Foo {
-    pub a: Vec<u16>,
-}
-impl Foo {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 5
-    }
-    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> {
-        if bytes.get().remaining() < 5 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 5,
-                got: bytes.get().remaining(),
-            });
-        }
-        let a_count = bytes.get_mut().get_uint_le(5) as usize;
-        if bytes.get().remaining() < a_count * 2usize {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: a_count * 2usize,
-                got: bytes.get().remaining(),
-            });
-        }
-        let a = (0..a_count)
-            .map(|_| Ok::<_, Error>(bytes.get_mut().get_u16_le()))
-            .collect::<Result<Vec<_>>>()?;
-        Ok(Self { a })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        if self.a.len() > 0xff_ffff_ffff_usize {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Foo", "a", self.a.len(),
-                0xff_ffff_ffff_usize
-            );
-        }
-        buffer.put_uint_le(self.a.len() as u64, 5);
-        for elem in &self.a {
-            buffer.put_u16_le(*elem);
-        }
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        5 + self.a.len() * 2
-    }
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct BarData {
-    a: Vec<Foo>,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Bar {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    bar: BarData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct BarBuilder {
-    pub a: Vec<Foo>,
-}
-impl BarData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 128
-    }
-    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() < 128usize {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
-                wanted: 128usize,
-                got: bytes.get().remaining(),
-            });
-        }
-        let (head, tail) = bytes.get().split_at(128usize);
-        let mut head = &mut Cell::new(head);
-        bytes.replace(tail);
-        let mut a = Vec::new();
-        while !head.get().is_empty() {
-            a.push(Foo::parse_inner(head)?);
-        }
-        Ok(Self { a })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        let current_size = buffer.len();
-        for elem in &self.a {
-            elem.write_to(buffer);
-        }
-        let array_size = buffer.len() - current_size;
-        if array_size > 128usize {
-            panic!(
-                "attempted to serialize an array larger than the enclosing padding size"
-            );
-        }
-        buffer.put_bytes(0, 128usize - array_size);
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        128
-    }
-}
-impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.bar.get_size());
-        self.bar.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
-    }
-}
-impl Bar {
-    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 = BarData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(bar: BarData) -> Result<Self> {
-        Ok(Self { bar })
-    }
-    pub fn get_a(&self) -> &Vec<Foo> {
-        &self.bar.a
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.bar.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.bar.get_size()
-    }
-}
-impl BarBuilder {
-    pub fn build(self) -> Bar {
-        let bar = BarData { a: self.a };
-        Bar::new(bar).unwrap()
-    }
-}
-impl From<BarBuilder> for Bar {
-    fn from(builder: BarBuilder) -> Bar {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_complex_scalars_big_endian.rs b/tests/generated/packet_decl_complex_scalars_big_endian.rs
deleted file mode 100644
index 4c3de07..0000000
--- a/tests/generated/packet_decl_complex_scalars_big_endian.rs
+++ /dev/null
@@ -1,192 +0,0 @@
-#![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 struct FooData {
-    a: u8,
-    b: u8,
-    c: u8,
-    d: u32,
-    e: u16,
-    f: u8,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {
-    pub a: u8,
-    pub b: u8,
-    pub c: u8,
-    pub d: u32,
-    pub e: u16,
-    pub f: u8,
-}
-impl FooData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 7
-    }
-    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() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 2,
-                got: bytes.get().remaining(),
-            });
-        }
-        let chunk = bytes.get_mut().get_u16();
-        let a = (chunk & 0x7) as u8;
-        let b = (chunk >> 3) as u8;
-        let c = ((chunk >> 11) & 0x1f) as u8;
-        if bytes.get().remaining() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 3,
-                got: bytes.get().remaining(),
-            });
-        }
-        let d = bytes.get_mut().get_uint(3) as u32;
-        if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 2,
-                got: bytes.get().remaining(),
-            });
-        }
-        let chunk = bytes.get_mut().get_u16();
-        let e = (chunk & 0xfff);
-        let f = ((chunk >> 12) & 0xf) as u8;
-        Ok(Self { a, b, c, d, e, f })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        if self.a > 0x7 {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0x7);
-        }
-        if self.c > 0x1f {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "c", self.c, 0x1f);
-        }
-        let value = (self.a as u16) | ((self.b as u16) << 3) | ((self.c as u16) << 11);
-        buffer.put_u16(value);
-        if self.d > 0xff_ffff {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "d", self.d, 0xff_ffff);
-        }
-        buffer.put_uint(self.d as u64, 3);
-        if self.e > 0xfff {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "e", self.e, 0xfff);
-        }
-        if self.f > 0xf {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "f", self.f, 0xf);
-        }
-        let value = self.e | ((self.f as u16) << 12);
-        buffer.put_u16(value);
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        7
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    pub fn get_a(&self) -> u8 {
-        self.foo.a
-    }
-    pub fn get_b(&self) -> u8 {
-        self.foo.b
-    }
-    pub fn get_c(&self) -> u8 {
-        self.foo.c
-    }
-    pub fn get_d(&self) -> u32 {
-        self.foo.d
-    }
-    pub fn get_e(&self) -> u16 {
-        self.foo.e
-    }
-    pub fn get_f(&self) -> u8 {
-        self.foo.f
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData {
-            a: self.a,
-            b: self.b,
-            c: self.c,
-            d: self.d,
-            e: self.e,
-            f: self.f,
-        };
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_complex_scalars_little_endian.rs b/tests/generated/packet_decl_complex_scalars_little_endian.rs
deleted file mode 100644
index 4bd1a80..0000000
--- a/tests/generated/packet_decl_complex_scalars_little_endian.rs
+++ /dev/null
@@ -1,192 +0,0 @@
-#![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 struct FooData {
-    a: u8,
-    b: u8,
-    c: u8,
-    d: u32,
-    e: u16,
-    f: u8,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {
-    pub a: u8,
-    pub b: u8,
-    pub c: u8,
-    pub d: u32,
-    pub e: u16,
-    pub f: u8,
-}
-impl FooData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 7
-    }
-    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() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 2,
-                got: bytes.get().remaining(),
-            });
-        }
-        let chunk = bytes.get_mut().get_u16_le();
-        let a = (chunk & 0x7) as u8;
-        let b = (chunk >> 3) as u8;
-        let c = ((chunk >> 11) & 0x1f) as u8;
-        if bytes.get().remaining() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 3,
-                got: bytes.get().remaining(),
-            });
-        }
-        let d = bytes.get_mut().get_uint_le(3) as u32;
-        if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 2,
-                got: bytes.get().remaining(),
-            });
-        }
-        let chunk = bytes.get_mut().get_u16_le();
-        let e = (chunk & 0xfff);
-        let f = ((chunk >> 12) & 0xf) as u8;
-        Ok(Self { a, b, c, d, e, f })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        if self.a > 0x7 {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0x7);
-        }
-        if self.c > 0x1f {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "c", self.c, 0x1f);
-        }
-        let value = (self.a as u16) | ((self.b as u16) << 3) | ((self.c as u16) << 11);
-        buffer.put_u16_le(value);
-        if self.d > 0xff_ffff {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "d", self.d, 0xff_ffff);
-        }
-        buffer.put_uint_le(self.d as u64, 3);
-        if self.e > 0xfff {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "e", self.e, 0xfff);
-        }
-        if self.f > 0xf {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "f", self.f, 0xf);
-        }
-        let value = self.e | ((self.f as u16) << 12);
-        buffer.put_u16_le(value);
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        7
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    pub fn get_a(&self) -> u8 {
-        self.foo.a
-    }
-    pub fn get_b(&self) -> u8 {
-        self.foo.b
-    }
-    pub fn get_c(&self) -> u8 {
-        self.foo.c
-    }
-    pub fn get_d(&self) -> u32 {
-        self.foo.d
-    }
-    pub fn get_e(&self) -> u16 {
-        self.foo.e
-    }
-    pub fn get_f(&self) -> u8 {
-        self.foo.f
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData {
-            a: self.a,
-            b: self.b,
-            c: self.c,
-            d: self.d,
-            e: self.e,
-            f: self.f,
-        };
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_empty_big_endian.rs b/tests/generated/packet_decl_empty_big_endian.rs
deleted file mode 100644
index 49f14b8..0000000
--- a/tests/generated/packet_decl_empty_big_endian.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-#![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 struct FooData {}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {}
-impl FooData {
-    fn conforms(bytes: &[u8]) -> bool {
-        true
-    }
-    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> {
-        Ok(Self {})
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {}
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        0
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData {};
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_empty_little_endian.rs b/tests/generated/packet_decl_empty_little_endian.rs
deleted file mode 100644
index 49f14b8..0000000
--- a/tests/generated/packet_decl_empty_little_endian.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-#![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 struct FooData {}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {}
-impl FooData {
-    fn conforms(bytes: &[u8]) -> bool {
-        true
-    }
-    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> {
-        Ok(Self {})
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {}
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        0
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData {};
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_fixed_scalar_field_big_endian.rs b/tests/generated/packet_decl_fixed_scalar_field_big_endian.rs
deleted file mode 100644
index 2c5ad70..0000000
--- a/tests/generated/packet_decl_fixed_scalar_field_big_endian.rs
+++ /dev/null
@@ -1,135 +0,0 @@
-#![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 struct FooData {
-    b: u64,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {
-    pub b: u64,
-}
-impl FooData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 8
-    }
-    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() < 8 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 8,
-                got: bytes.get().remaining(),
-            });
-        }
-        let chunk = bytes.get_mut().get_u64();
-        let fixed_value = (chunk & 0x7f) as u8;
-        if fixed_value != 7 {
-            return Err(Error::InvalidFixedValue {
-                expected: 7,
-                actual: fixed_value as u64,
-            });
-        }
-        let b = ((chunk >> 7) & 0x1ff_ffff_ffff_ffff_u64);
-        Ok(Self { b })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        if self.b > 0x1ff_ffff_ffff_ffff_u64 {
-            panic!(
-                "Invalid value for {}::{}: {} > {}", "Foo", "b", self.b,
-                0x1ff_ffff_ffff_ffff_u64
-            );
-        }
-        let value = (7 as u64) | (self.b << 7);
-        buffer.put_u64(value);
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        8
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    pub fn get_b(&self) -> u64 {
-        self.foo.b
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData { b: self.b };
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_fixed_scalar_field_little_endian.rs b/tests/generated/packet_decl_fixed_scalar_field_little_endian.rs
deleted file mode 100644
index b37bce0..0000000
--- a/tests/generated/packet_decl_fixed_scalar_field_little_endian.rs
+++ /dev/null
@@ -1,135 +0,0 @@
-#![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 struct FooData {
-    b: u64,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {
-    pub b: u64,
-}
-impl FooData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 8
-    }
-    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() < 8 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 8,
-                got: bytes.get().remaining(),
-            });
-        }
-        let chunk = bytes.get_mut().get_u64_le();
-        let fixed_value = (chunk & 0x7f) as u8;
-        if fixed_value != 7 {
-            return Err(Error::InvalidFixedValue {
-                expected: 7,
-                actual: fixed_value as u64,
-            });
-        }
-        let b = ((chunk >> 7) & 0x1ff_ffff_ffff_ffff_u64);
-        Ok(Self { b })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        if self.b > 0x1ff_ffff_ffff_ffff_u64 {
-            panic!(
-                "Invalid value for {}::{}: {} > {}", "Foo", "b", self.b,
-                0x1ff_ffff_ffff_ffff_u64
-            );
-        }
-        let value = (7 as u64) | (self.b << 7);
-        buffer.put_u64_le(value);
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        8
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    pub fn get_b(&self) -> u64 {
-        self.foo.b
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData { b: self.b };
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_mask_scalar_value_big_endian.rs b/tests/generated/packet_decl_mask_scalar_value_big_endian.rs
deleted file mode 100644
index dddbc0b..0000000
--- a/tests/generated/packet_decl_mask_scalar_value_big_endian.rs
+++ /dev/null
@@ -1,147 +0,0 @@
-#![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 struct FooData {
-    a: u8,
-    b: u32,
-    c: u8,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {
-    pub a: u8,
-    pub b: u32,
-    pub c: u8,
-}
-impl FooData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 4
-    }
-    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() < 4 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 4,
-                got: bytes.get().remaining(),
-            });
-        }
-        let chunk = bytes.get_mut().get_u32();
-        let a = (chunk & 0x3) as u8;
-        let b = ((chunk >> 2) & 0xff_ffff);
-        let c = ((chunk >> 26) & 0x3f) as u8;
-        Ok(Self { a, b, c })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        if self.a > 0x3 {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0x3);
-        }
-        if self.b > 0xff_ffff {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "b", self.b, 0xff_ffff);
-        }
-        if self.c > 0x3f {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "c", self.c, 0x3f);
-        }
-        let value = (self.a as u32) | (self.b << 2) | ((self.c as u32) << 26);
-        buffer.put_u32(value);
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        4
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    pub fn get_a(&self) -> u8 {
-        self.foo.a
-    }
-    pub fn get_b(&self) -> u32 {
-        self.foo.b
-    }
-    pub fn get_c(&self) -> u8 {
-        self.foo.c
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData {
-            a: self.a,
-            b: self.b,
-            c: self.c,
-        };
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_mask_scalar_value_little_endian.rs b/tests/generated/packet_decl_mask_scalar_value_little_endian.rs
deleted file mode 100644
index 57bcb51..0000000
--- a/tests/generated/packet_decl_mask_scalar_value_little_endian.rs
+++ /dev/null
@@ -1,147 +0,0 @@
-#![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 struct FooData {
-    a: u8,
-    b: u32,
-    c: u8,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {
-    pub a: u8,
-    pub b: u32,
-    pub c: u8,
-}
-impl FooData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 4
-    }
-    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() < 4 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 4,
-                got: bytes.get().remaining(),
-            });
-        }
-        let chunk = bytes.get_mut().get_u32_le();
-        let a = (chunk & 0x3) as u8;
-        let b = ((chunk >> 2) & 0xff_ffff);
-        let c = ((chunk >> 26) & 0x3f) as u8;
-        Ok(Self { a, b, c })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        if self.a > 0x3 {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0x3);
-        }
-        if self.b > 0xff_ffff {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "b", self.b, 0xff_ffff);
-        }
-        if self.c > 0x3f {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "c", self.c, 0x3f);
-        }
-        let value = (self.a as u32) | (self.b << 2) | ((self.c as u32) << 26);
-        buffer.put_u32_le(value);
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        4
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    pub fn get_a(&self) -> u8 {
-        self.foo.a
-    }
-    pub fn get_b(&self) -> u32 {
-        self.foo.b
-    }
-    pub fn get_c(&self) -> u8 {
-        self.foo.c
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData {
-            a: self.a,
-            b: self.b,
-            c: self.c,
-        };
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_parent_with_alias_child_little_endian.rs b/tests/generated/packet_decl_parent_with_alias_child_little_endian.rs
deleted file mode 100644
index c0a1cf1..0000000
--- a/tests/generated/packet_decl_parent_with_alias_child_little_endian.rs
+++ /dev/null
@@ -1,919 +0,0 @@
-#![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
-    }
-}
-#[repr(u64)]
-#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
-pub enum Enum8 {
-    A = 0x0,
-    B = 0x1,
-    C = 0x2,
-}
-impl TryFrom<u8> for Enum8 {
-    type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
-        match value {
-            0x0 => Ok(Enum8::A),
-            0x1 => Ok(Enum8::B),
-            0x2 => Ok(Enum8::C),
-            _ => Err(value),
-        }
-    }
-}
-impl From<&Enum8> for u8 {
-    fn from(value: &Enum8) -> Self {
-        match value {
-            Enum8::A => 0x0,
-            Enum8::B => 0x1,
-            Enum8::C => 0x2,
-        }
-    }
-}
-impl From<Enum8> for u8 {
-    fn from(value: Enum8) -> Self {
-        (&value).into()
-    }
-}
-impl From<Enum8> for i16 {
-    fn from(value: Enum8) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<Enum8> for i32 {
-    fn from(value: Enum8) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<Enum8> for i64 {
-    fn from(value: Enum8) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<Enum8> for u16 {
-    fn from(value: Enum8) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<Enum8> for u32 {
-    fn from(value: Enum8) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<Enum8> for u64 {
-    fn from(value: Enum8) -> Self {
-        u8::from(value) as Self
-    }
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub enum ParentDataChild {
-    AliasChild(AliasChildData),
-    NormalChild(NormalChildData),
-    Payload(Bytes),
-    None,
-}
-impl ParentDataChild {
-    fn get_total_size(&self) -> usize {
-        match self {
-            ParentDataChild::AliasChild(value) => value.get_total_size(),
-            ParentDataChild::NormalChild(value) => value.get_total_size(),
-            ParentDataChild::Payload(bytes) => bytes.len(),
-            ParentDataChild::None => 0,
-        }
-    }
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub enum ParentChild {
-    AliasChild(AliasChild),
-    NormalChild(NormalChild),
-    Payload(Bytes),
-    None,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct ParentData {
-    v: Enum8,
-    child: ParentDataChild,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Parent {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    parent: ParentData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct ParentBuilder {
-    pub v: Enum8,
-    pub payload: Option<Bytes>,
-}
-impl ParentData {
-    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: "Parent".to_string(),
-                wanted: 1,
-                got: bytes.get().remaining(),
-            });
-        }
-        let v = Enum8::try_from(bytes.get_mut().get_u8())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Parent".to_string(),
-                field: "v".to_string(),
-                value: unknown_val as u64,
-                type_: "Enum8".to_string(),
-            })?;
-        let payload = bytes.get();
-        bytes.get_mut().advance(payload.len());
-        let child = match (v) {
-            (Enum8::B | Enum8::C) if AliasChildData::conforms(&payload) => {
-                let mut cell = Cell::new(payload);
-                let child_data = AliasChildData::parse_inner(&mut cell, v)?;
-                ParentDataChild::AliasChild(child_data)
-            }
-            (Enum8::A) if NormalChildData::conforms(&payload) => {
-                let mut cell = Cell::new(payload);
-                let child_data = NormalChildData::parse_inner(&mut cell)?;
-                ParentDataChild::NormalChild(child_data)
-            }
-            _ if !payload.is_empty() => {
-                ParentDataChild::Payload(Bytes::copy_from_slice(payload))
-            }
-            _ => ParentDataChild::None,
-        };
-        Ok(Self { v, child })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        buffer.put_u8(u8::from(self.v));
-        match &self.child {
-            ParentDataChild::AliasChild(child) => child.write_to(buffer),
-            ParentDataChild::NormalChild(child) => child.write_to(buffer),
-            ParentDataChild::Payload(payload) => buffer.put_slice(payload),
-            ParentDataChild::None => {}
-        }
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        1 + self.child.get_total_size()
-    }
-}
-impl Packet for Parent {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Parent> for Bytes {
-    fn from(packet: Parent) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Parent> for Vec<u8> {
-    fn from(packet: Parent) -> Self {
-        packet.to_vec()
-    }
-}
-impl Parent {
-    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 = ParentData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    pub fn specialize(&self) -> ParentChild {
-        match &self.parent.child {
-            ParentDataChild::AliasChild(_) => {
-                ParentChild::AliasChild(AliasChild::new(self.parent.clone()).unwrap())
-            }
-            ParentDataChild::NormalChild(_) => {
-                ParentChild::NormalChild(NormalChild::new(self.parent.clone()).unwrap())
-            }
-            ParentDataChild::Payload(payload) => ParentChild::Payload(payload.clone()),
-            ParentDataChild::None => ParentChild::None,
-        }
-    }
-    fn new(parent: ParentData) -> Result<Self> {
-        Ok(Self { parent })
-    }
-    pub fn get_v(&self) -> Enum8 {
-        self.parent.v
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.parent.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.parent.get_size()
-    }
-}
-impl ParentBuilder {
-    pub fn build(self) -> Parent {
-        let parent = ParentData {
-            v: self.v,
-            child: match self.payload {
-                None => ParentDataChild::None,
-                Some(bytes) => ParentDataChild::Payload(bytes),
-            },
-        };
-        Parent::new(parent).unwrap()
-    }
-}
-impl From<ParentBuilder> for Parent {
-    fn from(builder: ParentBuilder) -> Parent {
-        builder.build().into()
-    }
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub enum AliasChildDataChild {
-    NormalGrandChild1(NormalGrandChild1Data),
-    NormalGrandChild2(NormalGrandChild2Data),
-    Payload(Bytes),
-    None,
-}
-impl AliasChildDataChild {
-    fn get_total_size(&self) -> usize {
-        match self {
-            AliasChildDataChild::NormalGrandChild1(value) => value.get_total_size(),
-            AliasChildDataChild::NormalGrandChild2(value) => value.get_total_size(),
-            AliasChildDataChild::Payload(bytes) => bytes.len(),
-            AliasChildDataChild::None => 0,
-        }
-    }
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub enum AliasChildChild {
-    NormalGrandChild1(NormalGrandChild1),
-    NormalGrandChild2(NormalGrandChild2),
-    Payload(Bytes),
-    None,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct AliasChildData {
-    child: AliasChildDataChild,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct AliasChild {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    parent: ParentData,
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    aliaschild: AliasChildData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct AliasChildBuilder {
-    pub v: Enum8,
-    pub payload: Option<Bytes>,
-}
-impl AliasChildData {
-    fn conforms(bytes: &[u8]) -> bool {
-        true
-    }
-    fn parse(bytes: &[u8], v: Enum8) -> Result<Self> {
-        let mut cell = Cell::new(bytes);
-        let packet = Self::parse_inner(&mut cell, v)?;
-        Ok(packet)
-    }
-    fn parse_inner(mut bytes: &mut Cell<&[u8]>, v: Enum8) -> Result<Self> {
-        let payload = bytes.get();
-        bytes.get_mut().advance(payload.len());
-        let child = match (v) {
-            (Enum8::B) if NormalGrandChild1Data::conforms(&payload) => {
-                let mut cell = Cell::new(payload);
-                let child_data = NormalGrandChild1Data::parse_inner(&mut cell)?;
-                AliasChildDataChild::NormalGrandChild1(child_data)
-            }
-            (Enum8::C) if NormalGrandChild2Data::conforms(&payload) => {
-                let mut cell = Cell::new(payload);
-                let child_data = NormalGrandChild2Data::parse_inner(&mut cell)?;
-                AliasChildDataChild::NormalGrandChild2(child_data)
-            }
-            _ if !payload.is_empty() => {
-                AliasChildDataChild::Payload(Bytes::copy_from_slice(payload))
-            }
-            _ => AliasChildDataChild::None,
-        };
-        Ok(Self { child })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        match &self.child {
-            AliasChildDataChild::NormalGrandChild1(child) => child.write_to(buffer),
-            AliasChildDataChild::NormalGrandChild2(child) => child.write_to(buffer),
-            AliasChildDataChild::Payload(payload) => buffer.put_slice(payload),
-            AliasChildDataChild::None => {}
-        }
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        self.child.get_total_size()
-    }
-}
-impl Packet for AliasChild {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<AliasChild> for Bytes {
-    fn from(packet: AliasChild) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<AliasChild> for Vec<u8> {
-    fn from(packet: AliasChild) -> Self {
-        packet.to_vec()
-    }
-}
-impl From<AliasChild> for Parent {
-    fn from(packet: AliasChild) -> Parent {
-        Parent::new(packet.parent).unwrap()
-    }
-}
-impl TryFrom<Parent> for AliasChild {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<AliasChild> {
-        AliasChild::new(packet.parent)
-    }
-}
-impl AliasChild {
-    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 = ParentData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    pub fn specialize(&self) -> AliasChildChild {
-        match &self.aliaschild.child {
-            AliasChildDataChild::NormalGrandChild1(_) => {
-                AliasChildChild::NormalGrandChild1(
-                    NormalGrandChild1::new(self.parent.clone()).unwrap(),
-                )
-            }
-            AliasChildDataChild::NormalGrandChild2(_) => {
-                AliasChildChild::NormalGrandChild2(
-                    NormalGrandChild2::new(self.parent.clone()).unwrap(),
-                )
-            }
-            AliasChildDataChild::Payload(payload) => {
-                AliasChildChild::Payload(payload.clone())
-            }
-            AliasChildDataChild::None => AliasChildChild::None,
-        }
-    }
-    fn new(parent: ParentData) -> Result<Self> {
-        let aliaschild = match &parent.child {
-            ParentDataChild::AliasChild(value) => value.clone(),
-            _ => {
-                return Err(Error::InvalidChildError {
-                    expected: stringify!(ParentDataChild::AliasChild),
-                    actual: format!("{:?}", & parent.child),
-                });
-            }
-        };
-        Ok(Self { parent, aliaschild })
-    }
-    pub fn get_v(&self) -> Enum8 {
-        self.parent.v
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.aliaschild.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.parent.get_size()
-    }
-}
-impl AliasChildBuilder {
-    pub fn build(self) -> AliasChild {
-        let aliaschild = AliasChildData {
-            child: match self.payload {
-                None => AliasChildDataChild::None,
-                Some(bytes) => AliasChildDataChild::Payload(bytes),
-            },
-        };
-        let parent = ParentData {
-            v: self.v,
-            child: ParentDataChild::AliasChild(aliaschild),
-        };
-        AliasChild::new(parent).unwrap()
-    }
-}
-impl From<AliasChildBuilder> for Parent {
-    fn from(builder: AliasChildBuilder) -> Parent {
-        builder.build().into()
-    }
-}
-impl From<AliasChildBuilder> for AliasChild {
-    fn from(builder: AliasChildBuilder) -> AliasChild {
-        builder.build().into()
-    }
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct NormalChildData {}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct NormalChild {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    parent: ParentData,
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    normalchild: NormalChildData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct NormalChildBuilder {}
-impl NormalChildData {
-    fn conforms(bytes: &[u8]) -> bool {
-        true
-    }
-    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> {
-        Ok(Self {})
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {}
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        0
-    }
-}
-impl Packet for NormalChild {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<NormalChild> for Bytes {
-    fn from(packet: NormalChild) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<NormalChild> for Vec<u8> {
-    fn from(packet: NormalChild) -> Self {
-        packet.to_vec()
-    }
-}
-impl From<NormalChild> for Parent {
-    fn from(packet: NormalChild) -> Parent {
-        Parent::new(packet.parent).unwrap()
-    }
-}
-impl TryFrom<Parent> for NormalChild {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<NormalChild> {
-        NormalChild::new(packet.parent)
-    }
-}
-impl NormalChild {
-    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 = ParentData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(parent: ParentData) -> Result<Self> {
-        let normalchild = match &parent.child {
-            ParentDataChild::NormalChild(value) => value.clone(),
-            _ => {
-                return Err(Error::InvalidChildError {
-                    expected: stringify!(ParentDataChild::NormalChild),
-                    actual: format!("{:?}", & parent.child),
-                });
-            }
-        };
-        Ok(Self { parent, normalchild })
-    }
-    pub fn get_v(&self) -> Enum8 {
-        self.parent.v
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.normalchild.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.parent.get_size()
-    }
-}
-impl NormalChildBuilder {
-    pub fn build(self) -> NormalChild {
-        let normalchild = NormalChildData {};
-        let parent = ParentData {
-            v: Enum8::A,
-            child: ParentDataChild::NormalChild(normalchild),
-        };
-        NormalChild::new(parent).unwrap()
-    }
-}
-impl From<NormalChildBuilder> for Parent {
-    fn from(builder: NormalChildBuilder) -> Parent {
-        builder.build().into()
-    }
-}
-impl From<NormalChildBuilder> for NormalChild {
-    fn from(builder: NormalChildBuilder) -> NormalChild {
-        builder.build().into()
-    }
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct NormalGrandChild1Data {}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct NormalGrandChild1 {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    parent: ParentData,
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    aliaschild: AliasChildData,
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    normalgrandchild1: NormalGrandChild1Data,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct NormalGrandChild1Builder {}
-impl NormalGrandChild1Data {
-    fn conforms(bytes: &[u8]) -> bool {
-        true
-    }
-    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> {
-        Ok(Self {})
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {}
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        0
-    }
-}
-impl Packet for NormalGrandChild1 {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<NormalGrandChild1> for Bytes {
-    fn from(packet: NormalGrandChild1) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<NormalGrandChild1> for Vec<u8> {
-    fn from(packet: NormalGrandChild1) -> Self {
-        packet.to_vec()
-    }
-}
-impl From<NormalGrandChild1> for Parent {
-    fn from(packet: NormalGrandChild1) -> Parent {
-        Parent::new(packet.parent).unwrap()
-    }
-}
-impl From<NormalGrandChild1> for AliasChild {
-    fn from(packet: NormalGrandChild1) -> AliasChild {
-        AliasChild::new(packet.parent).unwrap()
-    }
-}
-impl TryFrom<Parent> for NormalGrandChild1 {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<NormalGrandChild1> {
-        NormalGrandChild1::new(packet.parent)
-    }
-}
-impl NormalGrandChild1 {
-    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 = ParentData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(parent: ParentData) -> Result<Self> {
-        let aliaschild = match &parent.child {
-            ParentDataChild::AliasChild(value) => value.clone(),
-            _ => {
-                return Err(Error::InvalidChildError {
-                    expected: stringify!(ParentDataChild::AliasChild),
-                    actual: format!("{:?}", & parent.child),
-                });
-            }
-        };
-        let normalgrandchild1 = match &aliaschild.child {
-            AliasChildDataChild::NormalGrandChild1(value) => value.clone(),
-            _ => {
-                return Err(Error::InvalidChildError {
-                    expected: stringify!(AliasChildDataChild::NormalGrandChild1),
-                    actual: format!("{:?}", & aliaschild.child),
-                });
-            }
-        };
-        Ok(Self {
-            parent,
-            aliaschild,
-            normalgrandchild1,
-        })
-    }
-    pub fn get_v(&self) -> Enum8 {
-        self.parent.v
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.normalgrandchild1.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.parent.get_size()
-    }
-}
-impl NormalGrandChild1Builder {
-    pub fn build(self) -> NormalGrandChild1 {
-        let normalgrandchild1 = NormalGrandChild1Data {};
-        let aliaschild = AliasChildData {
-            child: AliasChildDataChild::NormalGrandChild1(normalgrandchild1),
-        };
-        let parent = ParentData {
-            v: Enum8::B,
-            child: ParentDataChild::AliasChild(aliaschild),
-        };
-        NormalGrandChild1::new(parent).unwrap()
-    }
-}
-impl From<NormalGrandChild1Builder> for Parent {
-    fn from(builder: NormalGrandChild1Builder) -> Parent {
-        builder.build().into()
-    }
-}
-impl From<NormalGrandChild1Builder> for AliasChild {
-    fn from(builder: NormalGrandChild1Builder) -> AliasChild {
-        builder.build().into()
-    }
-}
-impl From<NormalGrandChild1Builder> for NormalGrandChild1 {
-    fn from(builder: NormalGrandChild1Builder) -> NormalGrandChild1 {
-        builder.build().into()
-    }
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub enum NormalGrandChild2DataChild {
-    Payload(Bytes),
-    None,
-}
-impl NormalGrandChild2DataChild {
-    fn get_total_size(&self) -> usize {
-        match self {
-            NormalGrandChild2DataChild::Payload(bytes) => bytes.len(),
-            NormalGrandChild2DataChild::None => 0,
-        }
-    }
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub enum NormalGrandChild2Child {
-    Payload(Bytes),
-    None,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct NormalGrandChild2Data {
-    child: NormalGrandChild2DataChild,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct NormalGrandChild2 {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    parent: ParentData,
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    aliaschild: AliasChildData,
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    normalgrandchild2: NormalGrandChild2Data,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct NormalGrandChild2Builder {
-    pub payload: Option<Bytes>,
-}
-impl NormalGrandChild2Data {
-    fn conforms(bytes: &[u8]) -> bool {
-        true
-    }
-    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 payload = bytes.get();
-        bytes.get_mut().advance(payload.len());
-        let child = match () {
-            _ if !payload.is_empty() => {
-                NormalGrandChild2DataChild::Payload(Bytes::copy_from_slice(payload))
-            }
-            _ => NormalGrandChild2DataChild::None,
-        };
-        Ok(Self { child })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        match &self.child {
-            NormalGrandChild2DataChild::Payload(payload) => buffer.put_slice(payload),
-            NormalGrandChild2DataChild::None => {}
-        }
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        self.child.get_total_size()
-    }
-}
-impl Packet for NormalGrandChild2 {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<NormalGrandChild2> for Bytes {
-    fn from(packet: NormalGrandChild2) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<NormalGrandChild2> for Vec<u8> {
-    fn from(packet: NormalGrandChild2) -> Self {
-        packet.to_vec()
-    }
-}
-impl From<NormalGrandChild2> for Parent {
-    fn from(packet: NormalGrandChild2) -> Parent {
-        Parent::new(packet.parent).unwrap()
-    }
-}
-impl From<NormalGrandChild2> for AliasChild {
-    fn from(packet: NormalGrandChild2) -> AliasChild {
-        AliasChild::new(packet.parent).unwrap()
-    }
-}
-impl TryFrom<Parent> for NormalGrandChild2 {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<NormalGrandChild2> {
-        NormalGrandChild2::new(packet.parent)
-    }
-}
-impl NormalGrandChild2 {
-    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 = ParentData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    pub fn specialize(&self) -> NormalGrandChild2Child {
-        match &self.normalgrandchild2.child {
-            NormalGrandChild2DataChild::Payload(payload) => {
-                NormalGrandChild2Child::Payload(payload.clone())
-            }
-            NormalGrandChild2DataChild::None => NormalGrandChild2Child::None,
-        }
-    }
-    fn new(parent: ParentData) -> Result<Self> {
-        let aliaschild = match &parent.child {
-            ParentDataChild::AliasChild(value) => value.clone(),
-            _ => {
-                return Err(Error::InvalidChildError {
-                    expected: stringify!(ParentDataChild::AliasChild),
-                    actual: format!("{:?}", & parent.child),
-                });
-            }
-        };
-        let normalgrandchild2 = match &aliaschild.child {
-            AliasChildDataChild::NormalGrandChild2(value) => value.clone(),
-            _ => {
-                return Err(Error::InvalidChildError {
-                    expected: stringify!(AliasChildDataChild::NormalGrandChild2),
-                    actual: format!("{:?}", & aliaschild.child),
-                });
-            }
-        };
-        Ok(Self {
-            parent,
-            aliaschild,
-            normalgrandchild2,
-        })
-    }
-    pub fn get_v(&self) -> Enum8 {
-        self.parent.v
-    }
-    pub fn get_payload(&self) -> &[u8] {
-        match &self.normalgrandchild2.child {
-            NormalGrandChild2DataChild::Payload(bytes) => &bytes,
-            NormalGrandChild2DataChild::None => &[],
-        }
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.normalgrandchild2.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.parent.get_size()
-    }
-}
-impl NormalGrandChild2Builder {
-    pub fn build(self) -> NormalGrandChild2 {
-        let normalgrandchild2 = NormalGrandChild2Data {
-            child: match self.payload {
-                None => NormalGrandChild2DataChild::None,
-                Some(bytes) => NormalGrandChild2DataChild::Payload(bytes),
-            },
-        };
-        let aliaschild = AliasChildData {
-            child: AliasChildDataChild::NormalGrandChild2(normalgrandchild2),
-        };
-        let parent = ParentData {
-            v: Enum8::C,
-            child: ParentDataChild::AliasChild(aliaschild),
-        };
-        NormalGrandChild2::new(parent).unwrap()
-    }
-}
-impl From<NormalGrandChild2Builder> for Parent {
-    fn from(builder: NormalGrandChild2Builder) -> Parent {
-        builder.build().into()
-    }
-}
-impl From<NormalGrandChild2Builder> for AliasChild {
-    fn from(builder: NormalGrandChild2Builder) -> AliasChild {
-        builder.build().into()
-    }
-}
-impl From<NormalGrandChild2Builder> for NormalGrandChild2 {
-    fn from(builder: NormalGrandChild2Builder) -> NormalGrandChild2 {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_parent_with_no_payload_little_endian.rs b/tests/generated/packet_decl_parent_with_no_payload_little_endian.rs
deleted file mode 100644
index 4bb083b..0000000
--- a/tests/generated/packet_decl_parent_with_no_payload_little_endian.rs
+++ /dev/null
@@ -1,350 +0,0 @@
-#![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
-    }
-}
-#[repr(u64)]
-#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
-pub enum Enum8 {
-    A = 0x0,
-}
-impl TryFrom<u8> for Enum8 {
-    type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
-        match value {
-            0x0 => Ok(Enum8::A),
-            _ => Err(value),
-        }
-    }
-}
-impl From<&Enum8> for u8 {
-    fn from(value: &Enum8) -> Self {
-        match value {
-            Enum8::A => 0x0,
-        }
-    }
-}
-impl From<Enum8> for u8 {
-    fn from(value: Enum8) -> Self {
-        (&value).into()
-    }
-}
-impl From<Enum8> for i16 {
-    fn from(value: Enum8) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<Enum8> for i32 {
-    fn from(value: Enum8) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<Enum8> for i64 {
-    fn from(value: Enum8) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<Enum8> for u16 {
-    fn from(value: Enum8) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<Enum8> for u32 {
-    fn from(value: Enum8) -> Self {
-        u8::from(value) as Self
-    }
-}
-impl From<Enum8> for u64 {
-    fn from(value: Enum8) -> Self {
-        u8::from(value) as Self
-    }
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub enum ParentDataChild {
-    Child(ChildData),
-    Payload(Bytes),
-    None,
-}
-impl ParentDataChild {
-    fn get_total_size(&self) -> usize {
-        match self {
-            ParentDataChild::Child(value) => value.get_total_size(),
-            ParentDataChild::Payload(bytes) => bytes.len(),
-            ParentDataChild::None => 0,
-        }
-    }
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub enum ParentChild {
-    Child(Child),
-    Payload(Bytes),
-    None,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct ParentData {
-    v: Enum8,
-    child: ParentDataChild,
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Parent {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    parent: ParentData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct ParentBuilder {
-    pub v: Enum8,
-    pub payload: Option<Bytes>,
-}
-impl ParentData {
-    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: "Parent".to_string(),
-                wanted: 1,
-                got: bytes.get().remaining(),
-            });
-        }
-        let v = Enum8::try_from(bytes.get_mut().get_u8())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Parent".to_string(),
-                field: "v".to_string(),
-                value: unknown_val as u64,
-                type_: "Enum8".to_string(),
-            })?;
-        let payload: &[u8] = &[];
-        let child = match (v) {
-            (Enum8::A) if ChildData::conforms(&payload) => {
-                let mut cell = Cell::new(payload);
-                let child_data = ChildData::parse_inner(&mut cell)?;
-                ParentDataChild::Child(child_data)
-            }
-            _ if !payload.is_empty() => {
-                ParentDataChild::Payload(Bytes::copy_from_slice(payload))
-            }
-            _ => ParentDataChild::None,
-        };
-        Ok(Self { v, child })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        buffer.put_u8(u8::from(self.v));
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        1
-    }
-}
-impl Packet for Parent {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Parent> for Bytes {
-    fn from(packet: Parent) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Parent> for Vec<u8> {
-    fn from(packet: Parent) -> Self {
-        packet.to_vec()
-    }
-}
-impl Parent {
-    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 = ParentData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    pub fn specialize(&self) -> ParentChild {
-        match &self.parent.child {
-            ParentDataChild::Child(_) => {
-                ParentChild::Child(Child::new(self.parent.clone()).unwrap())
-            }
-            ParentDataChild::Payload(payload) => ParentChild::Payload(payload.clone()),
-            ParentDataChild::None => ParentChild::None,
-        }
-    }
-    fn new(parent: ParentData) -> Result<Self> {
-        Ok(Self { parent })
-    }
-    pub fn get_v(&self) -> Enum8 {
-        self.parent.v
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.parent.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.parent.get_size()
-    }
-}
-impl ParentBuilder {
-    pub fn build(self) -> Parent {
-        let parent = ParentData {
-            v: self.v,
-            child: ParentDataChild::None,
-        };
-        Parent::new(parent).unwrap()
-    }
-}
-impl From<ParentBuilder> for Parent {
-    fn from(builder: ParentBuilder) -> Parent {
-        builder.build().into()
-    }
-}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct ChildData {}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Child {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    parent: ParentData,
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    child: ChildData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct ChildBuilder {}
-impl ChildData {
-    fn conforms(bytes: &[u8]) -> bool {
-        true
-    }
-    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> {
-        Ok(Self {})
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {}
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        0
-    }
-}
-impl Packet for Child {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Child> for Bytes {
-    fn from(packet: Child) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Child> for Vec<u8> {
-    fn from(packet: Child) -> Self {
-        packet.to_vec()
-    }
-}
-impl From<Child> for Parent {
-    fn from(packet: Child) -> Parent {
-        Parent::new(packet.parent).unwrap()
-    }
-}
-impl TryFrom<Parent> for Child {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<Child> {
-        Child::new(packet.parent)
-    }
-}
-impl Child {
-    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 = ParentData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(parent: ParentData) -> Result<Self> {
-        let child = match &parent.child {
-            ParentDataChild::Child(value) => value.clone(),
-            _ => {
-                return Err(Error::InvalidChildError {
-                    expected: stringify!(ParentDataChild::Child),
-                    actual: format!("{:?}", & parent.child),
-                });
-            }
-        };
-        Ok(Self { parent, child })
-    }
-    pub fn get_v(&self) -> Enum8 {
-        self.parent.v
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.child.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.parent.get_size()
-    }
-}
-impl ChildBuilder {
-    pub fn build(self) -> Child {
-        let child = ChildData {};
-        let parent = ParentData {
-            v: Enum8::A,
-            child: ParentDataChild::None,
-        };
-        Child::new(parent).unwrap()
-    }
-}
-impl From<ChildBuilder> for Parent {
-    fn from(builder: ChildBuilder) -> Parent {
-        builder.build().into()
-    }
-}
-impl From<ChildBuilder> for Child {
-    fn from(builder: ChildBuilder) -> Child {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_reserved_field_big_endian.rs b/tests/generated/packet_decl_reserved_field_big_endian.rs
deleted file mode 100644
index b296e58..0000000
--- a/tests/generated/packet_decl_reserved_field_big_endian.rs
+++ /dev/null
@@ -1,113 +0,0 @@
-#![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 struct FooData {}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {}
-impl FooData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 5
-    }
-    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() < 5 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 5,
-                got: bytes.get().remaining(),
-            });
-        }
-        bytes.get_mut().advance(5);
-        Ok(Self {})
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        buffer.put_bytes(0, 5);
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        5
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData {};
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/packet_decl_reserved_field_little_endian.rs b/tests/generated/packet_decl_reserved_field_little_endian.rs
deleted file mode 100644
index b296e58..0000000
--- a/tests/generated/packet_decl_reserved_field_little_endian.rs
+++ /dev/null
@@ -1,113 +0,0 @@
-#![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 struct FooData {}
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct Foo {
-    #[cfg_attr(feature = "serde", serde(flatten))]
-    foo: FooData,
-}
-#[derive(Debug)]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-pub struct FooBuilder {}
-impl FooData {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 5
-    }
-    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() < 5 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 5,
-                got: bytes.get().remaining(),
-            });
-        }
-        bytes.get_mut().advance(5);
-        Ok(Self {})
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        buffer.put_bytes(0, 5);
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        5
-    }
-}
-impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
-    }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
-    }
-}
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
-    }
-}
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
-    }
-}
-impl Foo {
-    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 = FooData::parse_inner(&mut bytes)?;
-        Self::new(data)
-    }
-    fn new(foo: FooData) -> Result<Self> {
-        Ok(Self { foo })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        self.foo.write_to(buffer)
-    }
-    pub fn get_size(&self) -> usize {
-        self.foo.get_size()
-    }
-}
-impl FooBuilder {
-    pub fn build(self) -> Foo {
-        let foo = FooData {};
-        Foo::new(foo).unwrap()
-    }
-}
-impl From<FooBuilder> for Foo {
-    fn from(builder: FooBuilder) -> Foo {
-        builder.build().into()
-    }
-}
diff --git a/tests/generated/preamble.rs b/tests/generated/preamble.rs
index dd11680..ab77b58 100644
--- a/tests/generated/preamble.rs
+++ b/tests/generated/preamble.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,3 +18,8 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
diff --git a/tests/generated/rust/custom_field_declaration_big_endian.rs b/tests/generated/rust/custom_field_declaration_big_endian.rs
new file mode 100644
index 0000000..e5e9d5b
--- /dev/null
+++ b/tests/generated/rust/custom_field_declaration_big_endian.rs
@@ -0,0 +1,102 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(from = "u32", into = "u32"))]
+pub struct ExactSize(u32);
+impl From<&ExactSize> for u32 {
+    fn from(value: &ExactSize) -> u32 {
+        value.0
+    }
+}
+impl From<ExactSize> for u32 {
+    fn from(value: ExactSize) -> u32 {
+        value.0
+    }
+}
+impl Packet for ExactSize {
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.len() < 4 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "ExactSize",
+                wanted: 4,
+                got: buf.len(),
+            });
+        }
+        Ok((buf.get_u32().into(), buf))
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u32(u32::from(self));
+        Ok(())
+    }
+    fn encoded_len(&self) -> usize {
+        4
+    }
+}
+impl From<u32> for ExactSize {
+    fn from(value: u32) -> Self {
+        ExactSize(value)
+    }
+}
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u32", into = "u32"))]
+pub struct TruncatedSize(u32);
+impl From<&TruncatedSize> for u32 {
+    fn from(value: &TruncatedSize) -> u32 {
+        value.0
+    }
+}
+impl From<TruncatedSize> for u32 {
+    fn from(value: TruncatedSize) -> u32 {
+        value.0
+    }
+}
+impl Packet for TruncatedSize {
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.len() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "TruncatedSize",
+                wanted: 3,
+                got: buf.len(),
+            });
+        }
+        Ok(((buf.get_uint(3) as u32).try_into().unwrap(), buf))
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_uint(u32::from(self) as u64, 3);
+        Ok(())
+    }
+    fn encoded_len(&self) -> usize {
+        3
+    }
+}
+impl TryFrom<u32> for TruncatedSize {
+    type Error = u32;
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
+        if value > 0xff_ffff { Err(value) } else { Ok(TruncatedSize(value)) }
+    }
+}
diff --git a/tests/generated/rust/custom_field_declaration_little_endian.rs b/tests/generated/rust/custom_field_declaration_little_endian.rs
new file mode 100644
index 0000000..bc1874c
--- /dev/null
+++ b/tests/generated/rust/custom_field_declaration_little_endian.rs
@@ -0,0 +1,102 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(from = "u32", into = "u32"))]
+pub struct ExactSize(u32);
+impl From<&ExactSize> for u32 {
+    fn from(value: &ExactSize) -> u32 {
+        value.0
+    }
+}
+impl From<ExactSize> for u32 {
+    fn from(value: ExactSize) -> u32 {
+        value.0
+    }
+}
+impl Packet for ExactSize {
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.len() < 4 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "ExactSize",
+                wanted: 4,
+                got: buf.len(),
+            });
+        }
+        Ok((buf.get_u32_le().into(), buf))
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u32_le(u32::from(self));
+        Ok(())
+    }
+    fn encoded_len(&self) -> usize {
+        4
+    }
+}
+impl From<u32> for ExactSize {
+    fn from(value: u32) -> Self {
+        ExactSize(value)
+    }
+}
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u32", into = "u32"))]
+pub struct TruncatedSize(u32);
+impl From<&TruncatedSize> for u32 {
+    fn from(value: &TruncatedSize) -> u32 {
+        value.0
+    }
+}
+impl From<TruncatedSize> for u32 {
+    fn from(value: TruncatedSize) -> u32 {
+        value.0
+    }
+}
+impl Packet for TruncatedSize {
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.len() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "TruncatedSize",
+                wanted: 3,
+                got: buf.len(),
+            });
+        }
+        Ok(((buf.get_uint_le(3) as u32).try_into().unwrap(), buf))
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_uint_le(u32::from(self) as u64, 3);
+        Ok(())
+    }
+    fn encoded_len(&self) -> usize {
+        3
+    }
+}
+impl TryFrom<u32> for TruncatedSize {
+    type Error = u32;
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
+        if value > 0xff_ffff { Err(value) } else { Ok(TruncatedSize(value)) }
+    }
+}
diff --git a/tests/generated/enum_declaration_big_endian.rs b/tests/generated/rust/enum_declaration_big_endian.rs
similarity index 95%
rename from tests/generated/enum_declaration_big_endian.rs
rename to tests/generated/rust/enum_declaration_big_endian.rs
index bd90591..dcff08e 100644
--- a/tests/generated/enum_declaration_big_endian.rs
+++ b/tests/generated/rust/enum_declaration_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u8> for IncompleteTruncatedClosed {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(IncompleteTruncatedClosed::A),
             0x1 => Ok(IncompleteTruncatedClosed::B),
@@ -94,7 +99,7 @@
 }
 impl TryFrom<u8> for IncompleteTruncatedOpen {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(IncompleteTruncatedOpen::A),
             0x1 => Ok(IncompleteTruncatedOpen::B),
@@ -163,7 +168,7 @@
 }
 impl TryFrom<u8> for IncompleteTruncatedClosedWithRange {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(IncompleteTruncatedClosedWithRange::A),
             0x1 => Ok(IncompleteTruncatedClosedWithRange::X),
@@ -235,7 +240,7 @@
 }
 impl TryFrom<u8> for IncompleteTruncatedOpenWithRange {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(IncompleteTruncatedOpenWithRange::A),
             0x1 => Ok(IncompleteTruncatedOpenWithRange::X),
@@ -313,7 +318,7 @@
 }
 impl TryFrom<u8> for CompleteTruncated {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(CompleteTruncated::A),
             0x1 => Ok(CompleteTruncated::B),
@@ -392,7 +397,7 @@
 }
 impl TryFrom<u8> for CompleteTruncatedWithRange {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(CompleteTruncatedWithRange::A),
             0x1 => Ok(CompleteTruncatedWithRange::X),
@@ -462,7 +467,7 @@
 }
 impl TryFrom<u8> for CompleteWithRange {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(CompleteWithRange::A),
             0x1 => Ok(CompleteWithRange::B),
diff --git a/tests/generated/enum_declaration_big_endian.rs b/tests/generated/rust/enum_declaration_little_endian.rs
similarity index 95%
copy from tests/generated/enum_declaration_big_endian.rs
copy to tests/generated/rust/enum_declaration_little_endian.rs
index bd90591..dcff08e 100644
--- a/tests/generated/enum_declaration_big_endian.rs
+++ b/tests/generated/rust/enum_declaration_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u8> for IncompleteTruncatedClosed {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(IncompleteTruncatedClosed::A),
             0x1 => Ok(IncompleteTruncatedClosed::B),
@@ -94,7 +99,7 @@
 }
 impl TryFrom<u8> for IncompleteTruncatedOpen {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(IncompleteTruncatedOpen::A),
             0x1 => Ok(IncompleteTruncatedOpen::B),
@@ -163,7 +168,7 @@
 }
 impl TryFrom<u8> for IncompleteTruncatedClosedWithRange {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(IncompleteTruncatedClosedWithRange::A),
             0x1 => Ok(IncompleteTruncatedClosedWithRange::X),
@@ -235,7 +240,7 @@
 }
 impl TryFrom<u8> for IncompleteTruncatedOpenWithRange {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(IncompleteTruncatedOpenWithRange::A),
             0x1 => Ok(IncompleteTruncatedOpenWithRange::X),
@@ -313,7 +318,7 @@
 }
 impl TryFrom<u8> for CompleteTruncated {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(CompleteTruncated::A),
             0x1 => Ok(CompleteTruncated::B),
@@ -392,7 +397,7 @@
 }
 impl TryFrom<u8> for CompleteTruncatedWithRange {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(CompleteTruncatedWithRange::A),
             0x1 => Ok(CompleteTruncatedWithRange::X),
@@ -462,7 +467,7 @@
 }
 impl TryFrom<u8> for CompleteWithRange {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(CompleteWithRange::A),
             0x1 => Ok(CompleteWithRange::B),
diff --git a/tests/generated/rust/packet_decl_24bit_enum_array_big_endian.rs b/tests/generated/rust/packet_decl_24bit_enum_array_big_endian.rs
new file mode 100644
index 0000000..6fe68e4
--- /dev/null
+++ b/tests/generated/rust/packet_decl_24bit_enum_array_big_endian.rs
@@ -0,0 +1,115 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u32", into = "u32"))]
+pub enum Foo {
+    FooBar = 0x1,
+    Baz = 0x2,
+}
+impl TryFrom<u32> for Foo {
+    type Error = u32;
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Foo::FooBar),
+            0x2 => Ok(Foo::Baz),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Foo> for u32 {
+    fn from(value: &Foo) -> Self {
+        match value {
+            Foo::FooBar => 0x1,
+            Foo::Baz => 0x2,
+        }
+    }
+}
+impl From<Foo> for u32 {
+    fn from(value: Foo) -> Self {
+        (&value).into()
+    }
+}
+impl From<Foo> for i32 {
+    fn from(value: Foo) -> Self {
+        u32::from(value) as Self
+    }
+}
+impl From<Foo> for i64 {
+    fn from(value: Foo) -> Self {
+        u32::from(value) as Self
+    }
+}
+impl From<Foo> for u64 {
+    fn from(value: Foo) -> Self {
+        u32::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: [Foo; 5],
+}
+impl Bar {
+    pub fn x(&self) -> &[Foo; 5] {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        self.x.len() * 3
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.x {
+            buf.put_uint(u32::from(elem) as u64, 3);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 5 * 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 5 * 3,
+                got: buf.remaining(),
+            });
+        }
+        let mut x = Vec::with_capacity(5);
+        for _ in 0..5 {
+            x.push(
+                Foo::try_from(buf.get_uint(3) as u32)
+                    .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                        obj: "Bar",
+                        field: "",
+                        value: unknown_val as u64,
+                        type_: "Foo",
+                    })?,
+            )
+        }
+        let x = x.try_into().map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_24bit_enum_array_little_endian.rs b/tests/generated/rust/packet_decl_24bit_enum_array_little_endian.rs
new file mode 100644
index 0000000..2e863dd
--- /dev/null
+++ b/tests/generated/rust/packet_decl_24bit_enum_array_little_endian.rs
@@ -0,0 +1,115 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u32", into = "u32"))]
+pub enum Foo {
+    FooBar = 0x1,
+    Baz = 0x2,
+}
+impl TryFrom<u32> for Foo {
+    type Error = u32;
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Foo::FooBar),
+            0x2 => Ok(Foo::Baz),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Foo> for u32 {
+    fn from(value: &Foo) -> Self {
+        match value {
+            Foo::FooBar => 0x1,
+            Foo::Baz => 0x2,
+        }
+    }
+}
+impl From<Foo> for u32 {
+    fn from(value: Foo) -> Self {
+        (&value).into()
+    }
+}
+impl From<Foo> for i32 {
+    fn from(value: Foo) -> Self {
+        u32::from(value) as Self
+    }
+}
+impl From<Foo> for i64 {
+    fn from(value: Foo) -> Self {
+        u32::from(value) as Self
+    }
+}
+impl From<Foo> for u64 {
+    fn from(value: Foo) -> Self {
+        u32::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: [Foo; 5],
+}
+impl Bar {
+    pub fn x(&self) -> &[Foo; 5] {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        self.x.len() * 3
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.x {
+            buf.put_uint_le(u32::from(elem) as u64, 3);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 5 * 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 5 * 3,
+                got: buf.remaining(),
+            });
+        }
+        let mut x = Vec::with_capacity(5);
+        for _ in 0..5 {
+            x.push(
+                Foo::try_from(buf.get_uint_le(3) as u32)
+                    .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                        obj: "Bar",
+                        field: "",
+                        value: unknown_val as u64,
+                        type_: "Foo",
+                    })?,
+            )
+        }
+        let x = x.try_into().map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_24bit_enum_big_endian.rs b/tests/generated/rust/packet_decl_24bit_enum_big_endian.rs
new file mode 100644
index 0000000..ed6b119
--- /dev/null
+++ b/tests/generated/rust/packet_decl_24bit_enum_big_endian.rs
@@ -0,0 +1,107 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u32", into = "u32"))]
+pub enum Foo {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u32> for Foo {
+    type Error = u32;
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Foo::A),
+            0x2 => Ok(Foo::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Foo> for u32 {
+    fn from(value: &Foo) -> Self {
+        match value {
+            Foo::A => 0x1,
+            Foo::B => 0x2,
+        }
+    }
+}
+impl From<Foo> for u32 {
+    fn from(value: Foo) -> Self {
+        (&value).into()
+    }
+}
+impl From<Foo> for i32 {
+    fn from(value: Foo) -> Self {
+        u32::from(value) as Self
+    }
+}
+impl From<Foo> for i64 {
+    fn from(value: Foo) -> Self {
+        u32::from(value) as Self
+    }
+}
+impl From<Foo> for u64 {
+    fn from(value: Foo) -> Self {
+        u32::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: Foo,
+}
+impl Bar {
+    pub fn x(&self) -> Foo {
+        self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        3
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_uint(u32::from(self.x()) as u64, 3);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let x = Foo::try_from(buf.get_uint(3) as u32)
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Bar",
+                field: "x",
+                value: unknown_val as u64,
+                type_: "Foo",
+            })?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_24bit_enum_little_endian.rs b/tests/generated/rust/packet_decl_24bit_enum_little_endian.rs
new file mode 100644
index 0000000..d31578c
--- /dev/null
+++ b/tests/generated/rust/packet_decl_24bit_enum_little_endian.rs
@@ -0,0 +1,107 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u32", into = "u32"))]
+pub enum Foo {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u32> for Foo {
+    type Error = u32;
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Foo::A),
+            0x2 => Ok(Foo::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Foo> for u32 {
+    fn from(value: &Foo) -> Self {
+        match value {
+            Foo::A => 0x1,
+            Foo::B => 0x2,
+        }
+    }
+}
+impl From<Foo> for u32 {
+    fn from(value: Foo) -> Self {
+        (&value).into()
+    }
+}
+impl From<Foo> for i32 {
+    fn from(value: Foo) -> Self {
+        u32::from(value) as Self
+    }
+}
+impl From<Foo> for i64 {
+    fn from(value: Foo) -> Self {
+        u32::from(value) as Self
+    }
+}
+impl From<Foo> for u64 {
+    fn from(value: Foo) -> Self {
+        u32::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: Foo,
+}
+impl Bar {
+    pub fn x(&self) -> Foo {
+        self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        3
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_uint_le(u32::from(self.x()) as u64, 3);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let x = Foo::try_from(buf.get_uint_le(3) as u32)
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Bar",
+                field: "x",
+                value: unknown_val as u64,
+                type_: "Foo",
+            })?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_24bit_scalar_array_big_endian.rs b/tests/generated/rust/packet_decl_24bit_scalar_array_big_endian.rs
new file mode 100644
index 0000000..4cb8e6c
--- /dev/null
+++ b/tests/generated/rust/packet_decl_24bit_scalar_array_big_endian.rs
@@ -0,0 +1,61 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub x: [u32; 5],
+}
+impl Foo {
+    pub fn x(&self) -> &[u32; 5] {
+        &self.x
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.x.len() * 3
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.x {
+            buf.put_uint(*elem as u64, 3);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 5 * 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 5 * 3,
+                got: buf.remaining(),
+            });
+        }
+        let mut x = Vec::with_capacity(5);
+        for _ in 0..5 {
+            x.push(Ok::<_, DecodeError>(buf.get_uint(3) as u32)?)
+        }
+        let x = x.try_into().map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_24bit_scalar_array_little_endian.rs b/tests/generated/rust/packet_decl_24bit_scalar_array_little_endian.rs
new file mode 100644
index 0000000..08f2cd5
--- /dev/null
+++ b/tests/generated/rust/packet_decl_24bit_scalar_array_little_endian.rs
@@ -0,0 +1,61 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub x: [u32; 5],
+}
+impl Foo {
+    pub fn x(&self) -> &[u32; 5] {
+        &self.x
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.x.len() * 3
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.x {
+            buf.put_uint_le(*elem as u64, 3);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 5 * 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 5 * 3,
+                got: buf.remaining(),
+            });
+        }
+        let mut x = Vec::with_capacity(5);
+        for _ in 0..5 {
+            x.push(Ok::<_, DecodeError>(buf.get_uint_le(3) as u32)?)
+        }
+        let x = x.try_into().map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_24bit_scalar_big_endian.rs b/tests/generated/rust/packet_decl_24bit_scalar_big_endian.rs
new file mode 100644
index 0000000..d00b083
--- /dev/null
+++ b/tests/generated/rust/packet_decl_24bit_scalar_big_endian.rs
@@ -0,0 +1,63 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub x: u32,
+}
+impl Foo {
+    pub fn x(&self) -> u32 {
+        self.x
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        3
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.x() > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "x",
+                value: self.x() as u64,
+                maximum_value: 0xff_ffff as u64,
+            });
+        }
+        buf.put_uint(self.x() as u64, 3);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf.get_uint(3) as u32;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_24bit_scalar_little_endian.rs b/tests/generated/rust/packet_decl_24bit_scalar_little_endian.rs
new file mode 100644
index 0000000..1959bab
--- /dev/null
+++ b/tests/generated/rust/packet_decl_24bit_scalar_little_endian.rs
@@ -0,0 +1,63 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub x: u32,
+}
+impl Foo {
+    pub fn x(&self) -> u32 {
+        self.x
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        3
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.x() > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "x",
+                value: self.x() as u64,
+                maximum_value: 0xff_ffff as u64,
+            });
+        }
+        buf.put_uint_le(self.x() as u64, 3);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf.get_uint_le(3) as u32;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_64bit_enum_array_big_endian.rs b/tests/generated/rust/packet_decl_64bit_enum_array_big_endian.rs
new file mode 100644
index 0000000..f46a9bf
--- /dev/null
+++ b/tests/generated/rust/packet_decl_64bit_enum_array_big_endian.rs
@@ -0,0 +1,100 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u64", into = "u64"))]
+pub enum Foo {
+    FooBar = 0x1,
+    Baz = 0x2,
+}
+impl TryFrom<u64> for Foo {
+    type Error = u64;
+    fn try_from(value: u64) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Foo::FooBar),
+            0x2 => Ok(Foo::Baz),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Foo> for u64 {
+    fn from(value: &Foo) -> Self {
+        match value {
+            Foo::FooBar => 0x1,
+            Foo::Baz => 0x2,
+        }
+    }
+}
+impl From<Foo> for u64 {
+    fn from(value: Foo) -> Self {
+        (&value).into()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: [Foo; 7],
+}
+impl Bar {
+    pub fn x(&self) -> &[Foo; 7] {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        self.x.len() * 8
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.x {
+            buf.put_u64(u64::from(elem));
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 7 * 8 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 7 * 8,
+                got: buf.remaining(),
+            });
+        }
+        let mut x = Vec::with_capacity(7);
+        for _ in 0..7 {
+            x.push(
+                Foo::try_from(buf.get_u64())
+                    .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                        obj: "Bar",
+                        field: "",
+                        value: unknown_val as u64,
+                        type_: "Foo",
+                    })?,
+            )
+        }
+        let x = x.try_into().map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_64bit_enum_array_little_endian.rs b/tests/generated/rust/packet_decl_64bit_enum_array_little_endian.rs
new file mode 100644
index 0000000..ee0ae20
--- /dev/null
+++ b/tests/generated/rust/packet_decl_64bit_enum_array_little_endian.rs
@@ -0,0 +1,100 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u64", into = "u64"))]
+pub enum Foo {
+    FooBar = 0x1,
+    Baz = 0x2,
+}
+impl TryFrom<u64> for Foo {
+    type Error = u64;
+    fn try_from(value: u64) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Foo::FooBar),
+            0x2 => Ok(Foo::Baz),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Foo> for u64 {
+    fn from(value: &Foo) -> Self {
+        match value {
+            Foo::FooBar => 0x1,
+            Foo::Baz => 0x2,
+        }
+    }
+}
+impl From<Foo> for u64 {
+    fn from(value: Foo) -> Self {
+        (&value).into()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: [Foo; 7],
+}
+impl Bar {
+    pub fn x(&self) -> &[Foo; 7] {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        self.x.len() * 8
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.x {
+            buf.put_u64_le(u64::from(elem));
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 7 * 8 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 7 * 8,
+                got: buf.remaining(),
+            });
+        }
+        let mut x = Vec::with_capacity(7);
+        for _ in 0..7 {
+            x.push(
+                Foo::try_from(buf.get_u64_le())
+                    .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                        obj: "Bar",
+                        field: "",
+                        value: unknown_val as u64,
+                        type_: "Foo",
+                    })?,
+            )
+        }
+        let x = x.try_into().map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_64bit_enum_big_endian.rs b/tests/generated/rust/packet_decl_64bit_enum_big_endian.rs
new file mode 100644
index 0000000..3858625
--- /dev/null
+++ b/tests/generated/rust/packet_decl_64bit_enum_big_endian.rs
@@ -0,0 +1,92 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u64", into = "u64"))]
+pub enum Foo {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u64> for Foo {
+    type Error = u64;
+    fn try_from(value: u64) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Foo::A),
+            0x2 => Ok(Foo::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Foo> for u64 {
+    fn from(value: &Foo) -> Self {
+        match value {
+            Foo::A => 0x1,
+            Foo::B => 0x2,
+        }
+    }
+}
+impl From<Foo> for u64 {
+    fn from(value: Foo) -> Self {
+        (&value).into()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: Foo,
+}
+impl Bar {
+    pub fn x(&self) -> Foo {
+        self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        8
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u64(u64::from(self.x()));
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 8 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 8,
+                got: buf.remaining(),
+            });
+        }
+        let x = Foo::try_from(buf.get_u64())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Bar",
+                field: "x",
+                value: unknown_val as u64,
+                type_: "Foo",
+            })?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_64bit_enum_little_endian.rs b/tests/generated/rust/packet_decl_64bit_enum_little_endian.rs
new file mode 100644
index 0000000..aa34078
--- /dev/null
+++ b/tests/generated/rust/packet_decl_64bit_enum_little_endian.rs
@@ -0,0 +1,92 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u64", into = "u64"))]
+pub enum Foo {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u64> for Foo {
+    type Error = u64;
+    fn try_from(value: u64) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Foo::A),
+            0x2 => Ok(Foo::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Foo> for u64 {
+    fn from(value: &Foo) -> Self {
+        match value {
+            Foo::A => 0x1,
+            Foo::B => 0x2,
+        }
+    }
+}
+impl From<Foo> for u64 {
+    fn from(value: Foo) -> Self {
+        (&value).into()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: Foo,
+}
+impl Bar {
+    pub fn x(&self) -> Foo {
+        self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        8
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u64_le(u64::from(self.x()));
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 8 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 8,
+                got: buf.remaining(),
+            });
+        }
+        let x = Foo::try_from(buf.get_u64_le())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Bar",
+                field: "x",
+                value: unknown_val as u64,
+                type_: "Foo",
+            })?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_64bit_scalar_array_big_endian.rs b/tests/generated/rust/packet_decl_64bit_scalar_array_big_endian.rs
new file mode 100644
index 0000000..666de4b
--- /dev/null
+++ b/tests/generated/rust/packet_decl_64bit_scalar_array_big_endian.rs
@@ -0,0 +1,61 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub x: [u64; 7],
+}
+impl Foo {
+    pub fn x(&self) -> &[u64; 7] {
+        &self.x
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.x.len() * 8
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.x {
+            buf.put_u64(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 7 * 8 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 7 * 8,
+                got: buf.remaining(),
+            });
+        }
+        let mut x = Vec::with_capacity(7);
+        for _ in 0..7 {
+            x.push(Ok::<_, DecodeError>(buf.get_u64())?)
+        }
+        let x = x.try_into().map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_64bit_scalar_array_little_endian.rs b/tests/generated/rust/packet_decl_64bit_scalar_array_little_endian.rs
new file mode 100644
index 0000000..a5ad742
--- /dev/null
+++ b/tests/generated/rust/packet_decl_64bit_scalar_array_little_endian.rs
@@ -0,0 +1,61 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub x: [u64; 7],
+}
+impl Foo {
+    pub fn x(&self) -> &[u64; 7] {
+        &self.x
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.x.len() * 8
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.x {
+            buf.put_u64_le(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 7 * 8 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 7 * 8,
+                got: buf.remaining(),
+            });
+        }
+        let mut x = Vec::with_capacity(7);
+        for _ in 0..7 {
+            x.push(Ok::<_, DecodeError>(buf.get_u64_le())?)
+        }
+        let x = x.try_into().map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_64bit_scalar_big_endian.rs b/tests/generated/rust/packet_decl_64bit_scalar_big_endian.rs
new file mode 100644
index 0000000..38c4e71
--- /dev/null
+++ b/tests/generated/rust/packet_decl_64bit_scalar_big_endian.rs
@@ -0,0 +1,55 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub x: u64,
+}
+impl Foo {
+    pub fn x(&self) -> u64 {
+        self.x
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        8
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u64(self.x());
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 8 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 8,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf.get_u64();
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_64bit_scalar_little_endian.rs b/tests/generated/rust/packet_decl_64bit_scalar_little_endian.rs
new file mode 100644
index 0000000..d993814
--- /dev/null
+++ b/tests/generated/rust/packet_decl_64bit_scalar_little_endian.rs
@@ -0,0 +1,55 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub x: u64,
+}
+impl Foo {
+    pub fn x(&self) -> u64 {
+        self.x
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        8
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u64_le(self.x());
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 8 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 8,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf.get_u64_le();
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_8bit_enum_array_big_endian.rs b/tests/generated/rust/packet_decl_8bit_enum_array_big_endian.rs
new file mode 100644
index 0000000..e48e5fc
--- /dev/null
+++ b/tests/generated/rust/packet_decl_8bit_enum_array_big_endian.rs
@@ -0,0 +1,130 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
+pub enum Foo {
+    FooBar = 0x1,
+    Baz = 0x2,
+}
+impl TryFrom<u8> for Foo {
+    type Error = u8;
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Foo::FooBar),
+            0x2 => Ok(Foo::Baz),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Foo> for u8 {
+    fn from(value: &Foo) -> Self {
+        match value {
+            Foo::FooBar => 0x1,
+            Foo::Baz => 0x2,
+        }
+    }
+}
+impl From<Foo> for u8 {
+    fn from(value: Foo) -> Self {
+        (&value).into()
+    }
+}
+impl From<Foo> for i16 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for i32 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for i64 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for u16 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for u32 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for u64 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: [Foo; 3],
+}
+impl Bar {
+    pub fn x(&self) -> &[Foo; 3] {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        self.x.len() * 1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.x {
+            buf.put_u8(u8::from(elem));
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let mut x = Vec::with_capacity(3);
+        for _ in 0..3 {
+            x.push(
+                Foo::try_from(buf.get_u8())
+                    .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                        obj: "Bar",
+                        field: "",
+                        value: unknown_val as u64,
+                        type_: "Foo",
+                    })?,
+            )
+        }
+        let x = x.try_into().map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_8bit_enum_array_little_endian.rs b/tests/generated/rust/packet_decl_8bit_enum_array_little_endian.rs
new file mode 100644
index 0000000..e48e5fc
--- /dev/null
+++ b/tests/generated/rust/packet_decl_8bit_enum_array_little_endian.rs
@@ -0,0 +1,130 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
+pub enum Foo {
+    FooBar = 0x1,
+    Baz = 0x2,
+}
+impl TryFrom<u8> for Foo {
+    type Error = u8;
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Foo::FooBar),
+            0x2 => Ok(Foo::Baz),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Foo> for u8 {
+    fn from(value: &Foo) -> Self {
+        match value {
+            Foo::FooBar => 0x1,
+            Foo::Baz => 0x2,
+        }
+    }
+}
+impl From<Foo> for u8 {
+    fn from(value: Foo) -> Self {
+        (&value).into()
+    }
+}
+impl From<Foo> for i16 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for i32 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for i64 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for u16 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for u32 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for u64 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: [Foo; 3],
+}
+impl Bar {
+    pub fn x(&self) -> &[Foo; 3] {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        self.x.len() * 1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.x {
+            buf.put_u8(u8::from(elem));
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let mut x = Vec::with_capacity(3);
+        for _ in 0..3 {
+            x.push(
+                Foo::try_from(buf.get_u8())
+                    .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                        obj: "Bar",
+                        field: "",
+                        value: unknown_val as u64,
+                        type_: "Foo",
+                    })?,
+            )
+        }
+        let x = x.try_into().map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_8bit_enum_big_endian.rs b/tests/generated/rust/packet_decl_8bit_enum_big_endian.rs
new file mode 100644
index 0000000..809b880
--- /dev/null
+++ b/tests/generated/rust/packet_decl_8bit_enum_big_endian.rs
@@ -0,0 +1,122 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
+pub enum Foo {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u8> for Foo {
+    type Error = u8;
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Foo::A),
+            0x2 => Ok(Foo::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Foo> for u8 {
+    fn from(value: &Foo) -> Self {
+        match value {
+            Foo::A => 0x1,
+            Foo::B => 0x2,
+        }
+    }
+}
+impl From<Foo> for u8 {
+    fn from(value: Foo) -> Self {
+        (&value).into()
+    }
+}
+impl From<Foo> for i16 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for i32 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for i64 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for u16 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for u32 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for u64 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: Foo,
+}
+impl Bar {
+    pub fn x(&self) -> Foo {
+        self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(u8::from(self.x()));
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let x = Foo::try_from(buf.get_u8())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Bar",
+                field: "x",
+                value: unknown_val as u64,
+                type_: "Foo",
+            })?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_8bit_enum_little_endian.rs b/tests/generated/rust/packet_decl_8bit_enum_little_endian.rs
new file mode 100644
index 0000000..809b880
--- /dev/null
+++ b/tests/generated/rust/packet_decl_8bit_enum_little_endian.rs
@@ -0,0 +1,122 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
+pub enum Foo {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u8> for Foo {
+    type Error = u8;
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Foo::A),
+            0x2 => Ok(Foo::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Foo> for u8 {
+    fn from(value: &Foo) -> Self {
+        match value {
+            Foo::A => 0x1,
+            Foo::B => 0x2,
+        }
+    }
+}
+impl From<Foo> for u8 {
+    fn from(value: Foo) -> Self {
+        (&value).into()
+    }
+}
+impl From<Foo> for i16 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for i32 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for i64 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for u16 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for u32 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Foo> for u64 {
+    fn from(value: Foo) -> Self {
+        u8::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: Foo,
+}
+impl Bar {
+    pub fn x(&self) -> Foo {
+        self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(u8::from(self.x()));
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let x = Foo::try_from(buf.get_u8())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Bar",
+                field: "x",
+                value: unknown_val as u64,
+                type_: "Foo",
+            })?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_8bit_scalar_array_big_endian.rs b/tests/generated/rust/packet_decl_8bit_scalar_array_big_endian.rs
new file mode 100644
index 0000000..ad91b8d
--- /dev/null
+++ b/tests/generated/rust/packet_decl_8bit_scalar_array_big_endian.rs
@@ -0,0 +1,61 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub x: [u8; 3],
+}
+impl Foo {
+    pub fn x(&self) -> &[u8; 3] {
+        &self.x
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.x.len() * 1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.x {
+            buf.put_u8(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let mut x = Vec::with_capacity(3);
+        for _ in 0..3 {
+            x.push(Ok::<_, DecodeError>(buf.get_u8())?)
+        }
+        let x = x.try_into().map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_8bit_scalar_array_little_endian.rs b/tests/generated/rust/packet_decl_8bit_scalar_array_little_endian.rs
new file mode 100644
index 0000000..ad91b8d
--- /dev/null
+++ b/tests/generated/rust/packet_decl_8bit_scalar_array_little_endian.rs
@@ -0,0 +1,61 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub x: [u8; 3],
+}
+impl Foo {
+    pub fn x(&self) -> &[u8; 3] {
+        &self.x
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.x.len() * 1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.x {
+            buf.put_u8(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let mut x = Vec::with_capacity(3);
+        for _ in 0..3 {
+            x.push(Ok::<_, DecodeError>(buf.get_u8())?)
+        }
+        let x = x.try_into().map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_8bit_scalar_big_endian.rs b/tests/generated/rust/packet_decl_8bit_scalar_big_endian.rs
new file mode 100644
index 0000000..d49959b
--- /dev/null
+++ b/tests/generated/rust/packet_decl_8bit_scalar_big_endian.rs
@@ -0,0 +1,55 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub x: u8,
+}
+impl Foo {
+    pub fn x(&self) -> u8 {
+        self.x
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.x());
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf.get_u8();
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_8bit_scalar_little_endian.rs b/tests/generated/rust/packet_decl_8bit_scalar_little_endian.rs
new file mode 100644
index 0000000..d49959b
--- /dev/null
+++ b/tests/generated/rust/packet_decl_8bit_scalar_little_endian.rs
@@ -0,0 +1,55 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub x: u8,
+}
+impl Foo {
+    pub fn x(&self) -> u8 {
+        self.x
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.x());
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf.get_u8();
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_dynamic_count_big_endian.rs b/tests/generated/rust/packet_decl_array_dynamic_count_big_endian.rs
new file mode 100644
index 0000000..2c6faa8
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_dynamic_count_big_endian.rs
@@ -0,0 +1,91 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub padding: u8,
+    pub x: Vec<u32>,
+}
+impl Foo {
+    pub fn padding(&self) -> u8 {
+        self.padding
+    }
+    pub fn x(&self) -> &Vec<u32> {
+        &self.x
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        1 + self.x.len() * 3
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.x.len() > 0x1f {
+            return Err(EncodeError::CountOverflow {
+                packet: "Foo",
+                field: "x",
+                count: self.x.len(),
+                maximum_count: 0x1f,
+            });
+        }
+        if self.padding() > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "padding",
+                value: self.padding() as u64,
+                maximum_value: 0x7 as u64,
+            });
+        }
+        let value = self.x.len() as u8 | (self.padding() << 5);
+        buf.put_u8(value);
+        for elem in &self.x {
+            buf.put_uint(*elem as u64, 3);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u8();
+        let x_count = (chunk & 0x1f) as usize;
+        let padding = ((chunk >> 5) & 0x7);
+        if buf.remaining() < x_count * 3usize {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: x_count * 3usize,
+                got: buf.remaining(),
+            });
+        }
+        let x = (0..x_count)
+            .map(|_| Ok::<_, DecodeError>(buf.get_uint(3) as u32))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        Ok((Self { padding, x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_dynamic_count_little_endian.rs b/tests/generated/rust/packet_decl_array_dynamic_count_little_endian.rs
new file mode 100644
index 0000000..687a614
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_dynamic_count_little_endian.rs
@@ -0,0 +1,91 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub padding: u8,
+    pub x: Vec<u32>,
+}
+impl Foo {
+    pub fn padding(&self) -> u8 {
+        self.padding
+    }
+    pub fn x(&self) -> &Vec<u32> {
+        &self.x
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        1 + self.x.len() * 3
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.x.len() > 0x1f {
+            return Err(EncodeError::CountOverflow {
+                packet: "Foo",
+                field: "x",
+                count: self.x.len(),
+                maximum_count: 0x1f,
+            });
+        }
+        if self.padding() > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "padding",
+                value: self.padding() as u64,
+                maximum_value: 0x7 as u64,
+            });
+        }
+        let value = self.x.len() as u8 | (self.padding() << 5);
+        buf.put_u8(value);
+        for elem in &self.x {
+            buf.put_uint_le(*elem as u64, 3);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u8();
+        let x_count = (chunk & 0x1f) as usize;
+        let padding = ((chunk >> 5) & 0x7);
+        if buf.remaining() < x_count * 3usize {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: x_count * 3usize,
+                got: buf.remaining(),
+            });
+        }
+        let x = (0..x_count)
+            .map(|_| Ok::<_, DecodeError>(buf.get_uint_le(3) as u32))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        Ok((Self { padding, x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_dynamic_element_size_big_endian.rs b/tests/generated/rust/packet_decl_array_dynamic_element_size_big_endian.rs
new file mode 100644
index 0000000..bd95da3
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_dynamic_element_size_big_endian.rs
@@ -0,0 +1,146 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub inner: Vec<u8>,
+}
+impl Foo {
+    pub fn inner(&self) -> &Vec<u8> {
+        &self.inner
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.inner.len() * 1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.inner {
+            buf.put_u8(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let mut inner = Vec::with_capacity(buf.remaining());
+        for _ in 0..buf.remaining() {
+            inner.push(Ok::<_, DecodeError>(buf.get_u8())?);
+        }
+        Ok((Self { inner }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub padding: u8,
+    pub x: Vec<Foo>,
+}
+impl Bar {
+    pub fn padding(&self) -> u8 {
+        self.padding
+    }
+    pub fn x(&self) -> &Vec<Foo> {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        1 + self.x.iter().map(Packet::encoded_len).sum::<usize>()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        let x_element_size = self.x.get(0).map_or(0, Packet::encoded_len);
+        for (element_index, element) in self.x.iter().enumerate() {
+            if element.encoded_len() != x_element_size {
+                return Err(EncodeError::InvalidArrayElementSize {
+                    packet: "Bar",
+                    field: "x",
+                    size: element.encoded_len(),
+                    expected_size: x_element_size,
+                    element_index,
+                });
+            }
+        }
+        if x_element_size > 0x1f {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "x",
+                size: x_element_size,
+                maximum_size: 0x1f,
+            });
+        }
+        let x_element_size = x_element_size as u8;
+        if self.padding() > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Bar",
+                field: "padding",
+                value: self.padding() as u64,
+                maximum_value: 0x7 as u64,
+            });
+        }
+        let value = x_element_size | (self.padding() << 5);
+        buf.put_u8(value);
+        for elem in &self.x {
+            elem.encode(buf)?;
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u8();
+        let x_element_size = (chunk & 0x1f) as usize;
+        let padding = ((chunk >> 5) & 0x7);
+        if buf.remaining() % x_element_size != 0 {
+            return Err(DecodeError::InvalidArraySize {
+                array: buf.remaining(),
+                element: x_element_size,
+            });
+        }
+        let x = buf
+            .chunks(x_element_size)
+            .take(buf.remaining() / x_element_size)
+            .map(|mut chunk| {
+                Foo::decode_mut(&mut chunk)
+                    .and_then(|value| {
+                        if chunk.is_empty() {
+                            Ok(value)
+                        } else {
+                            Err(DecodeError::TrailingBytesInArray {
+                                obj: "Bar",
+                                field: "x",
+                            })
+                        }
+                    })
+            })
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        buf = &buf[buf.remaining()..];
+        Ok((Self { padding, x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_dynamic_element_size_dynamic_count_big_endian.rs b/tests/generated/rust/packet_decl_array_dynamic_element_size_dynamic_count_big_endian.rs
new file mode 100644
index 0000000..795f94b
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_dynamic_element_size_dynamic_count_big_endian.rs
@@ -0,0 +1,143 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub inner: Vec<u8>,
+}
+impl Foo {
+    pub fn inner(&self) -> &Vec<u8> {
+        &self.inner
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.inner.len() * 1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.inner {
+            buf.put_u8(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let mut inner = Vec::with_capacity(buf.remaining());
+        for _ in 0..buf.remaining() {
+            inner.push(Ok::<_, DecodeError>(buf.get_u8())?);
+        }
+        Ok((Self { inner }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: Vec<Foo>,
+}
+impl Bar {
+    pub fn x(&self) -> &Vec<Foo> {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        1 + self.x.iter().map(Packet::encoded_len).sum::<usize>()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.x.len() > 0xf {
+            return Err(EncodeError::CountOverflow {
+                packet: "Bar",
+                field: "x",
+                count: self.x.len(),
+                maximum_count: 0xf,
+            });
+        }
+        let x_element_size = self.x.get(0).map_or(0, Packet::encoded_len);
+        for (element_index, element) in self.x.iter().enumerate() {
+            if element.encoded_len() != x_element_size {
+                return Err(EncodeError::InvalidArrayElementSize {
+                    packet: "Bar",
+                    field: "x",
+                    size: element.encoded_len(),
+                    expected_size: x_element_size,
+                    element_index,
+                });
+            }
+        }
+        if x_element_size > 0xf {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "x",
+                size: x_element_size,
+                maximum_size: 0xf,
+            });
+        }
+        let x_element_size = x_element_size as u8;
+        let value = self.x.len() as u8 | (x_element_size << 4);
+        buf.put_u8(value);
+        for elem in &self.x {
+            elem.encode(buf)?;
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u8();
+        let x_count = (chunk & 0xf) as usize;
+        let x_element_size = ((chunk >> 4) & 0xf) as usize;
+        if buf.remaining() < x_count * x_element_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: x_count * x_element_size,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf
+            .chunks(x_element_size)
+            .take(x_count)
+            .map(|mut chunk| {
+                Foo::decode_mut(&mut chunk)
+                    .and_then(|value| {
+                        if chunk.is_empty() {
+                            Ok(value)
+                        } else {
+                            Err(DecodeError::TrailingBytesInArray {
+                                obj: "Bar",
+                                field: "x",
+                            })
+                        }
+                    })
+            })
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        buf = &buf[(x_element_size * x_count)..];
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_dynamic_element_size_dynamic_count_little_endian.rs b/tests/generated/rust/packet_decl_array_dynamic_element_size_dynamic_count_little_endian.rs
new file mode 100644
index 0000000..795f94b
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_dynamic_element_size_dynamic_count_little_endian.rs
@@ -0,0 +1,143 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub inner: Vec<u8>,
+}
+impl Foo {
+    pub fn inner(&self) -> &Vec<u8> {
+        &self.inner
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.inner.len() * 1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.inner {
+            buf.put_u8(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let mut inner = Vec::with_capacity(buf.remaining());
+        for _ in 0..buf.remaining() {
+            inner.push(Ok::<_, DecodeError>(buf.get_u8())?);
+        }
+        Ok((Self { inner }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: Vec<Foo>,
+}
+impl Bar {
+    pub fn x(&self) -> &Vec<Foo> {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        1 + self.x.iter().map(Packet::encoded_len).sum::<usize>()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.x.len() > 0xf {
+            return Err(EncodeError::CountOverflow {
+                packet: "Bar",
+                field: "x",
+                count: self.x.len(),
+                maximum_count: 0xf,
+            });
+        }
+        let x_element_size = self.x.get(0).map_or(0, Packet::encoded_len);
+        for (element_index, element) in self.x.iter().enumerate() {
+            if element.encoded_len() != x_element_size {
+                return Err(EncodeError::InvalidArrayElementSize {
+                    packet: "Bar",
+                    field: "x",
+                    size: element.encoded_len(),
+                    expected_size: x_element_size,
+                    element_index,
+                });
+            }
+        }
+        if x_element_size > 0xf {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "x",
+                size: x_element_size,
+                maximum_size: 0xf,
+            });
+        }
+        let x_element_size = x_element_size as u8;
+        let value = self.x.len() as u8 | (x_element_size << 4);
+        buf.put_u8(value);
+        for elem in &self.x {
+            elem.encode(buf)?;
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u8();
+        let x_count = (chunk & 0xf) as usize;
+        let x_element_size = ((chunk >> 4) & 0xf) as usize;
+        if buf.remaining() < x_count * x_element_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: x_count * x_element_size,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf
+            .chunks(x_element_size)
+            .take(x_count)
+            .map(|mut chunk| {
+                Foo::decode_mut(&mut chunk)
+                    .and_then(|value| {
+                        if chunk.is_empty() {
+                            Ok(value)
+                        } else {
+                            Err(DecodeError::TrailingBytesInArray {
+                                obj: "Bar",
+                                field: "x",
+                            })
+                        }
+                    })
+            })
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        buf = &buf[(x_element_size * x_count)..];
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_dynamic_element_size_dynamic_size_big_endian.rs b/tests/generated/rust/packet_decl_array_dynamic_element_size_dynamic_size_big_endian.rs
new file mode 100644
index 0000000..aa84e02
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_dynamic_element_size_dynamic_size_big_endian.rs
@@ -0,0 +1,150 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub inner: Vec<u8>,
+}
+impl Foo {
+    pub fn inner(&self) -> &Vec<u8> {
+        &self.inner
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.inner.len() * 1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.inner {
+            buf.put_u8(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let mut inner = Vec::with_capacity(buf.remaining());
+        for _ in 0..buf.remaining() {
+            inner.push(Ok::<_, DecodeError>(buf.get_u8())?);
+        }
+        Ok((Self { inner }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: Vec<Foo>,
+}
+impl Bar {
+    pub fn x(&self) -> &Vec<Foo> {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        1 + self.x.iter().map(Packet::encoded_len).sum::<usize>()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        let x_size = self.x.iter().map(Packet::encoded_len).sum::<usize>();
+        if x_size > 0xf {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "x",
+                size: x_size,
+                maximum_size: 0xf,
+            });
+        }
+        let x_element_size = self.x.get(0).map_or(0, Packet::encoded_len);
+        for (element_index, element) in self.x.iter().enumerate() {
+            if element.encoded_len() != x_element_size {
+                return Err(EncodeError::InvalidArrayElementSize {
+                    packet: "Bar",
+                    field: "x",
+                    size: element.encoded_len(),
+                    expected_size: x_element_size,
+                    element_index,
+                });
+            }
+        }
+        if x_element_size > 0xf {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "x",
+                size: x_element_size,
+                maximum_size: 0xf,
+            });
+        }
+        let x_element_size = x_element_size as u8;
+        let value = x_size as u8 | (x_element_size << 4);
+        buf.put_u8(value);
+        for elem in &self.x {
+            elem.encode(buf)?;
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u8();
+        let x_size = (chunk & 0xf) as usize;
+        let x_element_size = ((chunk >> 4) & 0xf) as usize;
+        if buf.remaining() < x_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: x_size,
+                got: buf.remaining(),
+            });
+        }
+        if x_size % x_element_size != 0 {
+            return Err(DecodeError::InvalidArraySize {
+                array: x_size,
+                element: x_element_size,
+            });
+        }
+        let x = buf
+            .chunks(x_element_size)
+            .take(x_size / x_element_size)
+            .map(|mut chunk| {
+                Foo::decode_mut(&mut chunk)
+                    .and_then(|value| {
+                        if chunk.is_empty() {
+                            Ok(value)
+                        } else {
+                            Err(DecodeError::TrailingBytesInArray {
+                                obj: "Bar",
+                                field: "x",
+                            })
+                        }
+                    })
+            })
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        buf = &buf[x_size..];
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_dynamic_element_size_dynamic_size_little_endian.rs b/tests/generated/rust/packet_decl_array_dynamic_element_size_dynamic_size_little_endian.rs
new file mode 100644
index 0000000..aa84e02
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_dynamic_element_size_dynamic_size_little_endian.rs
@@ -0,0 +1,150 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub inner: Vec<u8>,
+}
+impl Foo {
+    pub fn inner(&self) -> &Vec<u8> {
+        &self.inner
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.inner.len() * 1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.inner {
+            buf.put_u8(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let mut inner = Vec::with_capacity(buf.remaining());
+        for _ in 0..buf.remaining() {
+            inner.push(Ok::<_, DecodeError>(buf.get_u8())?);
+        }
+        Ok((Self { inner }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: Vec<Foo>,
+}
+impl Bar {
+    pub fn x(&self) -> &Vec<Foo> {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        1 + self.x.iter().map(Packet::encoded_len).sum::<usize>()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        let x_size = self.x.iter().map(Packet::encoded_len).sum::<usize>();
+        if x_size > 0xf {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "x",
+                size: x_size,
+                maximum_size: 0xf,
+            });
+        }
+        let x_element_size = self.x.get(0).map_or(0, Packet::encoded_len);
+        for (element_index, element) in self.x.iter().enumerate() {
+            if element.encoded_len() != x_element_size {
+                return Err(EncodeError::InvalidArrayElementSize {
+                    packet: "Bar",
+                    field: "x",
+                    size: element.encoded_len(),
+                    expected_size: x_element_size,
+                    element_index,
+                });
+            }
+        }
+        if x_element_size > 0xf {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "x",
+                size: x_element_size,
+                maximum_size: 0xf,
+            });
+        }
+        let x_element_size = x_element_size as u8;
+        let value = x_size as u8 | (x_element_size << 4);
+        buf.put_u8(value);
+        for elem in &self.x {
+            elem.encode(buf)?;
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u8();
+        let x_size = (chunk & 0xf) as usize;
+        let x_element_size = ((chunk >> 4) & 0xf) as usize;
+        if buf.remaining() < x_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: x_size,
+                got: buf.remaining(),
+            });
+        }
+        if x_size % x_element_size != 0 {
+            return Err(DecodeError::InvalidArraySize {
+                array: x_size,
+                element: x_element_size,
+            });
+        }
+        let x = buf
+            .chunks(x_element_size)
+            .take(x_size / x_element_size)
+            .map(|mut chunk| {
+                Foo::decode_mut(&mut chunk)
+                    .and_then(|value| {
+                        if chunk.is_empty() {
+                            Ok(value)
+                        } else {
+                            Err(DecodeError::TrailingBytesInArray {
+                                obj: "Bar",
+                                field: "x",
+                            })
+                        }
+                    })
+            })
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        buf = &buf[x_size..];
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_dynamic_element_size_little_endian.rs b/tests/generated/rust/packet_decl_array_dynamic_element_size_little_endian.rs
new file mode 100644
index 0000000..bd95da3
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_dynamic_element_size_little_endian.rs
@@ -0,0 +1,146 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub inner: Vec<u8>,
+}
+impl Foo {
+    pub fn inner(&self) -> &Vec<u8> {
+        &self.inner
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.inner.len() * 1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.inner {
+            buf.put_u8(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let mut inner = Vec::with_capacity(buf.remaining());
+        for _ in 0..buf.remaining() {
+            inner.push(Ok::<_, DecodeError>(buf.get_u8())?);
+        }
+        Ok((Self { inner }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub padding: u8,
+    pub x: Vec<Foo>,
+}
+impl Bar {
+    pub fn padding(&self) -> u8 {
+        self.padding
+    }
+    pub fn x(&self) -> &Vec<Foo> {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        1 + self.x.iter().map(Packet::encoded_len).sum::<usize>()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        let x_element_size = self.x.get(0).map_or(0, Packet::encoded_len);
+        for (element_index, element) in self.x.iter().enumerate() {
+            if element.encoded_len() != x_element_size {
+                return Err(EncodeError::InvalidArrayElementSize {
+                    packet: "Bar",
+                    field: "x",
+                    size: element.encoded_len(),
+                    expected_size: x_element_size,
+                    element_index,
+                });
+            }
+        }
+        if x_element_size > 0x1f {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "x",
+                size: x_element_size,
+                maximum_size: 0x1f,
+            });
+        }
+        let x_element_size = x_element_size as u8;
+        if self.padding() > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Bar",
+                field: "padding",
+                value: self.padding() as u64,
+                maximum_value: 0x7 as u64,
+            });
+        }
+        let value = x_element_size | (self.padding() << 5);
+        buf.put_u8(value);
+        for elem in &self.x {
+            elem.encode(buf)?;
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u8();
+        let x_element_size = (chunk & 0x1f) as usize;
+        let padding = ((chunk >> 5) & 0x7);
+        if buf.remaining() % x_element_size != 0 {
+            return Err(DecodeError::InvalidArraySize {
+                array: buf.remaining(),
+                element: x_element_size,
+            });
+        }
+        let x = buf
+            .chunks(x_element_size)
+            .take(buf.remaining() / x_element_size)
+            .map(|mut chunk| {
+                Foo::decode_mut(&mut chunk)
+                    .and_then(|value| {
+                        if chunk.is_empty() {
+                            Ok(value)
+                        } else {
+                            Err(DecodeError::TrailingBytesInArray {
+                                obj: "Bar",
+                                field: "x",
+                            })
+                        }
+                    })
+            })
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        buf = &buf[buf.remaining()..];
+        Ok((Self { padding, x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_dynamic_element_size_static_count_1_big_endian.rs b/tests/generated/rust/packet_decl_array_dynamic_element_size_static_count_1_big_endian.rs
new file mode 100644
index 0000000..8b38b98
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_dynamic_element_size_static_count_1_big_endian.rs
@@ -0,0 +1,148 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub inner: Vec<u8>,
+}
+impl Foo {
+    pub fn inner(&self) -> &Vec<u8> {
+        &self.inner
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.inner.len() * 1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.inner {
+            buf.put_u8(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let mut inner = Vec::with_capacity(buf.remaining());
+        for _ in 0..buf.remaining() {
+            inner.push(Ok::<_, DecodeError>(buf.get_u8())?);
+        }
+        Ok((Self { inner }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub padding: u8,
+    pub x: [Foo; 1],
+}
+impl Bar {
+    pub fn padding(&self) -> u8 {
+        self.padding
+    }
+    pub fn x(&self) -> &[Foo; 1] {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        1 + self.x.iter().map(Packet::encoded_len).sum::<usize>()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        let x_element_size = self.x.get(0).map_or(0, Packet::encoded_len);
+        for (element_index, element) in self.x.iter().enumerate() {
+            if element.encoded_len() != x_element_size {
+                return Err(EncodeError::InvalidArrayElementSize {
+                    packet: "Bar",
+                    field: "x",
+                    size: element.encoded_len(),
+                    expected_size: x_element_size,
+                    element_index,
+                });
+            }
+        }
+        if x_element_size > 0x1f {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "x",
+                size: x_element_size,
+                maximum_size: 0x1f,
+            });
+        }
+        let x_element_size = x_element_size as u8;
+        if self.padding() > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Bar",
+                field: "padding",
+                value: self.padding() as u64,
+                maximum_value: 0x7 as u64,
+            });
+        }
+        let value = x_element_size | (self.padding() << 5);
+        buf.put_u8(value);
+        for elem in &self.x {
+            elem.encode(buf)?;
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u8();
+        let x_element_size = (chunk & 0x1f) as usize;
+        let padding = ((chunk >> 5) & 0x7);
+        if buf.remaining() < x_element_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: x_element_size,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf
+            .chunks(x_element_size)
+            .take(1usize)
+            .map(|mut chunk| {
+                Foo::decode_mut(&mut chunk)
+                    .and_then(|value| {
+                        if chunk.is_empty() {
+                            Ok(value)
+                        } else {
+                            Err(DecodeError::TrailingBytesInArray {
+                                obj: "Bar",
+                                field: "x",
+                            })
+                        }
+                    })
+            })
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        buf = &buf[x_element_size..];
+        let x = x.try_into().map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok((Self { padding, x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_dynamic_element_size_static_count_1_little_endian.rs b/tests/generated/rust/packet_decl_array_dynamic_element_size_static_count_1_little_endian.rs
new file mode 100644
index 0000000..8b38b98
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_dynamic_element_size_static_count_1_little_endian.rs
@@ -0,0 +1,148 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub inner: Vec<u8>,
+}
+impl Foo {
+    pub fn inner(&self) -> &Vec<u8> {
+        &self.inner
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.inner.len() * 1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.inner {
+            buf.put_u8(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let mut inner = Vec::with_capacity(buf.remaining());
+        for _ in 0..buf.remaining() {
+            inner.push(Ok::<_, DecodeError>(buf.get_u8())?);
+        }
+        Ok((Self { inner }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub padding: u8,
+    pub x: [Foo; 1],
+}
+impl Bar {
+    pub fn padding(&self) -> u8 {
+        self.padding
+    }
+    pub fn x(&self) -> &[Foo; 1] {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        1 + self.x.iter().map(Packet::encoded_len).sum::<usize>()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        let x_element_size = self.x.get(0).map_or(0, Packet::encoded_len);
+        for (element_index, element) in self.x.iter().enumerate() {
+            if element.encoded_len() != x_element_size {
+                return Err(EncodeError::InvalidArrayElementSize {
+                    packet: "Bar",
+                    field: "x",
+                    size: element.encoded_len(),
+                    expected_size: x_element_size,
+                    element_index,
+                });
+            }
+        }
+        if x_element_size > 0x1f {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "x",
+                size: x_element_size,
+                maximum_size: 0x1f,
+            });
+        }
+        let x_element_size = x_element_size as u8;
+        if self.padding() > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Bar",
+                field: "padding",
+                value: self.padding() as u64,
+                maximum_value: 0x7 as u64,
+            });
+        }
+        let value = x_element_size | (self.padding() << 5);
+        buf.put_u8(value);
+        for elem in &self.x {
+            elem.encode(buf)?;
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u8();
+        let x_element_size = (chunk & 0x1f) as usize;
+        let padding = ((chunk >> 5) & 0x7);
+        if buf.remaining() < x_element_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: x_element_size,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf
+            .chunks(x_element_size)
+            .take(1usize)
+            .map(|mut chunk| {
+                Foo::decode_mut(&mut chunk)
+                    .and_then(|value| {
+                        if chunk.is_empty() {
+                            Ok(value)
+                        } else {
+                            Err(DecodeError::TrailingBytesInArray {
+                                obj: "Bar",
+                                field: "x",
+                            })
+                        }
+                    })
+            })
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        buf = &buf[x_element_size..];
+        let x = x.try_into().map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok((Self { padding, x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_dynamic_element_size_static_count_big_endian.rs b/tests/generated/rust/packet_decl_array_dynamic_element_size_static_count_big_endian.rs
new file mode 100644
index 0000000..0a86f0e
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_dynamic_element_size_static_count_big_endian.rs
@@ -0,0 +1,148 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub inner: Vec<u8>,
+}
+impl Foo {
+    pub fn inner(&self) -> &Vec<u8> {
+        &self.inner
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.inner.len() * 1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.inner {
+            buf.put_u8(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let mut inner = Vec::with_capacity(buf.remaining());
+        for _ in 0..buf.remaining() {
+            inner.push(Ok::<_, DecodeError>(buf.get_u8())?);
+        }
+        Ok((Self { inner }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub padding: u8,
+    pub x: [Foo; 4],
+}
+impl Bar {
+    pub fn padding(&self) -> u8 {
+        self.padding
+    }
+    pub fn x(&self) -> &[Foo; 4] {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        1 + self.x.iter().map(Packet::encoded_len).sum::<usize>()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        let x_element_size = self.x.get(0).map_or(0, Packet::encoded_len);
+        for (element_index, element) in self.x.iter().enumerate() {
+            if element.encoded_len() != x_element_size {
+                return Err(EncodeError::InvalidArrayElementSize {
+                    packet: "Bar",
+                    field: "x",
+                    size: element.encoded_len(),
+                    expected_size: x_element_size,
+                    element_index,
+                });
+            }
+        }
+        if x_element_size > 0x1f {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "x",
+                size: x_element_size,
+                maximum_size: 0x1f,
+            });
+        }
+        let x_element_size = x_element_size as u8;
+        if self.padding() > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Bar",
+                field: "padding",
+                value: self.padding() as u64,
+                maximum_value: 0x7 as u64,
+            });
+        }
+        let value = x_element_size | (self.padding() << 5);
+        buf.put_u8(value);
+        for elem in &self.x {
+            elem.encode(buf)?;
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u8();
+        let x_element_size = (chunk & 0x1f) as usize;
+        let padding = ((chunk >> 5) & 0x7);
+        if buf.remaining() < 4usize * x_element_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 4usize * x_element_size,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf
+            .chunks(x_element_size)
+            .take(4usize)
+            .map(|mut chunk| {
+                Foo::decode_mut(&mut chunk)
+                    .and_then(|value| {
+                        if chunk.is_empty() {
+                            Ok(value)
+                        } else {
+                            Err(DecodeError::TrailingBytesInArray {
+                                obj: "Bar",
+                                field: "x",
+                            })
+                        }
+                    })
+            })
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        buf = &buf[4usize * x_element_size..];
+        let x = x.try_into().map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok((Self { padding, x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_dynamic_element_size_static_count_little_endian.rs b/tests/generated/rust/packet_decl_array_dynamic_element_size_static_count_little_endian.rs
new file mode 100644
index 0000000..0a86f0e
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_dynamic_element_size_static_count_little_endian.rs
@@ -0,0 +1,148 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub inner: Vec<u8>,
+}
+impl Foo {
+    pub fn inner(&self) -> &Vec<u8> {
+        &self.inner
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.inner.len() * 1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        for elem in &self.inner {
+            buf.put_u8(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let mut inner = Vec::with_capacity(buf.remaining());
+        for _ in 0..buf.remaining() {
+            inner.push(Ok::<_, DecodeError>(buf.get_u8())?);
+        }
+        Ok((Self { inner }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub padding: u8,
+    pub x: [Foo; 4],
+}
+impl Bar {
+    pub fn padding(&self) -> u8 {
+        self.padding
+    }
+    pub fn x(&self) -> &[Foo; 4] {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        1 + self.x.iter().map(Packet::encoded_len).sum::<usize>()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        let x_element_size = self.x.get(0).map_or(0, Packet::encoded_len);
+        for (element_index, element) in self.x.iter().enumerate() {
+            if element.encoded_len() != x_element_size {
+                return Err(EncodeError::InvalidArrayElementSize {
+                    packet: "Bar",
+                    field: "x",
+                    size: element.encoded_len(),
+                    expected_size: x_element_size,
+                    element_index,
+                });
+            }
+        }
+        if x_element_size > 0x1f {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "x",
+                size: x_element_size,
+                maximum_size: 0x1f,
+            });
+        }
+        let x_element_size = x_element_size as u8;
+        if self.padding() > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Bar",
+                field: "padding",
+                value: self.padding() as u64,
+                maximum_value: 0x7 as u64,
+            });
+        }
+        let value = x_element_size | (self.padding() << 5);
+        buf.put_u8(value);
+        for elem in &self.x {
+            elem.encode(buf)?;
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u8();
+        let x_element_size = (chunk & 0x1f) as usize;
+        let padding = ((chunk >> 5) & 0x7);
+        if buf.remaining() < 4usize * x_element_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 4usize * x_element_size,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf
+            .chunks(x_element_size)
+            .take(4usize)
+            .map(|mut chunk| {
+                Foo::decode_mut(&mut chunk)
+                    .and_then(|value| {
+                        if chunk.is_empty() {
+                            Ok(value)
+                        } else {
+                            Err(DecodeError::TrailingBytesInArray {
+                                obj: "Bar",
+                                field: "x",
+                            })
+                        }
+                    })
+            })
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        buf = &buf[4usize * x_element_size..];
+        let x = x.try_into().map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok((Self { padding, x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_dynamic_size_big_endian.rs b/tests/generated/rust/packet_decl_array_dynamic_size_big_endian.rs
new file mode 100644
index 0000000..4c7bb72
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_dynamic_size_big_endian.rs
@@ -0,0 +1,99 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub padding: u8,
+    pub x: Vec<u32>,
+}
+impl Foo {
+    pub fn padding(&self) -> u8 {
+        self.padding
+    }
+    pub fn x(&self) -> &Vec<u32> {
+        &self.x
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        1 + self.x.len() * 3
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if (self.x.len() * 3) > 0x1f {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "x",
+                size: (self.x.len() * 3),
+                maximum_size: 0x1f,
+            });
+        }
+        if self.padding() > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "padding",
+                value: self.padding() as u64,
+                maximum_value: 0x7 as u64,
+            });
+        }
+        let value = (self.x.len() * 3) as u8 | (self.padding() << 5);
+        buf.put_u8(value);
+        for elem in &self.x {
+            buf.put_uint(*elem as u64, 3);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u8();
+        let x_size = (chunk & 0x1f) as usize;
+        let padding = ((chunk >> 5) & 0x7);
+        if buf.remaining() < x_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: x_size,
+                got: buf.remaining(),
+            });
+        }
+        if x_size % 3 != 0 {
+            return Err(DecodeError::InvalidArraySize {
+                array: x_size,
+                element: 3,
+            });
+        }
+        let x_count = x_size / 3;
+        let mut x = Vec::with_capacity(x_count);
+        for _ in 0..x_count {
+            x.push(Ok::<_, DecodeError>(buf.get_uint(3) as u32)?);
+        }
+        Ok((Self { padding, x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_dynamic_size_little_endian.rs b/tests/generated/rust/packet_decl_array_dynamic_size_little_endian.rs
new file mode 100644
index 0000000..4d226f8
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_dynamic_size_little_endian.rs
@@ -0,0 +1,99 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub padding: u8,
+    pub x: Vec<u32>,
+}
+impl Foo {
+    pub fn padding(&self) -> u8 {
+        self.padding
+    }
+    pub fn x(&self) -> &Vec<u32> {
+        &self.x
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        1 + self.x.len() * 3
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if (self.x.len() * 3) > 0x1f {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "x",
+                size: (self.x.len() * 3),
+                maximum_size: 0x1f,
+            });
+        }
+        if self.padding() > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "padding",
+                value: self.padding() as u64,
+                maximum_value: 0x7 as u64,
+            });
+        }
+        let value = (self.x.len() * 3) as u8 | (self.padding() << 5);
+        buf.put_u8(value);
+        for elem in &self.x {
+            buf.put_uint_le(*elem as u64, 3);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u8();
+        let x_size = (chunk & 0x1f) as usize;
+        let padding = ((chunk >> 5) & 0x7);
+        if buf.remaining() < x_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: x_size,
+                got: buf.remaining(),
+            });
+        }
+        if x_size % 3 != 0 {
+            return Err(DecodeError::InvalidArraySize {
+                array: x_size,
+                element: 3,
+            });
+        }
+        let x_count = x_size / 3;
+        let mut x = Vec::with_capacity(x_count);
+        for _ in 0..x_count {
+            x.push(Ok::<_, DecodeError>(buf.get_uint_le(3) as u32)?);
+        }
+        Ok((Self { padding, x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_unknown_element_width_dynamic_count_big_endian.rs b/tests/generated/rust/packet_decl_array_unknown_element_width_dynamic_count_big_endian.rs
new file mode 100644
index 0000000..d9d7733
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_unknown_element_width_dynamic_count_big_endian.rs
@@ -0,0 +1,120 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: Vec<u16>,
+}
+impl Foo {
+    pub fn a(&self) -> &Vec<u16> {
+        &self.a
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        5 + self.a.len() * 2
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.a.len() > 0xff_ffff_ffff_usize {
+            return Err(EncodeError::CountOverflow {
+                packet: "Foo",
+                field: "a",
+                count: self.a.len(),
+                maximum_count: 0xff_ffff_ffff_usize,
+            });
+        }
+        buf.put_uint(self.a.len() as u64, 5);
+        for elem in &self.a {
+            buf.put_u16(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 5,
+                got: buf.remaining(),
+            });
+        }
+        let a_count = buf.get_uint(5) as usize;
+        if buf.remaining() < a_count * 2usize {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: a_count * 2usize,
+                got: buf.remaining(),
+            });
+        }
+        let a = (0..a_count)
+            .map(|_| Ok::<_, DecodeError>(buf.get_u16()))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        Ok((Self { a }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: Vec<Foo>,
+}
+impl Bar {
+    pub fn x(&self) -> &Vec<Foo> {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        5 + self.x.iter().map(Packet::encoded_len).sum::<usize>()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.x.len() > 0xff_ffff_ffff_usize {
+            return Err(EncodeError::CountOverflow {
+                packet: "Bar",
+                field: "x",
+                count: self.x.len(),
+                maximum_count: 0xff_ffff_ffff_usize,
+            });
+        }
+        buf.put_uint(self.x.len() as u64, 5);
+        for elem in &self.x {
+            elem.encode(buf)?;
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 5,
+                got: buf.remaining(),
+            });
+        }
+        let x_count = buf.get_uint(5) as usize;
+        let x = (0..x_count)
+            .map(|_| Foo::decode_mut(&mut buf))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_unknown_element_width_dynamic_count_little_endian.rs b/tests/generated/rust/packet_decl_array_unknown_element_width_dynamic_count_little_endian.rs
new file mode 100644
index 0000000..eb249ac
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_unknown_element_width_dynamic_count_little_endian.rs
@@ -0,0 +1,120 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: Vec<u16>,
+}
+impl Foo {
+    pub fn a(&self) -> &Vec<u16> {
+        &self.a
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        5 + self.a.len() * 2
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.a.len() > 0xff_ffff_ffff_usize {
+            return Err(EncodeError::CountOverflow {
+                packet: "Foo",
+                field: "a",
+                count: self.a.len(),
+                maximum_count: 0xff_ffff_ffff_usize,
+            });
+        }
+        buf.put_uint_le(self.a.len() as u64, 5);
+        for elem in &self.a {
+            buf.put_u16_le(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 5,
+                got: buf.remaining(),
+            });
+        }
+        let a_count = buf.get_uint_le(5) as usize;
+        if buf.remaining() < a_count * 2usize {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: a_count * 2usize,
+                got: buf.remaining(),
+            });
+        }
+        let a = (0..a_count)
+            .map(|_| Ok::<_, DecodeError>(buf.get_u16_le()))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        Ok((Self { a }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: Vec<Foo>,
+}
+impl Bar {
+    pub fn x(&self) -> &Vec<Foo> {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        5 + self.x.iter().map(Packet::encoded_len).sum::<usize>()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.x.len() > 0xff_ffff_ffff_usize {
+            return Err(EncodeError::CountOverflow {
+                packet: "Bar",
+                field: "x",
+                count: self.x.len(),
+                maximum_count: 0xff_ffff_ffff_usize,
+            });
+        }
+        buf.put_uint_le(self.x.len() as u64, 5);
+        for elem in &self.x {
+            elem.encode(buf)?;
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 5,
+                got: buf.remaining(),
+            });
+        }
+        let x_count = buf.get_uint_le(5) as usize;
+        let x = (0..x_count)
+            .map(|_| Foo::decode_mut(&mut buf))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_unknown_element_width_dynamic_size_big_endian.rs b/tests/generated/rust/packet_decl_array_unknown_element_width_dynamic_size_big_endian.rs
new file mode 100644
index 0000000..ef1ead6
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_unknown_element_width_dynamic_size_big_endian.rs
@@ -0,0 +1,131 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: Vec<u16>,
+}
+impl Foo {
+    pub fn a(&self) -> &Vec<u16> {
+        &self.a
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        5 + self.a.len() * 2
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.a.len() > 0xff_ffff_ffff_usize {
+            return Err(EncodeError::CountOverflow {
+                packet: "Foo",
+                field: "a",
+                count: self.a.len(),
+                maximum_count: 0xff_ffff_ffff_usize,
+            });
+        }
+        buf.put_uint(self.a.len() as u64, 5);
+        for elem in &self.a {
+            buf.put_u16(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 5,
+                got: buf.remaining(),
+            });
+        }
+        let a_count = buf.get_uint(5) as usize;
+        if buf.remaining() < a_count * 2usize {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: a_count * 2usize,
+                got: buf.remaining(),
+            });
+        }
+        let a = (0..a_count)
+            .map(|_| Ok::<_, DecodeError>(buf.get_u16()))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        Ok((Self { a }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: Vec<Foo>,
+}
+impl Bar {
+    pub fn x(&self) -> &Vec<Foo> {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        5 + self.x.iter().map(Packet::encoded_len).sum::<usize>()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        let x_size = self.x.iter().map(Packet::encoded_len).sum::<usize>();
+        if x_size > 0xff_ffff_ffff_usize {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "x",
+                size: x_size,
+                maximum_size: 0xff_ffff_ffff_usize,
+            });
+        }
+        buf.put_uint(x_size as u64, 5);
+        for elem in &self.x {
+            elem.encode(buf)?;
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 5,
+                got: buf.remaining(),
+            });
+        }
+        let x_size = buf.get_uint(5) as usize;
+        if buf.remaining() < x_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: x_size,
+                got: buf.remaining(),
+            });
+        }
+        let (mut head, tail) = buf.split_at(x_size);
+        buf = tail;
+        let mut x = Vec::new();
+        while !head.is_empty() {
+            x.push(Foo::decode_mut(&mut head)?);
+        }
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_unknown_element_width_dynamic_size_little_endian.rs b/tests/generated/rust/packet_decl_array_unknown_element_width_dynamic_size_little_endian.rs
new file mode 100644
index 0000000..91381c5
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_unknown_element_width_dynamic_size_little_endian.rs
@@ -0,0 +1,131 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: Vec<u16>,
+}
+impl Foo {
+    pub fn a(&self) -> &Vec<u16> {
+        &self.a
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        5 + self.a.len() * 2
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.a.len() > 0xff_ffff_ffff_usize {
+            return Err(EncodeError::CountOverflow {
+                packet: "Foo",
+                field: "a",
+                count: self.a.len(),
+                maximum_count: 0xff_ffff_ffff_usize,
+            });
+        }
+        buf.put_uint_le(self.a.len() as u64, 5);
+        for elem in &self.a {
+            buf.put_u16_le(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 5,
+                got: buf.remaining(),
+            });
+        }
+        let a_count = buf.get_uint_le(5) as usize;
+        if buf.remaining() < a_count * 2usize {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: a_count * 2usize,
+                got: buf.remaining(),
+            });
+        }
+        let a = (0..a_count)
+            .map(|_| Ok::<_, DecodeError>(buf.get_u16_le()))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        Ok((Self { a }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: Vec<Foo>,
+}
+impl Bar {
+    pub fn x(&self) -> &Vec<Foo> {
+        &self.x
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        5 + self.x.iter().map(Packet::encoded_len).sum::<usize>()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        let x_size = self.x.iter().map(Packet::encoded_len).sum::<usize>();
+        if x_size > 0xff_ffff_ffff_usize {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "x",
+                size: x_size,
+                maximum_size: 0xff_ffff_ffff_usize,
+            });
+        }
+        buf.put_uint_le(x_size as u64, 5);
+        for elem in &self.x {
+            elem.encode(buf)?;
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 5,
+                got: buf.remaining(),
+            });
+        }
+        let x_size = buf.get_uint_le(5) as usize;
+        if buf.remaining() < x_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: x_size,
+                got: buf.remaining(),
+            });
+        }
+        let (mut head, tail) = buf.split_at(x_size);
+        buf = tail;
+        let mut x = Vec::new();
+        while !head.is_empty() {
+            x.push(Foo::decode_mut(&mut head)?);
+        }
+        Ok((Self { x }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_with_padding_big_endian.rs b/tests/generated/rust/packet_decl_array_with_padding_big_endian.rs
new file mode 100644
index 0000000..44d3643
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_with_padding_big_endian.rs
@@ -0,0 +1,123 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: Vec<u16>,
+}
+impl Foo {
+    pub fn a(&self) -> &Vec<u16> {
+        &self.a
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        5 + self.a.len() * 2
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.a.len() > 0xff_ffff_ffff_usize {
+            return Err(EncodeError::CountOverflow {
+                packet: "Foo",
+                field: "a",
+                count: self.a.len(),
+                maximum_count: 0xff_ffff_ffff_usize,
+            });
+        }
+        buf.put_uint(self.a.len() as u64, 5);
+        for elem in &self.a {
+            buf.put_u16(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 5,
+                got: buf.remaining(),
+            });
+        }
+        let a_count = buf.get_uint(5) as usize;
+        if buf.remaining() < a_count * 2usize {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: a_count * 2usize,
+                got: buf.remaining(),
+            });
+        }
+        let a = (0..a_count)
+            .map(|_| Ok::<_, DecodeError>(buf.get_u16()))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        Ok((Self { a }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub a: Vec<Foo>,
+}
+impl Bar {
+    pub fn a(&self) -> &Vec<Foo> {
+        &self.a
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        self.a.iter().map(Packet::encoded_len).sum::<usize>()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        let array_size = self.a.iter().map(Packet::encoded_len).sum::<usize>();
+        if array_size > 128usize {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "a",
+                size: array_size,
+                maximum_size: 128usize,
+            });
+        }
+        for elem in &self.a {
+            elem.encode(buf)?;
+        }
+        buf.put_bytes(0, 128usize - array_size);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 128usize {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 128usize,
+                got: buf.remaining(),
+            });
+        }
+        let (mut head, tail) = buf.split_at(128usize);
+        buf = tail;
+        let mut a = Vec::new();
+        while !head.is_empty() {
+            a.push(Foo::decode_mut(&mut head)?);
+        }
+        Ok((Self { a }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_array_with_padding_little_endian.rs b/tests/generated/rust/packet_decl_array_with_padding_little_endian.rs
new file mode 100644
index 0000000..9295e39
--- /dev/null
+++ b/tests/generated/rust/packet_decl_array_with_padding_little_endian.rs
@@ -0,0 +1,123 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: Vec<u16>,
+}
+impl Foo {
+    pub fn a(&self) -> &Vec<u16> {
+        &self.a
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        5 + self.a.len() * 2
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.a.len() > 0xff_ffff_ffff_usize {
+            return Err(EncodeError::CountOverflow {
+                packet: "Foo",
+                field: "a",
+                count: self.a.len(),
+                maximum_count: 0xff_ffff_ffff_usize,
+            });
+        }
+        buf.put_uint_le(self.a.len() as u64, 5);
+        for elem in &self.a {
+            buf.put_u16_le(*elem);
+        }
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 5,
+                got: buf.remaining(),
+            });
+        }
+        let a_count = buf.get_uint_le(5) as usize;
+        if buf.remaining() < a_count * 2usize {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: a_count * 2usize,
+                got: buf.remaining(),
+            });
+        }
+        let a = (0..a_count)
+            .map(|_| Ok::<_, DecodeError>(buf.get_u16_le()))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        Ok((Self { a }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub a: Vec<Foo>,
+}
+impl Bar {
+    pub fn a(&self) -> &Vec<Foo> {
+        &self.a
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        self.a.iter().map(Packet::encoded_len).sum::<usize>()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        let array_size = self.a.iter().map(Packet::encoded_len).sum::<usize>();
+        if array_size > 128usize {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "a",
+                size: array_size,
+                maximum_size: 128usize,
+            });
+        }
+        for elem in &self.a {
+            elem.encode(buf)?;
+        }
+        buf.put_bytes(0, 128usize - array_size);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 128usize {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 128usize,
+                got: buf.remaining(),
+            });
+        }
+        let (mut head, tail) = buf.split_at(128usize);
+        buf = tail;
+        let mut a = Vec::new();
+        while !head.is_empty() {
+            a.push(Foo::decode_mut(&mut head)?);
+        }
+        Ok((Self { a }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_child_packets_big_endian.rs b/tests/generated/rust/packet_decl_child_packets_big_endian.rs
new file mode 100644
index 0000000..f319ed6
--- /dev/null
+++ b/tests/generated/rust/packet_decl_child_packets_big_endian.rs
@@ -0,0 +1,372 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))]
+pub enum Enum16 {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u16> for Enum16 {
+    type Error = u16;
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Enum16::A),
+            0x2 => Ok(Enum16::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum16> for u16 {
+    fn from(value: &Enum16) -> Self {
+        match value {
+            Enum16::A => 0x1,
+            Enum16::B => 0x2,
+        }
+    }
+}
+impl From<Enum16> for u16 {
+    fn from(value: Enum16) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum16> for i32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for i64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u8,
+    pub b: Enum16,
+    pub payload: Vec<u8>,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum FooChild {
+    Bar(Bar),
+    Baz(Baz),
+    None,
+}
+impl Foo {
+    pub fn specialize(&self) -> Result<FooChild, DecodeError> {
+        Ok(
+            match (self.a, self.b) {
+                (100, _) => FooChild::Bar(self.try_into()?),
+                (_, Enum16::B) => FooChild::Baz(self.try_into()?),
+                _ => FooChild::None,
+            },
+        )
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> Enum16 {
+        self.b
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        4 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        buf.put_u16(u16::from(self.b()));
+        if self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(self.payload.len() as u8);
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let a = buf.get_u8();
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let b = Enum16::try_from(buf.get_u16())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Foo",
+                field: "b",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let payload_size = buf.get_u8() as usize;
+        if buf.remaining() < payload_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: payload_size,
+                got: buf.remaining(),
+            });
+        }
+        let payload = buf[..payload_size].to_vec();
+        buf.advance(payload_size);
+        Ok((Self { payload, a, b }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: u8,
+    pub b: Enum16,
+}
+impl TryFrom<&Foo> for Bar {
+    type Error = DecodeError;
+    fn try_from(parent: &Foo) -> Result<Bar, Self::Error> {
+        Bar::decode_partial(&parent)
+    }
+}
+impl TryFrom<Foo> for Bar {
+    type Error = DecodeError;
+    fn try_from(parent: Foo) -> Result<Bar, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&Bar> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: &Bar) -> Result<Foo, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Foo {
+            a: 100,
+            b: packet.b,
+            payload,
+        })
+    }
+}
+impl TryFrom<Bar> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Foo, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl Bar {
+    fn decode_partial(parent: &Foo) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.a() != 100 {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "Bar",
+                field: "a",
+                expected: "100",
+                actual: format!("{:?}", parent.a()),
+            });
+        }
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf.get_u8();
+        if buf.is_empty() {
+            Ok(Self { x, b: parent.b })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.x());
+        Ok(())
+    }
+    pub fn x(&self) -> u8 {
+        self.x
+    }
+    pub fn b(&self) -> Enum16 {
+        self.b
+    }
+    pub fn a(&self) -> u8 {
+        100
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        5
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        buf.put_u16(u16::from(self.b()));
+        if 1 > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: 1,
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(1 as u8);
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Foo::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Baz {
+    pub y: u16,
+    pub a: u8,
+}
+impl TryFrom<&Foo> for Baz {
+    type Error = DecodeError;
+    fn try_from(parent: &Foo) -> Result<Baz, Self::Error> {
+        Baz::decode_partial(&parent)
+    }
+}
+impl TryFrom<Foo> for Baz {
+    type Error = DecodeError;
+    fn try_from(parent: Foo) -> Result<Baz, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&Baz> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: &Baz) -> Result<Foo, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Foo {
+            a: packet.a,
+            b: Enum16::B,
+            payload,
+        })
+    }
+}
+impl TryFrom<Baz> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: Baz) -> Result<Foo, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl Baz {
+    fn decode_partial(parent: &Foo) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.b() != Enum16::B {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "Baz",
+                field: "b",
+                expected: "Enum16::B",
+                actual: format!("{:?}", parent.b()),
+            });
+        }
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Baz",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let y = buf.get_u16();
+        if buf.is_empty() {
+            Ok(Self { y, a: parent.a })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16(self.y());
+        Ok(())
+    }
+    pub fn y(&self) -> u16 {
+        self.y
+    }
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> Enum16 {
+        Enum16::B
+    }
+}
+impl Packet for Baz {
+    fn encoded_len(&self) -> usize {
+        6
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        buf.put_u16(u16::from(self.b()));
+        if 2 > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: 2,
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 as u8);
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Foo::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_child_packets_little_endian.rs b/tests/generated/rust/packet_decl_child_packets_little_endian.rs
new file mode 100644
index 0000000..047c42a
--- /dev/null
+++ b/tests/generated/rust/packet_decl_child_packets_little_endian.rs
@@ -0,0 +1,372 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))]
+pub enum Enum16 {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u16> for Enum16 {
+    type Error = u16;
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Enum16::A),
+            0x2 => Ok(Enum16::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum16> for u16 {
+    fn from(value: &Enum16) -> Self {
+        match value {
+            Enum16::A => 0x1,
+            Enum16::B => 0x2,
+        }
+    }
+}
+impl From<Enum16> for u16 {
+    fn from(value: Enum16) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum16> for i32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for i64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u8,
+    pub b: Enum16,
+    pub payload: Vec<u8>,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum FooChild {
+    Bar(Bar),
+    Baz(Baz),
+    None,
+}
+impl Foo {
+    pub fn specialize(&self) -> Result<FooChild, DecodeError> {
+        Ok(
+            match (self.a, self.b) {
+                (100, _) => FooChild::Bar(self.try_into()?),
+                (_, Enum16::B) => FooChild::Baz(self.try_into()?),
+                _ => FooChild::None,
+            },
+        )
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> Enum16 {
+        self.b
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        4 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        buf.put_u16_le(u16::from(self.b()));
+        if self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(self.payload.len() as u8);
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let a = buf.get_u8();
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let b = Enum16::try_from(buf.get_u16_le())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Foo",
+                field: "b",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let payload_size = buf.get_u8() as usize;
+        if buf.remaining() < payload_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: payload_size,
+                got: buf.remaining(),
+            });
+        }
+        let payload = buf[..payload_size].to_vec();
+        buf.advance(payload_size);
+        Ok((Self { payload, a, b }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: u8,
+    pub b: Enum16,
+}
+impl TryFrom<&Foo> for Bar {
+    type Error = DecodeError;
+    fn try_from(parent: &Foo) -> Result<Bar, Self::Error> {
+        Bar::decode_partial(&parent)
+    }
+}
+impl TryFrom<Foo> for Bar {
+    type Error = DecodeError;
+    fn try_from(parent: Foo) -> Result<Bar, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&Bar> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: &Bar) -> Result<Foo, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Foo {
+            a: 100,
+            b: packet.b,
+            payload,
+        })
+    }
+}
+impl TryFrom<Bar> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Foo, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl Bar {
+    fn decode_partial(parent: &Foo) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.a() != 100 {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "Bar",
+                field: "a",
+                expected: "100",
+                actual: format!("{:?}", parent.a()),
+            });
+        }
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf.get_u8();
+        if buf.is_empty() {
+            Ok(Self { x, b: parent.b })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.x());
+        Ok(())
+    }
+    pub fn x(&self) -> u8 {
+        self.x
+    }
+    pub fn b(&self) -> Enum16 {
+        self.b
+    }
+    pub fn a(&self) -> u8 {
+        100
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        5
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        buf.put_u16_le(u16::from(self.b()));
+        if 1 > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: 1,
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(1 as u8);
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Foo::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Baz {
+    pub y: u16,
+    pub a: u8,
+}
+impl TryFrom<&Foo> for Baz {
+    type Error = DecodeError;
+    fn try_from(parent: &Foo) -> Result<Baz, Self::Error> {
+        Baz::decode_partial(&parent)
+    }
+}
+impl TryFrom<Foo> for Baz {
+    type Error = DecodeError;
+    fn try_from(parent: Foo) -> Result<Baz, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&Baz> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: &Baz) -> Result<Foo, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Foo {
+            a: packet.a,
+            b: Enum16::B,
+            payload,
+        })
+    }
+}
+impl TryFrom<Baz> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: Baz) -> Result<Foo, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl Baz {
+    fn decode_partial(parent: &Foo) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.b() != Enum16::B {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "Baz",
+                field: "b",
+                expected: "Enum16::B",
+                actual: format!("{:?}", parent.b()),
+            });
+        }
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Baz",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let y = buf.get_u16_le();
+        if buf.is_empty() {
+            Ok(Self { y, a: parent.a })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16_le(self.y());
+        Ok(())
+    }
+    pub fn y(&self) -> u16 {
+        self.y
+    }
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> Enum16 {
+        Enum16::B
+    }
+}
+impl Packet for Baz {
+    fn encoded_len(&self) -> usize {
+        6
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        buf.put_u16_le(u16::from(self.b()));
+        if 2 > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: 2,
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 as u8);
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Foo::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_complex_scalars_big_endian.rs b/tests/generated/rust/packet_decl_complex_scalars_big_endian.rs
new file mode 100644
index 0000000..e2f6e8c
--- /dev/null
+++ b/tests/generated/rust/packet_decl_complex_scalars_big_endian.rs
@@ -0,0 +1,141 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u8,
+    pub b: u8,
+    pub c: u8,
+    pub d: u32,
+    pub e: u16,
+    pub f: u8,
+}
+impl Foo {
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> u8 {
+        self.b
+    }
+    pub fn c(&self) -> u8 {
+        self.c
+    }
+    pub fn d(&self) -> u32 {
+        self.d
+    }
+    pub fn e(&self) -> u16 {
+        self.e
+    }
+    pub fn f(&self) -> u8 {
+        self.f
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        7
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.a() > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a() as u64,
+                maximum_value: 0x7 as u64,
+            });
+        }
+        if self.c() > 0x1f {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "c",
+                value: self.c() as u64,
+                maximum_value: 0x1f as u64,
+            });
+        }
+        let value = (self.a() as u16) | ((self.b() as u16) << 3)
+            | ((self.c() as u16) << 11);
+        buf.put_u16(value);
+        if self.d() > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "d",
+                value: self.d() as u64,
+                maximum_value: 0xff_ffff as u64,
+            });
+        }
+        buf.put_uint(self.d() as u64, 3);
+        if self.e() > 0xfff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "e",
+                value: self.e() as u64,
+                maximum_value: 0xfff as u64,
+            });
+        }
+        if self.f() > 0xf {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "f",
+                value: self.f() as u64,
+                maximum_value: 0xf as u64,
+            });
+        }
+        let value = self.e() | ((self.f() as u16) << 12);
+        buf.put_u16(value);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u16();
+        let a = (chunk & 0x7) as u8;
+        let b = (chunk >> 3) as u8;
+        let c = ((chunk >> 11) & 0x1f) as u8;
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let d = buf.get_uint(3) as u32;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u16();
+        let e = (chunk & 0xfff);
+        let f = ((chunk >> 12) & 0xf) as u8;
+        Ok((Self { a, b, c, d, e, f }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_complex_scalars_little_endian.rs b/tests/generated/rust/packet_decl_complex_scalars_little_endian.rs
new file mode 100644
index 0000000..b18d238
--- /dev/null
+++ b/tests/generated/rust/packet_decl_complex_scalars_little_endian.rs
@@ -0,0 +1,141 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u8,
+    pub b: u8,
+    pub c: u8,
+    pub d: u32,
+    pub e: u16,
+    pub f: u8,
+}
+impl Foo {
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> u8 {
+        self.b
+    }
+    pub fn c(&self) -> u8 {
+        self.c
+    }
+    pub fn d(&self) -> u32 {
+        self.d
+    }
+    pub fn e(&self) -> u16 {
+        self.e
+    }
+    pub fn f(&self) -> u8 {
+        self.f
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        7
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.a() > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a() as u64,
+                maximum_value: 0x7 as u64,
+            });
+        }
+        if self.c() > 0x1f {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "c",
+                value: self.c() as u64,
+                maximum_value: 0x1f as u64,
+            });
+        }
+        let value = (self.a() as u16) | ((self.b() as u16) << 3)
+            | ((self.c() as u16) << 11);
+        buf.put_u16_le(value);
+        if self.d() > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "d",
+                value: self.d() as u64,
+                maximum_value: 0xff_ffff as u64,
+            });
+        }
+        buf.put_uint_le(self.d() as u64, 3);
+        if self.e() > 0xfff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "e",
+                value: self.e() as u64,
+                maximum_value: 0xfff as u64,
+            });
+        }
+        if self.f() > 0xf {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "f",
+                value: self.f() as u64,
+                maximum_value: 0xf as u64,
+            });
+        }
+        let value = self.e() | ((self.f() as u16) << 12);
+        buf.put_u16_le(value);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u16_le();
+        let a = (chunk & 0x7) as u8;
+        let b = (chunk >> 3) as u8;
+        let c = ((chunk >> 11) & 0x1f) as u8;
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let d = buf.get_uint_le(3) as u32;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u16_le();
+        let e = (chunk & 0xfff);
+        let f = ((chunk >> 12) & 0xf) as u8;
+        Ok((Self { a, b, c, d, e, f }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_custom_field_big_endian.rs b/tests/generated/rust/packet_decl_custom_field_big_endian.rs
new file mode 100644
index 0000000..fc9f02a
--- /dev/null
+++ b/tests/generated/rust/packet_decl_custom_field_big_endian.rs
@@ -0,0 +1,131 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u32", into = "u32"))]
+pub struct Bar1(u32);
+impl From<&Bar1> for u32 {
+    fn from(value: &Bar1) -> u32 {
+        value.0
+    }
+}
+impl From<Bar1> for u32 {
+    fn from(value: Bar1) -> u32 {
+        value.0
+    }
+}
+impl Packet for Bar1 {
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.len() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar1",
+                wanted: 3,
+                got: buf.len(),
+            });
+        }
+        Ok(((buf.get_uint(3) as u32).try_into().unwrap(), buf))
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_uint(u32::from(self) as u64, 3);
+        Ok(())
+    }
+    fn encoded_len(&self) -> usize {
+        3
+    }
+}
+impl TryFrom<u32> for Bar1 {
+    type Error = u32;
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
+        if value > 0xff_ffff { Err(value) } else { Ok(Bar1(value)) }
+    }
+}
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(from = "u32", into = "u32"))]
+pub struct Bar2(u32);
+impl From<&Bar2> for u32 {
+    fn from(value: &Bar2) -> u32 {
+        value.0
+    }
+}
+impl From<Bar2> for u32 {
+    fn from(value: Bar2) -> u32 {
+        value.0
+    }
+}
+impl Packet for Bar2 {
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.len() < 4 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar2",
+                wanted: 4,
+                got: buf.len(),
+            });
+        }
+        Ok((buf.get_u32().into(), buf))
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u32(u32::from(self));
+        Ok(())
+    }
+    fn encoded_len(&self) -> usize {
+        4
+    }
+}
+impl From<u32> for Bar2 {
+    fn from(value: u32) -> Self {
+        Bar2(value)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: Bar1,
+    pub b: Bar2,
+}
+impl Foo {
+    pub fn a(&self) -> Bar1 {
+        self.a
+    }
+    pub fn b(&self) -> Bar2 {
+        self.b
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        56
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_uint(u32::from(self.a) as u64, 3);
+        buf.put_u32(u32::from(self.b));
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let a = (buf.get_uint(3) as u32).try_into().unwrap();
+        let b = buf.get_u32().into();
+        Ok((Self { a, b }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_custom_field_little_endian.rs b/tests/generated/rust/packet_decl_custom_field_little_endian.rs
new file mode 100644
index 0000000..e48f67e
--- /dev/null
+++ b/tests/generated/rust/packet_decl_custom_field_little_endian.rs
@@ -0,0 +1,131 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u32", into = "u32"))]
+pub struct Bar1(u32);
+impl From<&Bar1> for u32 {
+    fn from(value: &Bar1) -> u32 {
+        value.0
+    }
+}
+impl From<Bar1> for u32 {
+    fn from(value: Bar1) -> u32 {
+        value.0
+    }
+}
+impl Packet for Bar1 {
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.len() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar1",
+                wanted: 3,
+                got: buf.len(),
+            });
+        }
+        Ok(((buf.get_uint_le(3) as u32).try_into().unwrap(), buf))
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_uint_le(u32::from(self) as u64, 3);
+        Ok(())
+    }
+    fn encoded_len(&self) -> usize {
+        3
+    }
+}
+impl TryFrom<u32> for Bar1 {
+    type Error = u32;
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
+        if value > 0xff_ffff { Err(value) } else { Ok(Bar1(value)) }
+    }
+}
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(from = "u32", into = "u32"))]
+pub struct Bar2(u32);
+impl From<&Bar2> for u32 {
+    fn from(value: &Bar2) -> u32 {
+        value.0
+    }
+}
+impl From<Bar2> for u32 {
+    fn from(value: Bar2) -> u32 {
+        value.0
+    }
+}
+impl Packet for Bar2 {
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.len() < 4 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar2",
+                wanted: 4,
+                got: buf.len(),
+            });
+        }
+        Ok((buf.get_u32_le().into(), buf))
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u32_le(u32::from(self));
+        Ok(())
+    }
+    fn encoded_len(&self) -> usize {
+        4
+    }
+}
+impl From<u32> for Bar2 {
+    fn from(value: u32) -> Self {
+        Bar2(value)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: Bar1,
+    pub b: Bar2,
+}
+impl Foo {
+    pub fn a(&self) -> Bar1 {
+        self.a
+    }
+    pub fn b(&self) -> Bar2 {
+        self.b
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        56
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_uint_le(u32::from(self.a) as u64, 3);
+        buf.put_u32_le(u32::from(self.b));
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let a = (buf.get_uint_le(3) as u32).try_into().unwrap();
+        let b = buf.get_u32_le().into();
+        Ok((Self { a, b }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_empty_big_endian.rs b/tests/generated/rust/packet_decl_empty_big_endian.rs
new file mode 100644
index 0000000..64c4adf
--- /dev/null
+++ b/tests/generated/rust/packet_decl_empty_big_endian.rs
@@ -0,0 +1,40 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {}
+impl Foo {}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        0
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        Ok((Self {}, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_empty_little_endian.rs b/tests/generated/rust/packet_decl_empty_little_endian.rs
new file mode 100644
index 0000000..64c4adf
--- /dev/null
+++ b/tests/generated/rust/packet_decl_empty_little_endian.rs
@@ -0,0 +1,40 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {}
+impl Foo {}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        0
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        Ok((Self {}, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_fixed_enum_field_big_endian.rs b/tests/generated/rust/packet_decl_fixed_enum_field_big_endian.rs
new file mode 100644
index 0000000..62b8e7f
--- /dev/null
+++ b/tests/generated/rust/packet_decl_fixed_enum_field_big_endian.rs
@@ -0,0 +1,138 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
+pub enum Enum7 {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u8> for Enum7 {
+    type Error = u8;
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Enum7::A),
+            0x2 => Ok(Enum7::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum7> for u8 {
+    fn from(value: &Enum7) -> Self {
+        match value {
+            Enum7::A => 0x1,
+            Enum7::B => 0x2,
+        }
+    }
+}
+impl From<Enum7> for u8 {
+    fn from(value: Enum7) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum7> for i8 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for i16 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for i32 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for i64 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for u16 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for u32 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for u64 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub b: u64,
+}
+impl Foo {
+    pub fn b(&self) -> u64 {
+        self.b
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        8
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.b() > 0x1ff_ffff_ffff_ffff_u64 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "b",
+                value: self.b() as u64,
+                maximum_value: 0x1ff_ffff_ffff_ffff_u64 as u64,
+            });
+        }
+        let value = (u8::from(Enum7::A) as u64) | (self.b() << 7);
+        buf.put_u64(value);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 8 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 8,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u64();
+        let fixed_value = (chunk & 0x7f) as u8;
+        if fixed_value != u8::from(Enum7::A) {
+            return Err(DecodeError::InvalidFixedValue {
+                expected: u8::from(Enum7::A) as u64,
+                actual: fixed_value as u64,
+            });
+        }
+        let b = ((chunk >> 7) & 0x1ff_ffff_ffff_ffff_u64);
+        Ok((Self { b }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_fixed_enum_field_little_endian.rs b/tests/generated/rust/packet_decl_fixed_enum_field_little_endian.rs
new file mode 100644
index 0000000..015edf7
--- /dev/null
+++ b/tests/generated/rust/packet_decl_fixed_enum_field_little_endian.rs
@@ -0,0 +1,138 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
+pub enum Enum7 {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u8> for Enum7 {
+    type Error = u8;
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Enum7::A),
+            0x2 => Ok(Enum7::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum7> for u8 {
+    fn from(value: &Enum7) -> Self {
+        match value {
+            Enum7::A => 0x1,
+            Enum7::B => 0x2,
+        }
+    }
+}
+impl From<Enum7> for u8 {
+    fn from(value: Enum7) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum7> for i8 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for i16 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for i32 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for i64 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for u16 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for u32 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for u64 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub b: u64,
+}
+impl Foo {
+    pub fn b(&self) -> u64 {
+        self.b
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        8
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.b() > 0x1ff_ffff_ffff_ffff_u64 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "b",
+                value: self.b() as u64,
+                maximum_value: 0x1ff_ffff_ffff_ffff_u64 as u64,
+            });
+        }
+        let value = (u8::from(Enum7::A) as u64) | (self.b() << 7);
+        buf.put_u64_le(value);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 8 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 8,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u64_le();
+        let fixed_value = (chunk & 0x7f) as u8;
+        if fixed_value != u8::from(Enum7::A) {
+            return Err(DecodeError::InvalidFixedValue {
+                expected: u8::from(Enum7::A) as u64,
+                actual: fixed_value as u64,
+            });
+        }
+        let b = ((chunk >> 7) & 0x1ff_ffff_ffff_ffff_u64);
+        Ok((Self { b }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_fixed_scalar_field_big_endian.rs b/tests/generated/rust/packet_decl_fixed_scalar_field_big_endian.rs
new file mode 100644
index 0000000..c63be93
--- /dev/null
+++ b/tests/generated/rust/packet_decl_fixed_scalar_field_big_endian.rs
@@ -0,0 +1,72 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub b: u64,
+}
+impl Foo {
+    pub fn b(&self) -> u64 {
+        self.b
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        8
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.b() > 0x1ff_ffff_ffff_ffff_u64 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "b",
+                value: self.b() as u64,
+                maximum_value: 0x1ff_ffff_ffff_ffff_u64 as u64,
+            });
+        }
+        let value = (7 as u64) | (self.b() << 7);
+        buf.put_u64(value);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 8 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 8,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u64();
+        let fixed_value = (chunk & 0x7f) as u8;
+        if fixed_value != 7 {
+            return Err(DecodeError::InvalidFixedValue {
+                expected: 7,
+                actual: fixed_value as u64,
+            });
+        }
+        let b = ((chunk >> 7) & 0x1ff_ffff_ffff_ffff_u64);
+        Ok((Self { b }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_fixed_scalar_field_little_endian.rs b/tests/generated/rust/packet_decl_fixed_scalar_field_little_endian.rs
new file mode 100644
index 0000000..a6c4366
--- /dev/null
+++ b/tests/generated/rust/packet_decl_fixed_scalar_field_little_endian.rs
@@ -0,0 +1,72 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub b: u64,
+}
+impl Foo {
+    pub fn b(&self) -> u64 {
+        self.b
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        8
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.b() > 0x1ff_ffff_ffff_ffff_u64 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "b",
+                value: self.b() as u64,
+                maximum_value: 0x1ff_ffff_ffff_ffff_u64 as u64,
+            });
+        }
+        let value = (7 as u64) | (self.b() << 7);
+        buf.put_u64_le(value);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 8 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 8,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u64_le();
+        let fixed_value = (chunk & 0x7f) as u8;
+        if fixed_value != 7 {
+            return Err(DecodeError::InvalidFixedValue {
+                expected: 7,
+                actual: fixed_value as u64,
+            });
+        }
+        let b = ((chunk >> 7) & 0x1ff_ffff_ffff_ffff_u64);
+        Ok((Self { b }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_grand_children_big_endian.rs b/tests/generated/rust/packet_decl_grand_children_big_endian.rs
new file mode 100644
index 0000000..ceab016
--- /dev/null
+++ b/tests/generated/rust/packet_decl_grand_children_big_endian.rs
@@ -0,0 +1,594 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))]
+pub enum Enum16 {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u16> for Enum16 {
+    type Error = u16;
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Enum16::A),
+            0x2 => Ok(Enum16::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum16> for u16 {
+    fn from(value: &Enum16) -> Self {
+        match value {
+            Enum16::A => 0x1,
+            Enum16::B => 0x2,
+        }
+    }
+}
+impl From<Enum16> for u16 {
+    fn from(value: Enum16) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum16> for i32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for i64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Parent {
+    pub foo: Enum16,
+    pub bar: Enum16,
+    pub baz: Enum16,
+    pub payload: Vec<u8>,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum ParentChild {
+    Child(Child),
+    None,
+}
+impl Parent {
+    pub fn specialize(&self) -> Result<ParentChild, DecodeError> {
+        Ok(
+            match (self.foo,) {
+                (Enum16::A,) => ParentChild::Child(self.try_into()?),
+                _ => ParentChild::None,
+            },
+        )
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn foo(&self) -> Enum16 {
+        self.foo
+    }
+    pub fn bar(&self) -> Enum16 {
+        self.bar
+    }
+    pub fn baz(&self) -> Enum16 {
+        self.baz
+    }
+}
+impl Packet for Parent {
+    fn encoded_len(&self) -> usize {
+        7 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16(u16::from(self.foo()));
+        buf.put_u16(u16::from(self.bar()));
+        buf.put_u16(u16::from(self.baz()));
+        if self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(self.payload.len() as u8);
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let foo = Enum16::try_from(buf.get_u16())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "foo",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let bar = Enum16::try_from(buf.get_u16())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "bar",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let baz = Enum16::try_from(buf.get_u16())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "baz",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let payload_size = buf.get_u8() as usize;
+        if buf.remaining() < payload_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: payload_size,
+                got: buf.remaining(),
+            });
+        }
+        let payload = buf[..payload_size].to_vec();
+        buf.advance(payload_size);
+        Ok((Self { payload, foo, bar, baz }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Child {
+    pub quux: Enum16,
+    pub bar: Enum16,
+    pub baz: Enum16,
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&Parent> for Child {
+    type Error = DecodeError;
+    fn try_from(parent: &Parent) -> Result<Child, Self::Error> {
+        Child::decode_partial(&parent)
+    }
+}
+impl TryFrom<Parent> for Child {
+    type Error = DecodeError;
+    fn try_from(parent: Parent) -> Result<Child, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&Child> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &Child) -> Result<Parent, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Parent {
+            foo: Enum16::A,
+            bar: packet.bar,
+            baz: packet.baz,
+            payload,
+        })
+    }
+}
+impl TryFrom<Child> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: Child) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum ChildChild {
+    GrandChild(GrandChild),
+    None,
+}
+impl Child {
+    pub fn specialize(&self) -> Result<ChildChild, DecodeError> {
+        Ok(
+            match (self.bar, self.quux) {
+                (Enum16::A, Enum16::A) => ChildChild::GrandChild(self.try_into()?),
+                _ => ChildChild::None,
+            },
+        )
+    }
+    fn decode_partial(parent: &Parent) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.foo() != Enum16::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "Child",
+                field: "foo",
+                expected: "Enum16::A",
+                actual: format!("{:?}", parent.foo()),
+            });
+        }
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Child",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let quux = Enum16::try_from(buf.get_u16())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Child",
+                field: "quux",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        if buf.is_empty() {
+            Ok(Self {
+                payload,
+                quux,
+                bar: parent.bar,
+                baz: parent.baz,
+            })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16(u16::from(self.quux()));
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn quux(&self) -> Enum16 {
+        self.quux
+    }
+    pub fn bar(&self) -> Enum16 {
+        self.bar
+    }
+    pub fn baz(&self) -> Enum16 {
+        self.baz
+    }
+    pub fn foo(&self) -> Enum16 {
+        Enum16::A
+    }
+}
+impl Packet for Child {
+    fn encoded_len(&self) -> usize {
+        9 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16(u16::from(self.foo()));
+        buf.put_u16(u16::from(self.bar()));
+        buf.put_u16(u16::from(self.baz()));
+        if 2 + self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: 2 + self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 + self.payload.len() as u8);
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Parent::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct GrandChild {
+    pub baz: Enum16,
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&Child> for GrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: &Child) -> Result<GrandChild, Self::Error> {
+        GrandChild::decode_partial(&parent)
+    }
+}
+impl TryFrom<Child> for GrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: Child) -> Result<GrandChild, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&GrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandChild) -> Result<Child, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Child {
+            quux: Enum16::A,
+            bar: Enum16::A,
+            baz: packet.baz,
+            payload,
+        })
+    }
+}
+impl TryFrom<GrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: GrandChild) -> Result<Child, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl TryFrom<&GrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandChild) -> Result<Parent, Self::Error> {
+        (&Child::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<GrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: GrandChild) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum GrandChildChild {
+    GrandGrandChild(GrandGrandChild),
+    None,
+}
+impl GrandChild {
+    pub fn specialize(&self) -> Result<GrandChildChild, DecodeError> {
+        Ok(
+            match (self.baz,) {
+                (Enum16::A,) => GrandChildChild::GrandGrandChild(self.try_into()?),
+                _ => GrandChildChild::None,
+            },
+        )
+    }
+    fn decode_partial(parent: &Child) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.bar() != Enum16::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "GrandChild",
+                field: "bar",
+                expected: "Enum16::A",
+                actual: format!("{:?}", parent.bar()),
+            });
+        }
+        if parent.quux() != Enum16::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "GrandChild",
+                field: "quux",
+                expected: "Enum16::A",
+                actual: format!("{:?}", parent.quux()),
+            });
+        }
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        if buf.is_empty() {
+            Ok(Self { payload, baz: parent.baz })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn baz(&self) -> Enum16 {
+        self.baz
+    }
+    pub fn quux(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn foo(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn bar(&self) -> Enum16 {
+        Enum16::A
+    }
+}
+impl Packet for GrandChild {
+    fn encoded_len(&self) -> usize {
+        9 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16(u16::from(self.foo()));
+        buf.put_u16(u16::from(self.bar()));
+        buf.put_u16(u16::from(self.baz()));
+        if 2 + self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: 2 + self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 + self.payload.len() as u8);
+        buf.put_u16(u16::from(self.quux()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Child::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct GrandGrandChild {
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&GrandChild> for GrandGrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: &GrandChild) -> Result<GrandGrandChild, Self::Error> {
+        GrandGrandChild::decode_partial(&parent)
+    }
+}
+impl TryFrom<GrandChild> for GrandGrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: GrandChild) -> Result<GrandGrandChild, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&GrandGrandChild> for GrandChild {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<GrandChild, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(GrandChild {
+            baz: Enum16::A,
+            payload,
+        })
+    }
+}
+impl TryFrom<GrandGrandChild> for GrandChild {
+    type Error = EncodeError;
+    fn try_from(packet: GrandGrandChild) -> Result<GrandChild, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl TryFrom<&GrandGrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<Child, Self::Error> {
+        (&GrandChild::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<GrandGrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: GrandGrandChild) -> Result<Child, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl TryFrom<&GrandGrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<Parent, Self::Error> {
+        (&GrandChild::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<GrandGrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: GrandGrandChild) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl GrandGrandChild {
+    fn decode_partial(parent: &GrandChild) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.baz() != Enum16::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "GrandGrandChild",
+                field: "baz",
+                expected: "Enum16::A",
+                actual: format!("{:?}", parent.baz()),
+            });
+        }
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        if buf.is_empty() {
+            Ok(Self { payload })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn quux(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn foo(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn bar(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn baz(&self) -> Enum16 {
+        Enum16::A
+    }
+}
+impl Packet for GrandGrandChild {
+    fn encoded_len(&self) -> usize {
+        9 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16(u16::from(self.foo()));
+        buf.put_u16(u16::from(self.bar()));
+        buf.put_u16(u16::from(self.baz()));
+        if 2 + self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: 2 + self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 + self.payload.len() as u8);
+        buf.put_u16(u16::from(self.quux()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = GrandChild::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_grand_children_little_endian.rs b/tests/generated/rust/packet_decl_grand_children_little_endian.rs
new file mode 100644
index 0000000..48ddd7b
--- /dev/null
+++ b/tests/generated/rust/packet_decl_grand_children_little_endian.rs
@@ -0,0 +1,594 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))]
+pub enum Enum16 {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u16> for Enum16 {
+    type Error = u16;
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Enum16::A),
+            0x2 => Ok(Enum16::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum16> for u16 {
+    fn from(value: &Enum16) -> Self {
+        match value {
+            Enum16::A => 0x1,
+            Enum16::B => 0x2,
+        }
+    }
+}
+impl From<Enum16> for u16 {
+    fn from(value: Enum16) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum16> for i32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for i64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Parent {
+    pub foo: Enum16,
+    pub bar: Enum16,
+    pub baz: Enum16,
+    pub payload: Vec<u8>,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum ParentChild {
+    Child(Child),
+    None,
+}
+impl Parent {
+    pub fn specialize(&self) -> Result<ParentChild, DecodeError> {
+        Ok(
+            match (self.foo,) {
+                (Enum16::A,) => ParentChild::Child(self.try_into()?),
+                _ => ParentChild::None,
+            },
+        )
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn foo(&self) -> Enum16 {
+        self.foo
+    }
+    pub fn bar(&self) -> Enum16 {
+        self.bar
+    }
+    pub fn baz(&self) -> Enum16 {
+        self.baz
+    }
+}
+impl Packet for Parent {
+    fn encoded_len(&self) -> usize {
+        7 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16_le(u16::from(self.foo()));
+        buf.put_u16_le(u16::from(self.bar()));
+        buf.put_u16_le(u16::from(self.baz()));
+        if self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(self.payload.len() as u8);
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let foo = Enum16::try_from(buf.get_u16_le())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "foo",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let bar = Enum16::try_from(buf.get_u16_le())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "bar",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let baz = Enum16::try_from(buf.get_u16_le())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "baz",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let payload_size = buf.get_u8() as usize;
+        if buf.remaining() < payload_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: payload_size,
+                got: buf.remaining(),
+            });
+        }
+        let payload = buf[..payload_size].to_vec();
+        buf.advance(payload_size);
+        Ok((Self { payload, foo, bar, baz }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Child {
+    pub quux: Enum16,
+    pub bar: Enum16,
+    pub baz: Enum16,
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&Parent> for Child {
+    type Error = DecodeError;
+    fn try_from(parent: &Parent) -> Result<Child, Self::Error> {
+        Child::decode_partial(&parent)
+    }
+}
+impl TryFrom<Parent> for Child {
+    type Error = DecodeError;
+    fn try_from(parent: Parent) -> Result<Child, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&Child> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &Child) -> Result<Parent, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Parent {
+            foo: Enum16::A,
+            bar: packet.bar,
+            baz: packet.baz,
+            payload,
+        })
+    }
+}
+impl TryFrom<Child> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: Child) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum ChildChild {
+    GrandChild(GrandChild),
+    None,
+}
+impl Child {
+    pub fn specialize(&self) -> Result<ChildChild, DecodeError> {
+        Ok(
+            match (self.bar, self.quux) {
+                (Enum16::A, Enum16::A) => ChildChild::GrandChild(self.try_into()?),
+                _ => ChildChild::None,
+            },
+        )
+    }
+    fn decode_partial(parent: &Parent) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.foo() != Enum16::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "Child",
+                field: "foo",
+                expected: "Enum16::A",
+                actual: format!("{:?}", parent.foo()),
+            });
+        }
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Child",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let quux = Enum16::try_from(buf.get_u16_le())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Child",
+                field: "quux",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        if buf.is_empty() {
+            Ok(Self {
+                payload,
+                quux,
+                bar: parent.bar,
+                baz: parent.baz,
+            })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16_le(u16::from(self.quux()));
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn quux(&self) -> Enum16 {
+        self.quux
+    }
+    pub fn bar(&self) -> Enum16 {
+        self.bar
+    }
+    pub fn baz(&self) -> Enum16 {
+        self.baz
+    }
+    pub fn foo(&self) -> Enum16 {
+        Enum16::A
+    }
+}
+impl Packet for Child {
+    fn encoded_len(&self) -> usize {
+        9 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16_le(u16::from(self.foo()));
+        buf.put_u16_le(u16::from(self.bar()));
+        buf.put_u16_le(u16::from(self.baz()));
+        if 2 + self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: 2 + self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 + self.payload.len() as u8);
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Parent::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct GrandChild {
+    pub baz: Enum16,
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&Child> for GrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: &Child) -> Result<GrandChild, Self::Error> {
+        GrandChild::decode_partial(&parent)
+    }
+}
+impl TryFrom<Child> for GrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: Child) -> Result<GrandChild, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&GrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandChild) -> Result<Child, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Child {
+            quux: Enum16::A,
+            bar: Enum16::A,
+            baz: packet.baz,
+            payload,
+        })
+    }
+}
+impl TryFrom<GrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: GrandChild) -> Result<Child, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl TryFrom<&GrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandChild) -> Result<Parent, Self::Error> {
+        (&Child::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<GrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: GrandChild) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum GrandChildChild {
+    GrandGrandChild(GrandGrandChild),
+    None,
+}
+impl GrandChild {
+    pub fn specialize(&self) -> Result<GrandChildChild, DecodeError> {
+        Ok(
+            match (self.baz,) {
+                (Enum16::A,) => GrandChildChild::GrandGrandChild(self.try_into()?),
+                _ => GrandChildChild::None,
+            },
+        )
+    }
+    fn decode_partial(parent: &Child) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.bar() != Enum16::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "GrandChild",
+                field: "bar",
+                expected: "Enum16::A",
+                actual: format!("{:?}", parent.bar()),
+            });
+        }
+        if parent.quux() != Enum16::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "GrandChild",
+                field: "quux",
+                expected: "Enum16::A",
+                actual: format!("{:?}", parent.quux()),
+            });
+        }
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        if buf.is_empty() {
+            Ok(Self { payload, baz: parent.baz })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn baz(&self) -> Enum16 {
+        self.baz
+    }
+    pub fn quux(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn foo(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn bar(&self) -> Enum16 {
+        Enum16::A
+    }
+}
+impl Packet for GrandChild {
+    fn encoded_len(&self) -> usize {
+        9 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16_le(u16::from(self.foo()));
+        buf.put_u16_le(u16::from(self.bar()));
+        buf.put_u16_le(u16::from(self.baz()));
+        if 2 + self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: 2 + self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 + self.payload.len() as u8);
+        buf.put_u16_le(u16::from(self.quux()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Child::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct GrandGrandChild {
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&GrandChild> for GrandGrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: &GrandChild) -> Result<GrandGrandChild, Self::Error> {
+        GrandGrandChild::decode_partial(&parent)
+    }
+}
+impl TryFrom<GrandChild> for GrandGrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: GrandChild) -> Result<GrandGrandChild, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&GrandGrandChild> for GrandChild {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<GrandChild, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(GrandChild {
+            baz: Enum16::A,
+            payload,
+        })
+    }
+}
+impl TryFrom<GrandGrandChild> for GrandChild {
+    type Error = EncodeError;
+    fn try_from(packet: GrandGrandChild) -> Result<GrandChild, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl TryFrom<&GrandGrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<Child, Self::Error> {
+        (&GrandChild::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<GrandGrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: GrandGrandChild) -> Result<Child, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl TryFrom<&GrandGrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<Parent, Self::Error> {
+        (&GrandChild::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<GrandGrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: GrandGrandChild) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl GrandGrandChild {
+    fn decode_partial(parent: &GrandChild) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.baz() != Enum16::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "GrandGrandChild",
+                field: "baz",
+                expected: "Enum16::A",
+                actual: format!("{:?}", parent.baz()),
+            });
+        }
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        if buf.is_empty() {
+            Ok(Self { payload })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn quux(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn foo(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn bar(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn baz(&self) -> Enum16 {
+        Enum16::A
+    }
+}
+impl Packet for GrandGrandChild {
+    fn encoded_len(&self) -> usize {
+        9 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16_le(u16::from(self.foo()));
+        buf.put_u16_le(u16::from(self.bar()));
+        buf.put_u16_le(u16::from(self.baz()));
+        if 2 + self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: 2 + self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 + self.payload.len() as u8);
+        buf.put_u16_le(u16::from(self.quux()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = GrandChild::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_mask_scalar_value_big_endian.rs b/tests/generated/rust/packet_decl_mask_scalar_value_big_endian.rs
new file mode 100644
index 0000000..9ed566f
--- /dev/null
+++ b/tests/generated/rust/packet_decl_mask_scalar_value_big_endian.rs
@@ -0,0 +1,91 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u8,
+    pub b: u32,
+    pub c: u8,
+}
+impl Foo {
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> u32 {
+        self.b
+    }
+    pub fn c(&self) -> u8 {
+        self.c
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        4
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.a() > 0x3 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a() as u64,
+                maximum_value: 0x3 as u64,
+            });
+        }
+        if self.b() > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "b",
+                value: self.b() as u64,
+                maximum_value: 0xff_ffff as u64,
+            });
+        }
+        if self.c() > 0x3f {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "c",
+                value: self.c() as u64,
+                maximum_value: 0x3f as u64,
+            });
+        }
+        let value = (self.a() as u32) | (self.b() << 2) | ((self.c() as u32) << 26);
+        buf.put_u32(value);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 4 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 4,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u32();
+        let a = (chunk & 0x3) as u8;
+        let b = ((chunk >> 2) & 0xff_ffff);
+        let c = ((chunk >> 26) & 0x3f) as u8;
+        Ok((Self { a, b, c }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_mask_scalar_value_little_endian.rs b/tests/generated/rust/packet_decl_mask_scalar_value_little_endian.rs
new file mode 100644
index 0000000..da4bb64
--- /dev/null
+++ b/tests/generated/rust/packet_decl_mask_scalar_value_little_endian.rs
@@ -0,0 +1,91 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u8,
+    pub b: u32,
+    pub c: u8,
+}
+impl Foo {
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> u32 {
+        self.b
+    }
+    pub fn c(&self) -> u8 {
+        self.c
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        4
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.a() > 0x3 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a() as u64,
+                maximum_value: 0x3 as u64,
+            });
+        }
+        if self.b() > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "b",
+                value: self.b() as u64,
+                maximum_value: 0xff_ffff as u64,
+            });
+        }
+        if self.c() > 0x3f {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "c",
+                value: self.c() as u64,
+                maximum_value: 0x3f as u64,
+            });
+        }
+        let value = (self.a() as u32) | (self.b() << 2) | ((self.c() as u32) << 26);
+        buf.put_u32_le(value);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 4 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 4,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u32_le();
+        let a = (chunk & 0x3) as u8;
+        let b = ((chunk >> 2) & 0xff_ffff);
+        let c = ((chunk >> 26) & 0x3f) as u8;
+        Ok((Self { a, b, c }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_mixed_scalars_enums_big_endian.rs b/tests/generated/rust/packet_decl_mixed_scalars_enums_big_endian.rs
new file mode 100644
index 0000000..a974b70
--- /dev/null
+++ b/tests/generated/rust/packet_decl_mixed_scalars_enums_big_endian.rs
@@ -0,0 +1,223 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
+pub enum Enum7 {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u8> for Enum7 {
+    type Error = u8;
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Enum7::A),
+            0x2 => Ok(Enum7::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum7> for u8 {
+    fn from(value: &Enum7) -> Self {
+        match value {
+            Enum7::A => 0x1,
+            Enum7::B => 0x2,
+        }
+    }
+}
+impl From<Enum7> for u8 {
+    fn from(value: Enum7) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum7> for i8 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for i16 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for i32 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for i64 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for u16 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for u32 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for u64 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))]
+pub enum Enum9 {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u16> for Enum9 {
+    type Error = u16;
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Enum9::A),
+            0x2 => Ok(Enum9::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum9> for u16 {
+    fn from(value: &Enum9) -> Self {
+        match value {
+            Enum9::A => 0x1,
+            Enum9::B => 0x2,
+        }
+    }
+}
+impl From<Enum9> for u16 {
+    fn from(value: Enum9) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum9> for i16 {
+    fn from(value: Enum9) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum9> for i32 {
+    fn from(value: Enum9) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum9> for i64 {
+    fn from(value: Enum9) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum9> for u32 {
+    fn from(value: Enum9) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum9> for u64 {
+    fn from(value: Enum9) -> Self {
+        u16::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub x: Enum7,
+    pub y: u8,
+    pub z: Enum9,
+    pub w: u8,
+}
+impl Foo {
+    pub fn x(&self) -> Enum7 {
+        self.x
+    }
+    pub fn y(&self) -> u8 {
+        self.y
+    }
+    pub fn z(&self) -> Enum9 {
+        self.z
+    }
+    pub fn w(&self) -> u8 {
+        self.w
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        3
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.y() > 0x1f {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "y",
+                value: self.y() as u64,
+                maximum_value: 0x1f as u64,
+            });
+        }
+        if self.w() > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "w",
+                value: self.w() as u64,
+                maximum_value: 0x7 as u64,
+            });
+        }
+        let value = (u8::from(self.x()) as u32) | ((self.y() as u32) << 7)
+            | ((u16::from(self.z()) as u32) << 12) | ((self.w() as u32) << 21);
+        buf.put_uint(value as u64, 3);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_uint(3) as u32;
+        let x = Enum7::try_from((chunk & 0x7f) as u8)
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Foo",
+                field: "x",
+                value: unknown_val as u64,
+                type_: "Enum7",
+            })?;
+        let y = ((chunk >> 7) & 0x1f) as u8;
+        let z = Enum9::try_from(((chunk >> 12) & 0x1ff) as u16)
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Foo",
+                field: "z",
+                value: unknown_val as u64,
+                type_: "Enum9",
+            })?;
+        let w = ((chunk >> 21) & 0x7) as u8;
+        Ok((Self { x, y, z, w }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_mixed_scalars_enums_little_endian.rs b/tests/generated/rust/packet_decl_mixed_scalars_enums_little_endian.rs
new file mode 100644
index 0000000..77ed48e
--- /dev/null
+++ b/tests/generated/rust/packet_decl_mixed_scalars_enums_little_endian.rs
@@ -0,0 +1,223 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
+pub enum Enum7 {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u8> for Enum7 {
+    type Error = u8;
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Enum7::A),
+            0x2 => Ok(Enum7::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum7> for u8 {
+    fn from(value: &Enum7) -> Self {
+        match value {
+            Enum7::A => 0x1,
+            Enum7::B => 0x2,
+        }
+    }
+}
+impl From<Enum7> for u8 {
+    fn from(value: Enum7) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum7> for i8 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for i16 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for i32 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for i64 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for u16 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for u32 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum7> for u64 {
+    fn from(value: Enum7) -> Self {
+        u8::from(value) as Self
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))]
+pub enum Enum9 {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u16> for Enum9 {
+    type Error = u16;
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Enum9::A),
+            0x2 => Ok(Enum9::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum9> for u16 {
+    fn from(value: &Enum9) -> Self {
+        match value {
+            Enum9::A => 0x1,
+            Enum9::B => 0x2,
+        }
+    }
+}
+impl From<Enum9> for u16 {
+    fn from(value: Enum9) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum9> for i16 {
+    fn from(value: Enum9) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum9> for i32 {
+    fn from(value: Enum9) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum9> for i64 {
+    fn from(value: Enum9) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum9> for u32 {
+    fn from(value: Enum9) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum9> for u64 {
+    fn from(value: Enum9) -> Self {
+        u16::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub x: Enum7,
+    pub y: u8,
+    pub z: Enum9,
+    pub w: u8,
+}
+impl Foo {
+    pub fn x(&self) -> Enum7 {
+        self.x
+    }
+    pub fn y(&self) -> u8 {
+        self.y
+    }
+    pub fn z(&self) -> Enum9 {
+        self.z
+    }
+    pub fn w(&self) -> u8 {
+        self.w
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        3
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.y() > 0x1f {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "y",
+                value: self.y() as u64,
+                maximum_value: 0x1f as u64,
+            });
+        }
+        if self.w() > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "w",
+                value: self.w() as u64,
+                maximum_value: 0x7 as u64,
+            });
+        }
+        let value = (u8::from(self.x()) as u32) | ((self.y() as u32) << 7)
+            | ((u16::from(self.z()) as u32) << 12) | ((self.w() as u32) << 21);
+        buf.put_uint_le(value as u64, 3);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_uint_le(3) as u32;
+        let x = Enum7::try_from((chunk & 0x7f) as u8)
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Foo",
+                field: "x",
+                value: unknown_val as u64,
+                type_: "Enum7",
+            })?;
+        let y = ((chunk >> 7) & 0x1f) as u8;
+        let z = Enum9::try_from(((chunk >> 12) & 0x1ff) as u16)
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Foo",
+                field: "z",
+                value: unknown_val as u64,
+                type_: "Enum9",
+            })?;
+        let w = ((chunk >> 21) & 0x7) as u8;
+        Ok((Self { x, y, z, w }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_parent_with_alias_child_big_endian.rs b/tests/generated/rust/packet_decl_parent_with_alias_child_big_endian.rs
new file mode 100644
index 0000000..35df1a2
--- /dev/null
+++ b/tests/generated/rust/packet_decl_parent_with_alias_child_big_endian.rs
@@ -0,0 +1,461 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
+pub enum Enum8 {
+    A = 0x0,
+    B = 0x1,
+    C = 0x2,
+}
+impl TryFrom<u8> for Enum8 {
+    type Error = u8;
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
+        match value {
+            0x0 => Ok(Enum8::A),
+            0x1 => Ok(Enum8::B),
+            0x2 => Ok(Enum8::C),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum8> for u8 {
+    fn from(value: &Enum8) -> Self {
+        match value {
+            Enum8::A => 0x0,
+            Enum8::B => 0x1,
+            Enum8::C => 0x2,
+        }
+    }
+}
+impl From<Enum8> for u8 {
+    fn from(value: Enum8) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum8> for i16 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for i32 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for i64 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for u16 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for u32 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for u64 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Parent {
+    pub v: Enum8,
+    pub payload: Vec<u8>,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum ParentChild {
+    AliasChild(AliasChild),
+    NormalChild(NormalChild),
+    None,
+}
+impl Parent {
+    pub fn specialize(&self) -> Result<ParentChild, DecodeError> {
+        Ok(
+            match (self.v,) {
+                (_,) => ParentChild::AliasChild(self.try_into()?),
+                (Enum8::A,) => ParentChild::NormalChild(self.try_into()?),
+                _ => ParentChild::None,
+            },
+        )
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn v(&self) -> Enum8 {
+        self.v
+    }
+}
+impl Packet for Parent {
+    fn encoded_len(&self) -> usize {
+        1 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(u8::from(self.v()));
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let v = Enum8::try_from(buf.get_u8())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "v",
+                value: unknown_val as u64,
+                type_: "Enum8",
+            })?;
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        Ok((Self { payload, v }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct AliasChild {
+    pub v: Enum8,
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&Parent> for AliasChild {
+    type Error = DecodeError;
+    fn try_from(parent: &Parent) -> Result<AliasChild, Self::Error> {
+        AliasChild::decode_partial(&parent)
+    }
+}
+impl TryFrom<Parent> for AliasChild {
+    type Error = DecodeError;
+    fn try_from(parent: Parent) -> Result<AliasChild, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&AliasChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &AliasChild) -> Result<Parent, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Parent { v: packet.v, payload })
+    }
+}
+impl TryFrom<AliasChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: AliasChild) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum AliasChildChild {
+    NormalGrandChild1(NormalGrandChild1),
+    NormalGrandChild2(NormalGrandChild2),
+    None,
+}
+impl AliasChild {
+    pub fn specialize(&self) -> Result<AliasChildChild, DecodeError> {
+        Ok(
+            match (self.v,) {
+                (Enum8::B,) => AliasChildChild::NormalGrandChild1(self.try_into()?),
+                (Enum8::C,) => AliasChildChild::NormalGrandChild2(self.try_into()?),
+                _ => AliasChildChild::None,
+            },
+        )
+    }
+    fn decode_partial(parent: &Parent) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        if buf.is_empty() {
+            Ok(Self { payload, v: parent.v })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn v(&self) -> Enum8 {
+        self.v
+    }
+}
+impl Packet for AliasChild {
+    fn encoded_len(&self) -> usize {
+        1 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(u8::from(self.v()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Parent::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct NormalChild {}
+impl TryFrom<&Parent> for NormalChild {
+    type Error = DecodeError;
+    fn try_from(parent: &Parent) -> Result<NormalChild, Self::Error> {
+        NormalChild::decode_partial(&parent)
+    }
+}
+impl TryFrom<Parent> for NormalChild {
+    type Error = DecodeError;
+    fn try_from(parent: Parent) -> Result<NormalChild, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&NormalChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &NormalChild) -> Result<Parent, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Parent { v: Enum8::A, payload })
+    }
+}
+impl TryFrom<NormalChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: NormalChild) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl NormalChild {
+    fn decode_partial(parent: &Parent) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.v() != Enum8::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "NormalChild",
+                field: "v",
+                expected: "Enum8::A",
+                actual: format!("{:?}", parent.v()),
+            });
+        }
+        if buf.is_empty() { Ok(Self {}) } else { Err(DecodeError::TrailingBytes) }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        Ok(())
+    }
+    pub fn v(&self) -> Enum8 {
+        Enum8::A
+    }
+}
+impl Packet for NormalChild {
+    fn encoded_len(&self) -> usize {
+        1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(u8::from(self.v()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Parent::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct NormalGrandChild1 {}
+impl TryFrom<&AliasChild> for NormalGrandChild1 {
+    type Error = DecodeError;
+    fn try_from(parent: &AliasChild) -> Result<NormalGrandChild1, Self::Error> {
+        NormalGrandChild1::decode_partial(&parent)
+    }
+}
+impl TryFrom<AliasChild> for NormalGrandChild1 {
+    type Error = DecodeError;
+    fn try_from(parent: AliasChild) -> Result<NormalGrandChild1, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&NormalGrandChild1> for AliasChild {
+    type Error = EncodeError;
+    fn try_from(packet: &NormalGrandChild1) -> Result<AliasChild, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(AliasChild { v: Enum8::B, payload })
+    }
+}
+impl TryFrom<NormalGrandChild1> for AliasChild {
+    type Error = EncodeError;
+    fn try_from(packet: NormalGrandChild1) -> Result<AliasChild, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl TryFrom<&NormalGrandChild1> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &NormalGrandChild1) -> Result<Parent, Self::Error> {
+        (&AliasChild::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<NormalGrandChild1> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: NormalGrandChild1) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl NormalGrandChild1 {
+    fn decode_partial(parent: &AliasChild) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.v() != Enum8::B {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "NormalGrandChild1",
+                field: "v",
+                expected: "Enum8::B",
+                actual: format!("{:?}", parent.v()),
+            });
+        }
+        if buf.is_empty() { Ok(Self {}) } else { Err(DecodeError::TrailingBytes) }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        Ok(())
+    }
+    pub fn v(&self) -> Enum8 {
+        Enum8::B
+    }
+}
+impl Packet for NormalGrandChild1 {
+    fn encoded_len(&self) -> usize {
+        1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(u8::from(self.v()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = AliasChild::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct NormalGrandChild2 {
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&AliasChild> for NormalGrandChild2 {
+    type Error = DecodeError;
+    fn try_from(parent: &AliasChild) -> Result<NormalGrandChild2, Self::Error> {
+        NormalGrandChild2::decode_partial(&parent)
+    }
+}
+impl TryFrom<AliasChild> for NormalGrandChild2 {
+    type Error = DecodeError;
+    fn try_from(parent: AliasChild) -> Result<NormalGrandChild2, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&NormalGrandChild2> for AliasChild {
+    type Error = EncodeError;
+    fn try_from(packet: &NormalGrandChild2) -> Result<AliasChild, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(AliasChild { v: Enum8::C, payload })
+    }
+}
+impl TryFrom<NormalGrandChild2> for AliasChild {
+    type Error = EncodeError;
+    fn try_from(packet: NormalGrandChild2) -> Result<AliasChild, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl TryFrom<&NormalGrandChild2> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &NormalGrandChild2) -> Result<Parent, Self::Error> {
+        (&AliasChild::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<NormalGrandChild2> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: NormalGrandChild2) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl NormalGrandChild2 {
+    fn decode_partial(parent: &AliasChild) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.v() != Enum8::C {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "NormalGrandChild2",
+                field: "v",
+                expected: "Enum8::C",
+                actual: format!("{:?}", parent.v()),
+            });
+        }
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        if buf.is_empty() {
+            Ok(Self { payload })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn v(&self) -> Enum8 {
+        Enum8::C
+    }
+}
+impl Packet for NormalGrandChild2 {
+    fn encoded_len(&self) -> usize {
+        1 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(u8::from(self.v()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = AliasChild::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_parent_with_alias_child_little_endian.rs b/tests/generated/rust/packet_decl_parent_with_alias_child_little_endian.rs
new file mode 100644
index 0000000..35df1a2
--- /dev/null
+++ b/tests/generated/rust/packet_decl_parent_with_alias_child_little_endian.rs
@@ -0,0 +1,461 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
+pub enum Enum8 {
+    A = 0x0,
+    B = 0x1,
+    C = 0x2,
+}
+impl TryFrom<u8> for Enum8 {
+    type Error = u8;
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
+        match value {
+            0x0 => Ok(Enum8::A),
+            0x1 => Ok(Enum8::B),
+            0x2 => Ok(Enum8::C),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum8> for u8 {
+    fn from(value: &Enum8) -> Self {
+        match value {
+            Enum8::A => 0x0,
+            Enum8::B => 0x1,
+            Enum8::C => 0x2,
+        }
+    }
+}
+impl From<Enum8> for u8 {
+    fn from(value: Enum8) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum8> for i16 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for i32 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for i64 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for u16 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for u32 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for u64 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Parent {
+    pub v: Enum8,
+    pub payload: Vec<u8>,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum ParentChild {
+    AliasChild(AliasChild),
+    NormalChild(NormalChild),
+    None,
+}
+impl Parent {
+    pub fn specialize(&self) -> Result<ParentChild, DecodeError> {
+        Ok(
+            match (self.v,) {
+                (_,) => ParentChild::AliasChild(self.try_into()?),
+                (Enum8::A,) => ParentChild::NormalChild(self.try_into()?),
+                _ => ParentChild::None,
+            },
+        )
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn v(&self) -> Enum8 {
+        self.v
+    }
+}
+impl Packet for Parent {
+    fn encoded_len(&self) -> usize {
+        1 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(u8::from(self.v()));
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let v = Enum8::try_from(buf.get_u8())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "v",
+                value: unknown_val as u64,
+                type_: "Enum8",
+            })?;
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        Ok((Self { payload, v }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct AliasChild {
+    pub v: Enum8,
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&Parent> for AliasChild {
+    type Error = DecodeError;
+    fn try_from(parent: &Parent) -> Result<AliasChild, Self::Error> {
+        AliasChild::decode_partial(&parent)
+    }
+}
+impl TryFrom<Parent> for AliasChild {
+    type Error = DecodeError;
+    fn try_from(parent: Parent) -> Result<AliasChild, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&AliasChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &AliasChild) -> Result<Parent, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Parent { v: packet.v, payload })
+    }
+}
+impl TryFrom<AliasChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: AliasChild) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum AliasChildChild {
+    NormalGrandChild1(NormalGrandChild1),
+    NormalGrandChild2(NormalGrandChild2),
+    None,
+}
+impl AliasChild {
+    pub fn specialize(&self) -> Result<AliasChildChild, DecodeError> {
+        Ok(
+            match (self.v,) {
+                (Enum8::B,) => AliasChildChild::NormalGrandChild1(self.try_into()?),
+                (Enum8::C,) => AliasChildChild::NormalGrandChild2(self.try_into()?),
+                _ => AliasChildChild::None,
+            },
+        )
+    }
+    fn decode_partial(parent: &Parent) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        if buf.is_empty() {
+            Ok(Self { payload, v: parent.v })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn v(&self) -> Enum8 {
+        self.v
+    }
+}
+impl Packet for AliasChild {
+    fn encoded_len(&self) -> usize {
+        1 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(u8::from(self.v()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Parent::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct NormalChild {}
+impl TryFrom<&Parent> for NormalChild {
+    type Error = DecodeError;
+    fn try_from(parent: &Parent) -> Result<NormalChild, Self::Error> {
+        NormalChild::decode_partial(&parent)
+    }
+}
+impl TryFrom<Parent> for NormalChild {
+    type Error = DecodeError;
+    fn try_from(parent: Parent) -> Result<NormalChild, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&NormalChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &NormalChild) -> Result<Parent, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Parent { v: Enum8::A, payload })
+    }
+}
+impl TryFrom<NormalChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: NormalChild) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl NormalChild {
+    fn decode_partial(parent: &Parent) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.v() != Enum8::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "NormalChild",
+                field: "v",
+                expected: "Enum8::A",
+                actual: format!("{:?}", parent.v()),
+            });
+        }
+        if buf.is_empty() { Ok(Self {}) } else { Err(DecodeError::TrailingBytes) }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        Ok(())
+    }
+    pub fn v(&self) -> Enum8 {
+        Enum8::A
+    }
+}
+impl Packet for NormalChild {
+    fn encoded_len(&self) -> usize {
+        1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(u8::from(self.v()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Parent::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct NormalGrandChild1 {}
+impl TryFrom<&AliasChild> for NormalGrandChild1 {
+    type Error = DecodeError;
+    fn try_from(parent: &AliasChild) -> Result<NormalGrandChild1, Self::Error> {
+        NormalGrandChild1::decode_partial(&parent)
+    }
+}
+impl TryFrom<AliasChild> for NormalGrandChild1 {
+    type Error = DecodeError;
+    fn try_from(parent: AliasChild) -> Result<NormalGrandChild1, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&NormalGrandChild1> for AliasChild {
+    type Error = EncodeError;
+    fn try_from(packet: &NormalGrandChild1) -> Result<AliasChild, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(AliasChild { v: Enum8::B, payload })
+    }
+}
+impl TryFrom<NormalGrandChild1> for AliasChild {
+    type Error = EncodeError;
+    fn try_from(packet: NormalGrandChild1) -> Result<AliasChild, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl TryFrom<&NormalGrandChild1> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &NormalGrandChild1) -> Result<Parent, Self::Error> {
+        (&AliasChild::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<NormalGrandChild1> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: NormalGrandChild1) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl NormalGrandChild1 {
+    fn decode_partial(parent: &AliasChild) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.v() != Enum8::B {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "NormalGrandChild1",
+                field: "v",
+                expected: "Enum8::B",
+                actual: format!("{:?}", parent.v()),
+            });
+        }
+        if buf.is_empty() { Ok(Self {}) } else { Err(DecodeError::TrailingBytes) }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        Ok(())
+    }
+    pub fn v(&self) -> Enum8 {
+        Enum8::B
+    }
+}
+impl Packet for NormalGrandChild1 {
+    fn encoded_len(&self) -> usize {
+        1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(u8::from(self.v()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = AliasChild::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct NormalGrandChild2 {
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&AliasChild> for NormalGrandChild2 {
+    type Error = DecodeError;
+    fn try_from(parent: &AliasChild) -> Result<NormalGrandChild2, Self::Error> {
+        NormalGrandChild2::decode_partial(&parent)
+    }
+}
+impl TryFrom<AliasChild> for NormalGrandChild2 {
+    type Error = DecodeError;
+    fn try_from(parent: AliasChild) -> Result<NormalGrandChild2, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&NormalGrandChild2> for AliasChild {
+    type Error = EncodeError;
+    fn try_from(packet: &NormalGrandChild2) -> Result<AliasChild, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(AliasChild { v: Enum8::C, payload })
+    }
+}
+impl TryFrom<NormalGrandChild2> for AliasChild {
+    type Error = EncodeError;
+    fn try_from(packet: NormalGrandChild2) -> Result<AliasChild, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl TryFrom<&NormalGrandChild2> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &NormalGrandChild2) -> Result<Parent, Self::Error> {
+        (&AliasChild::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<NormalGrandChild2> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: NormalGrandChild2) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl NormalGrandChild2 {
+    fn decode_partial(parent: &AliasChild) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.v() != Enum8::C {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "NormalGrandChild2",
+                field: "v",
+                expected: "Enum8::C",
+                actual: format!("{:?}", parent.v()),
+            });
+        }
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        if buf.is_empty() {
+            Ok(Self { payload })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn v(&self) -> Enum8 {
+        Enum8::C
+    }
+}
+impl Packet for NormalGrandChild2 {
+    fn encoded_len(&self) -> usize {
+        1 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(u8::from(self.v()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = AliasChild::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_parent_with_no_payload_big_endian.rs b/tests/generated/rust/packet_decl_parent_with_no_payload_big_endian.rs
new file mode 100644
index 0000000..7fa66a7
--- /dev/null
+++ b/tests/generated/rust/packet_decl_parent_with_no_payload_big_endian.rs
@@ -0,0 +1,191 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
+pub enum Enum8 {
+    A = 0x0,
+}
+impl TryFrom<u8> for Enum8 {
+    type Error = u8;
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
+        match value {
+            0x0 => Ok(Enum8::A),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum8> for u8 {
+    fn from(value: &Enum8) -> Self {
+        match value {
+            Enum8::A => 0x0,
+        }
+    }
+}
+impl From<Enum8> for u8 {
+    fn from(value: Enum8) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum8> for i16 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for i32 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for i64 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for u16 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for u32 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for u64 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Parent {
+    pub v: Enum8,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum ParentChild {
+    Child(Child),
+    None,
+}
+impl Parent {
+    pub fn specialize(&self) -> Result<ParentChild, DecodeError> {
+        Ok(
+            match (self.v,) {
+                (Enum8::A,) => ParentChild::Child(self.try_into()?),
+                _ => ParentChild::None,
+            },
+        )
+    }
+    pub fn v(&self) -> Enum8 {
+        self.v
+    }
+}
+impl Packet for Parent {
+    fn encoded_len(&self) -> usize {
+        1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(u8::from(self.v()));
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let v = Enum8::try_from(buf.get_u8())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "v",
+                value: unknown_val as u64,
+                type_: "Enum8",
+            })?;
+        Ok((Self { v }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Child {}
+impl TryFrom<&Parent> for Child {
+    type Error = DecodeError;
+    fn try_from(parent: &Parent) -> Result<Child, Self::Error> {
+        Child::decode_partial(&parent)
+    }
+}
+impl TryFrom<Parent> for Child {
+    type Error = DecodeError;
+    fn try_from(parent: Parent) -> Result<Child, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl From<&Child> for Parent {
+    fn from(packet: &Child) -> Parent {
+        Parent { v: Enum8::A }
+    }
+}
+impl From<Child> for Parent {
+    fn from(packet: Child) -> Parent {
+        (&packet).into()
+    }
+}
+impl Child {
+    fn decode_partial(parent: &Parent) -> Result<Self, DecodeError> {
+        if parent.v() != Enum8::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "Child",
+                field: "v",
+                expected: "Enum8::A",
+                actual: format!("{:?}", parent.v()),
+            });
+        }
+        Ok(Self {})
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        Ok(())
+    }
+    pub fn v(&self) -> Enum8 {
+        Enum8::A
+    }
+}
+impl Packet for Child {
+    fn encoded_len(&self) -> usize {
+        1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(u8::from(self.v()));
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Parent::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_parent_with_no_payload_little_endian.rs b/tests/generated/rust/packet_decl_parent_with_no_payload_little_endian.rs
new file mode 100644
index 0000000..7fa66a7
--- /dev/null
+++ b/tests/generated/rust/packet_decl_parent_with_no_payload_little_endian.rs
@@ -0,0 +1,191 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
+pub enum Enum8 {
+    A = 0x0,
+}
+impl TryFrom<u8> for Enum8 {
+    type Error = u8;
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
+        match value {
+            0x0 => Ok(Enum8::A),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum8> for u8 {
+    fn from(value: &Enum8) -> Self {
+        match value {
+            Enum8::A => 0x0,
+        }
+    }
+}
+impl From<Enum8> for u8 {
+    fn from(value: Enum8) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum8> for i16 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for i32 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for i64 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for u16 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for u32 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+impl From<Enum8> for u64 {
+    fn from(value: Enum8) -> Self {
+        u8::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Parent {
+    pub v: Enum8,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum ParentChild {
+    Child(Child),
+    None,
+}
+impl Parent {
+    pub fn specialize(&self) -> Result<ParentChild, DecodeError> {
+        Ok(
+            match (self.v,) {
+                (Enum8::A,) => ParentChild::Child(self.try_into()?),
+                _ => ParentChild::None,
+            },
+        )
+    }
+    pub fn v(&self) -> Enum8 {
+        self.v
+    }
+}
+impl Packet for Parent {
+    fn encoded_len(&self) -> usize {
+        1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(u8::from(self.v()));
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let v = Enum8::try_from(buf.get_u8())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "v",
+                value: unknown_val as u64,
+                type_: "Enum8",
+            })?;
+        Ok((Self { v }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Child {}
+impl TryFrom<&Parent> for Child {
+    type Error = DecodeError;
+    fn try_from(parent: &Parent) -> Result<Child, Self::Error> {
+        Child::decode_partial(&parent)
+    }
+}
+impl TryFrom<Parent> for Child {
+    type Error = DecodeError;
+    fn try_from(parent: Parent) -> Result<Child, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl From<&Child> for Parent {
+    fn from(packet: &Child) -> Parent {
+        Parent { v: Enum8::A }
+    }
+}
+impl From<Child> for Parent {
+    fn from(packet: Child) -> Parent {
+        (&packet).into()
+    }
+}
+impl Child {
+    fn decode_partial(parent: &Parent) -> Result<Self, DecodeError> {
+        if parent.v() != Enum8::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "Child",
+                field: "v",
+                expected: "Enum8::A",
+                actual: format!("{:?}", parent.v()),
+            });
+        }
+        Ok(Self {})
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        Ok(())
+    }
+    pub fn v(&self) -> Enum8 {
+        Enum8::A
+    }
+}
+impl Packet for Child {
+    fn encoded_len(&self) -> usize {
+        1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(u8::from(self.v()));
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Parent::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_payload_field_unknown_size_big_endian.rs b/tests/generated/rust/packet_decl_payload_field_unknown_size_big_endian.rs
new file mode 100644
index 0000000..583f1c6
--- /dev/null
+++ b/tests/generated/rust/packet_decl_payload_field_unknown_size_big_endian.rs
@@ -0,0 +1,70 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u32,
+    pub payload: Vec<u8>,
+}
+impl Foo {
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn a(&self) -> u32 {
+        self.a
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        3 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.a() > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a() as u64,
+                maximum_value: 0xff_ffff as u64,
+            });
+        }
+        buf.put_uint(self.a() as u64, 3);
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let a = buf.get_uint(3) as u32;
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        Ok((Self { payload, a }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_payload_field_unknown_size_little_endian.rs b/tests/generated/rust/packet_decl_payload_field_unknown_size_little_endian.rs
new file mode 100644
index 0000000..04f9b1a
--- /dev/null
+++ b/tests/generated/rust/packet_decl_payload_field_unknown_size_little_endian.rs
@@ -0,0 +1,70 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u32,
+    pub payload: Vec<u8>,
+}
+impl Foo {
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn a(&self) -> u32 {
+        self.a
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        3 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.a() > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a() as u64,
+                maximum_value: 0xff_ffff as u64,
+            });
+        }
+        buf.put_uint_le(self.a() as u64, 3);
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let a = buf.get_uint_le(3) as u32;
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        Ok((Self { payload, a }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_payload_field_unknown_size_terminal_big_endian.rs b/tests/generated/rust/packet_decl_payload_field_unknown_size_terminal_big_endian.rs
new file mode 100644
index 0000000..8b56781
--- /dev/null
+++ b/tests/generated/rust/packet_decl_payload_field_unknown_size_terminal_big_endian.rs
@@ -0,0 +1,77 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u32,
+    pub payload: Vec<u8>,
+}
+impl Foo {
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn a(&self) -> u32 {
+        self.a
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        3 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_slice(&self.payload);
+        if self.a() > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a() as u64,
+                maximum_value: 0xff_ffff as u64,
+            });
+        }
+        buf.put_uint(self.a() as u64, 3);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let payload = buf[..buf.len() - 3].to_vec();
+        buf.advance(payload.len());
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let a = buf.get_uint(3) as u32;
+        Ok((Self { payload, a }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_payload_field_unknown_size_terminal_little_endian.rs b/tests/generated/rust/packet_decl_payload_field_unknown_size_terminal_little_endian.rs
new file mode 100644
index 0000000..6f4d71c
--- /dev/null
+++ b/tests/generated/rust/packet_decl_payload_field_unknown_size_terminal_little_endian.rs
@@ -0,0 +1,77 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u32,
+    pub payload: Vec<u8>,
+}
+impl Foo {
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn a(&self) -> u32 {
+        self.a
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        3 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_slice(&self.payload);
+        if self.a() > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a() as u64,
+                maximum_value: 0xff_ffff as u64,
+            });
+        }
+        buf.put_uint_le(self.a() as u64, 3);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let payload = buf[..buf.len() - 3].to_vec();
+        buf.advance(payload.len());
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let a = buf.get_uint_le(3) as u32;
+        Ok((Self { payload, a }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_payload_field_variable_size_big_endian.rs b/tests/generated/rust/packet_decl_payload_field_variable_size_big_endian.rs
new file mode 100644
index 0000000..4c5d8b3
--- /dev/null
+++ b/tests/generated/rust/packet_decl_payload_field_variable_size_big_endian.rs
@@ -0,0 +1,99 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u8,
+    pub b: u16,
+    pub payload: Vec<u8>,
+}
+impl Foo {
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> u16 {
+        self.b
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        4 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        if self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(self.payload.len() as u8);
+        buf.put_slice(&self.payload);
+        buf.put_u16(self.b());
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let a = buf.get_u8();
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let payload_size = buf.get_u8() as usize;
+        if buf.remaining() < payload_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: payload_size,
+                got: buf.remaining(),
+            });
+        }
+        let payload = buf[..payload_size].to_vec();
+        buf.advance(payload_size);
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let b = buf.get_u16();
+        Ok((Self { payload, a, b }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_payload_field_variable_size_little_endian.rs b/tests/generated/rust/packet_decl_payload_field_variable_size_little_endian.rs
new file mode 100644
index 0000000..f82f777
--- /dev/null
+++ b/tests/generated/rust/packet_decl_payload_field_variable_size_little_endian.rs
@@ -0,0 +1,99 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u8,
+    pub b: u16,
+    pub payload: Vec<u8>,
+}
+impl Foo {
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> u16 {
+        self.b
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        4 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        if self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(self.payload.len() as u8);
+        buf.put_slice(&self.payload);
+        buf.put_u16_le(self.b());
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let a = buf.get_u8();
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let payload_size = buf.get_u8() as usize;
+        if buf.remaining() < payload_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: payload_size,
+                got: buf.remaining(),
+            });
+        }
+        let payload = buf[..payload_size].to_vec();
+        buf.advance(payload_size);
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let b = buf.get_u16_le();
+        Ok((Self { payload, a, b }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_reserved_field_big_endian.rs b/tests/generated/rust/packet_decl_reserved_field_big_endian.rs
new file mode 100644
index 0000000..0eaeb23
--- /dev/null
+++ b/tests/generated/rust/packet_decl_reserved_field_big_endian.rs
@@ -0,0 +1,49 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {}
+impl Foo {}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        5
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_bytes(0, 5);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 5,
+                got: buf.remaining(),
+            });
+        }
+        buf.advance(5);
+        Ok((Self {}, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_reserved_field_little_endian.rs b/tests/generated/rust/packet_decl_reserved_field_little_endian.rs
new file mode 100644
index 0000000..0eaeb23
--- /dev/null
+++ b/tests/generated/rust/packet_decl_reserved_field_little_endian.rs
@@ -0,0 +1,49 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {}
+impl Foo {}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        5
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_bytes(0, 5);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 5,
+                got: buf.remaining(),
+            });
+        }
+        buf.advance(5);
+        Ok((Self {}, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_simple_scalars_big_endian.rs b/tests/generated/rust/packet_decl_simple_scalars_big_endian.rs
new file mode 100644
index 0000000..e1c39d3
--- /dev/null
+++ b/tests/generated/rust/packet_decl_simple_scalars_big_endian.rs
@@ -0,0 +1,89 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub x: u8,
+    pub y: u16,
+    pub z: u32,
+}
+impl Foo {
+    pub fn x(&self) -> u8 {
+        self.x
+    }
+    pub fn y(&self) -> u16 {
+        self.y
+    }
+    pub fn z(&self) -> u32 {
+        self.z
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        6
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.x());
+        buf.put_u16(self.y());
+        if self.z() > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "z",
+                value: self.z() as u64,
+                maximum_value: 0xff_ffff as u64,
+            });
+        }
+        buf.put_uint(self.z() as u64, 3);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf.get_u8();
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let y = buf.get_u16();
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let z = buf.get_uint(3) as u32;
+        Ok((Self { x, y, z }, buf))
+    }
+}
diff --git a/tests/generated/rust/packet_decl_simple_scalars_little_endian.rs b/tests/generated/rust/packet_decl_simple_scalars_little_endian.rs
new file mode 100644
index 0000000..e6560dc
--- /dev/null
+++ b/tests/generated/rust/packet_decl_simple_scalars_little_endian.rs
@@ -0,0 +1,89 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub x: u8,
+    pub y: u16,
+    pub z: u32,
+}
+impl Foo {
+    pub fn x(&self) -> u8 {
+        self.x
+    }
+    pub fn y(&self) -> u16 {
+        self.y
+    }
+    pub fn z(&self) -> u32 {
+        self.z
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        6
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.x());
+        buf.put_u16_le(self.y());
+        if self.z() > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "z",
+                value: self.z() as u64,
+                maximum_value: 0xff_ffff as u64,
+            });
+        }
+        buf.put_uint_le(self.z() as u64, 3);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf.get_u8();
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let y = buf.get_u16_le();
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let z = buf.get_uint_le(3) as u32;
+        Ok((Self { x, y, z }, buf))
+    }
+}
diff --git a/tests/generated/rust/payload_with_size_modifier_big_endian.rs b/tests/generated/rust/payload_with_size_modifier_big_endian.rs
new file mode 100644
index 0000000..a0411dc
--- /dev/null
+++ b/tests/generated/rust/payload_with_size_modifier_big_endian.rs
@@ -0,0 +1,81 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Test {
+    pub payload: Vec<u8>,
+}
+impl Test {
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+}
+impl Packet for Test {
+    fn encoded_len(&self) -> usize {
+        1 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if (self.payload.len() + 1) > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Test",
+                field: "_payload_",
+                size: (self.payload.len() + 1),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8((self.payload.len() + 1) as u8);
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Test",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let payload_size = buf.get_u8() as usize;
+        if payload_size < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Test",
+                wanted: 1,
+                got: payload_size,
+            });
+        }
+        let payload_size = payload_size - 1;
+        if buf.remaining() < payload_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Test",
+                wanted: payload_size,
+                got: buf.remaining(),
+            });
+        }
+        let payload = buf[..payload_size].to_vec();
+        buf.advance(payload_size);
+        Ok((Self { payload }, buf))
+    }
+}
diff --git a/tests/generated/rust/payload_with_size_modifier_little_endian.rs b/tests/generated/rust/payload_with_size_modifier_little_endian.rs
new file mode 100644
index 0000000..a0411dc
--- /dev/null
+++ b/tests/generated/rust/payload_with_size_modifier_little_endian.rs
@@ -0,0 +1,81 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Test {
+    pub payload: Vec<u8>,
+}
+impl Test {
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+}
+impl Packet for Test {
+    fn encoded_len(&self) -> usize {
+        1 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if (self.payload.len() + 1) > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Test",
+                field: "_payload_",
+                size: (self.payload.len() + 1),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8((self.payload.len() + 1) as u8);
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Test",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let payload_size = buf.get_u8() as usize;
+        if payload_size < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Test",
+                wanted: 1,
+                got: payload_size,
+            });
+        }
+        let payload_size = payload_size - 1;
+        if buf.remaining() < payload_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Test",
+                wanted: payload_size,
+                got: buf.remaining(),
+            });
+        }
+        let payload = buf[..payload_size].to_vec();
+        buf.advance(payload_size);
+        Ok((Self { payload }, buf))
+    }
+}
diff --git a/tests/generated/rust/reserved_identifier_big_endian.rs b/tests/generated/rust/reserved_identifier_big_endian.rs
new file mode 100644
index 0000000..17ee5a3
--- /dev/null
+++ b/tests/generated/rust/reserved_identifier_big_endian.rs
@@ -0,0 +1,55 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Test {
+    pub r#type: u8,
+}
+impl Test {
+    pub fn r#type(&self) -> u8 {
+        self.r#type
+    }
+}
+impl Packet for Test {
+    fn encoded_len(&self) -> usize {
+        1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.r#type());
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Test",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let r#type = buf.get_u8();
+        Ok((Self { r#type }, buf))
+    }
+}
diff --git a/tests/generated/rust/reserved_identifier_little_endian.rs b/tests/generated/rust/reserved_identifier_little_endian.rs
new file mode 100644
index 0000000..17ee5a3
--- /dev/null
+++ b/tests/generated/rust/reserved_identifier_little_endian.rs
@@ -0,0 +1,55 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Test {
+    pub r#type: u8,
+}
+impl Test {
+    pub fn r#type(&self) -> u8 {
+        self.r#type
+    }
+}
+impl Packet for Test {
+    fn encoded_len(&self) -> usize {
+        1
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.r#type());
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Test",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let r#type = buf.get_u8();
+        Ok((Self { r#type }, buf))
+    }
+}
diff --git a/tests/generated/rust/struct_decl_child_structs_big_endian.rs b/tests/generated/rust/struct_decl_child_structs_big_endian.rs
new file mode 100644
index 0000000..9653e2d
--- /dev/null
+++ b/tests/generated/rust/struct_decl_child_structs_big_endian.rs
@@ -0,0 +1,373 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))]
+pub enum Enum16 {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u16> for Enum16 {
+    type Error = u16;
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Enum16::A),
+            0x2 => Ok(Enum16::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum16> for u16 {
+    fn from(value: &Enum16) -> Self {
+        match value {
+            Enum16::A => 0x1,
+            Enum16::B => 0x2,
+        }
+    }
+}
+impl From<Enum16> for u16 {
+    fn from(value: Enum16) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum16> for i32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for i64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u8,
+    pub b: Enum16,
+    pub payload: Vec<u8>,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum FooChild {
+    Bar(Bar),
+    Baz(Baz),
+    None,
+}
+impl Foo {
+    pub fn specialize(&self) -> Result<FooChild, DecodeError> {
+        Ok(
+            match (self.a, self.b) {
+                (100, _) => FooChild::Bar(self.try_into()?),
+                (_, Enum16::B) => FooChild::Baz(self.try_into()?),
+                _ => FooChild::None,
+            },
+        )
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> Enum16 {
+        self.b
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        4 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        buf.put_u16(u16::from(self.b()));
+        if self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(self.payload.len() as u8);
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let a = buf.get_u8();
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let b = Enum16::try_from(buf.get_u16())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Foo",
+                field: "b",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let payload_size = buf.get_u8() as usize;
+        if buf.remaining() < payload_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: payload_size,
+                got: buf.remaining(),
+            });
+        }
+        let payload = buf[..payload_size].to_vec();
+        buf.advance(payload_size);
+        let payload = Vec::from(payload);
+        Ok((Self { payload, a, b }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: u8,
+    pub b: Enum16,
+}
+impl TryFrom<&Foo> for Bar {
+    type Error = DecodeError;
+    fn try_from(parent: &Foo) -> Result<Bar, Self::Error> {
+        Bar::decode_partial(&parent)
+    }
+}
+impl TryFrom<Foo> for Bar {
+    type Error = DecodeError;
+    fn try_from(parent: Foo) -> Result<Bar, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&Bar> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: &Bar) -> Result<Foo, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Foo {
+            a: 100,
+            b: packet.b,
+            payload,
+        })
+    }
+}
+impl TryFrom<Bar> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Foo, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl Bar {
+    fn decode_partial(parent: &Foo) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.a() != 100 {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "Bar",
+                field: "a",
+                expected: "100",
+                actual: format!("{:?}", parent.a()),
+            });
+        }
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf.get_u8();
+        if buf.is_empty() {
+            Ok(Self { x, b: parent.b })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.x());
+        Ok(())
+    }
+    pub fn x(&self) -> u8 {
+        self.x
+    }
+    pub fn b(&self) -> Enum16 {
+        self.b
+    }
+    pub fn a(&self) -> u8 {
+        100
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        5
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        buf.put_u16(u16::from(self.b()));
+        if 1 > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: 1,
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(1 as u8);
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Foo::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Baz {
+    pub y: u16,
+    pub a: u8,
+}
+impl TryFrom<&Foo> for Baz {
+    type Error = DecodeError;
+    fn try_from(parent: &Foo) -> Result<Baz, Self::Error> {
+        Baz::decode_partial(&parent)
+    }
+}
+impl TryFrom<Foo> for Baz {
+    type Error = DecodeError;
+    fn try_from(parent: Foo) -> Result<Baz, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&Baz> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: &Baz) -> Result<Foo, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Foo {
+            a: packet.a,
+            b: Enum16::B,
+            payload,
+        })
+    }
+}
+impl TryFrom<Baz> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: Baz) -> Result<Foo, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl Baz {
+    fn decode_partial(parent: &Foo) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.b() != Enum16::B {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "Baz",
+                field: "b",
+                expected: "Enum16::B",
+                actual: format!("{:?}", parent.b()),
+            });
+        }
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Baz",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let y = buf.get_u16();
+        if buf.is_empty() {
+            Ok(Self { y, a: parent.a })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16(self.y());
+        Ok(())
+    }
+    pub fn y(&self) -> u16 {
+        self.y
+    }
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> Enum16 {
+        Enum16::B
+    }
+}
+impl Packet for Baz {
+    fn encoded_len(&self) -> usize {
+        6
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        buf.put_u16(u16::from(self.b()));
+        if 2 > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: 2,
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 as u8);
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Foo::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
diff --git a/tests/generated/rust/struct_decl_child_structs_little_endian.rs b/tests/generated/rust/struct_decl_child_structs_little_endian.rs
new file mode 100644
index 0000000..20fc72c
--- /dev/null
+++ b/tests/generated/rust/struct_decl_child_structs_little_endian.rs
@@ -0,0 +1,373 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))]
+pub enum Enum16 {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u16> for Enum16 {
+    type Error = u16;
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Enum16::A),
+            0x2 => Ok(Enum16::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum16> for u16 {
+    fn from(value: &Enum16) -> Self {
+        match value {
+            Enum16::A => 0x1,
+            Enum16::B => 0x2,
+        }
+    }
+}
+impl From<Enum16> for u16 {
+    fn from(value: Enum16) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum16> for i32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for i64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u8,
+    pub b: Enum16,
+    pub payload: Vec<u8>,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum FooChild {
+    Bar(Bar),
+    Baz(Baz),
+    None,
+}
+impl Foo {
+    pub fn specialize(&self) -> Result<FooChild, DecodeError> {
+        Ok(
+            match (self.a, self.b) {
+                (100, _) => FooChild::Bar(self.try_into()?),
+                (_, Enum16::B) => FooChild::Baz(self.try_into()?),
+                _ => FooChild::None,
+            },
+        )
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> Enum16 {
+        self.b
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        4 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        buf.put_u16_le(u16::from(self.b()));
+        if self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(self.payload.len() as u8);
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let a = buf.get_u8();
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let b = Enum16::try_from(buf.get_u16_le())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Foo",
+                field: "b",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let payload_size = buf.get_u8() as usize;
+        if buf.remaining() < payload_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: payload_size,
+                got: buf.remaining(),
+            });
+        }
+        let payload = buf[..payload_size].to_vec();
+        buf.advance(payload_size);
+        let payload = Vec::from(payload);
+        Ok((Self { payload, a, b }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: u8,
+    pub b: Enum16,
+}
+impl TryFrom<&Foo> for Bar {
+    type Error = DecodeError;
+    fn try_from(parent: &Foo) -> Result<Bar, Self::Error> {
+        Bar::decode_partial(&parent)
+    }
+}
+impl TryFrom<Foo> for Bar {
+    type Error = DecodeError;
+    fn try_from(parent: Foo) -> Result<Bar, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&Bar> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: &Bar) -> Result<Foo, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Foo {
+            a: 100,
+            b: packet.b,
+            payload,
+        })
+    }
+}
+impl TryFrom<Bar> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Foo, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl Bar {
+    fn decode_partial(parent: &Foo) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.a() != 100 {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "Bar",
+                field: "a",
+                expected: "100",
+                actual: format!("{:?}", parent.a()),
+            });
+        }
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf.get_u8();
+        if buf.is_empty() {
+            Ok(Self { x, b: parent.b })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.x());
+        Ok(())
+    }
+    pub fn x(&self) -> u8 {
+        self.x
+    }
+    pub fn b(&self) -> Enum16 {
+        self.b
+    }
+    pub fn a(&self) -> u8 {
+        100
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        5
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        buf.put_u16_le(u16::from(self.b()));
+        if 1 > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: 1,
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(1 as u8);
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Foo::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Baz {
+    pub y: u16,
+    pub a: u8,
+}
+impl TryFrom<&Foo> for Baz {
+    type Error = DecodeError;
+    fn try_from(parent: &Foo) -> Result<Baz, Self::Error> {
+        Baz::decode_partial(&parent)
+    }
+}
+impl TryFrom<Foo> for Baz {
+    type Error = DecodeError;
+    fn try_from(parent: Foo) -> Result<Baz, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&Baz> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: &Baz) -> Result<Foo, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Foo {
+            a: packet.a,
+            b: Enum16::B,
+            payload,
+        })
+    }
+}
+impl TryFrom<Baz> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: Baz) -> Result<Foo, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl Baz {
+    fn decode_partial(parent: &Foo) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.b() != Enum16::B {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "Baz",
+                field: "b",
+                expected: "Enum16::B",
+                actual: format!("{:?}", parent.b()),
+            });
+        }
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Baz",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let y = buf.get_u16_le();
+        if buf.is_empty() {
+            Ok(Self { y, a: parent.a })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16_le(self.y());
+        Ok(())
+    }
+    pub fn y(&self) -> u16 {
+        self.y
+    }
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> Enum16 {
+        Enum16::B
+    }
+}
+impl Packet for Baz {
+    fn encoded_len(&self) -> usize {
+        6
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        buf.put_u16_le(u16::from(self.b()));
+        if 2 > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: 2,
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 as u8);
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Foo::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
diff --git a/tests/generated/rust/struct_decl_complex_scalars_big_endian.rs b/tests/generated/rust/struct_decl_complex_scalars_big_endian.rs
new file mode 100644
index 0000000..e2f6e8c
--- /dev/null
+++ b/tests/generated/rust/struct_decl_complex_scalars_big_endian.rs
@@ -0,0 +1,141 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u8,
+    pub b: u8,
+    pub c: u8,
+    pub d: u32,
+    pub e: u16,
+    pub f: u8,
+}
+impl Foo {
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> u8 {
+        self.b
+    }
+    pub fn c(&self) -> u8 {
+        self.c
+    }
+    pub fn d(&self) -> u32 {
+        self.d
+    }
+    pub fn e(&self) -> u16 {
+        self.e
+    }
+    pub fn f(&self) -> u8 {
+        self.f
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        7
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.a() > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a() as u64,
+                maximum_value: 0x7 as u64,
+            });
+        }
+        if self.c() > 0x1f {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "c",
+                value: self.c() as u64,
+                maximum_value: 0x1f as u64,
+            });
+        }
+        let value = (self.a() as u16) | ((self.b() as u16) << 3)
+            | ((self.c() as u16) << 11);
+        buf.put_u16(value);
+        if self.d() > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "d",
+                value: self.d() as u64,
+                maximum_value: 0xff_ffff as u64,
+            });
+        }
+        buf.put_uint(self.d() as u64, 3);
+        if self.e() > 0xfff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "e",
+                value: self.e() as u64,
+                maximum_value: 0xfff as u64,
+            });
+        }
+        if self.f() > 0xf {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "f",
+                value: self.f() as u64,
+                maximum_value: 0xf as u64,
+            });
+        }
+        let value = self.e() | ((self.f() as u16) << 12);
+        buf.put_u16(value);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u16();
+        let a = (chunk & 0x7) as u8;
+        let b = (chunk >> 3) as u8;
+        let c = ((chunk >> 11) & 0x1f) as u8;
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let d = buf.get_uint(3) as u32;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u16();
+        let e = (chunk & 0xfff);
+        let f = ((chunk >> 12) & 0xf) as u8;
+        Ok((Self { a, b, c, d, e, f }, buf))
+    }
+}
diff --git a/tests/generated/rust/struct_decl_complex_scalars_little_endian.rs b/tests/generated/rust/struct_decl_complex_scalars_little_endian.rs
new file mode 100644
index 0000000..b18d238
--- /dev/null
+++ b/tests/generated/rust/struct_decl_complex_scalars_little_endian.rs
@@ -0,0 +1,141 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u8,
+    pub b: u8,
+    pub c: u8,
+    pub d: u32,
+    pub e: u16,
+    pub f: u8,
+}
+impl Foo {
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> u8 {
+        self.b
+    }
+    pub fn c(&self) -> u8 {
+        self.c
+    }
+    pub fn d(&self) -> u32 {
+        self.d
+    }
+    pub fn e(&self) -> u16 {
+        self.e
+    }
+    pub fn f(&self) -> u8 {
+        self.f
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        7
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        if self.a() > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a() as u64,
+                maximum_value: 0x7 as u64,
+            });
+        }
+        if self.c() > 0x1f {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "c",
+                value: self.c() as u64,
+                maximum_value: 0x1f as u64,
+            });
+        }
+        let value = (self.a() as u16) | ((self.b() as u16) << 3)
+            | ((self.c() as u16) << 11);
+        buf.put_u16_le(value);
+        if self.d() > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "d",
+                value: self.d() as u64,
+                maximum_value: 0xff_ffff as u64,
+            });
+        }
+        buf.put_uint_le(self.d() as u64, 3);
+        if self.e() > 0xfff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "e",
+                value: self.e() as u64,
+                maximum_value: 0xfff as u64,
+            });
+        }
+        if self.f() > 0xf {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "f",
+                value: self.f() as u64,
+                maximum_value: 0xf as u64,
+            });
+        }
+        let value = self.e() | ((self.f() as u16) << 12);
+        buf.put_u16_le(value);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u16_le();
+        let a = (chunk & 0x7) as u8;
+        let b = (chunk >> 3) as u8;
+        let c = ((chunk >> 11) & 0x1f) as u8;
+        if buf.remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: buf.remaining(),
+            });
+        }
+        let d = buf.get_uint_le(3) as u32;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let chunk = buf.get_u16_le();
+        let e = (chunk & 0xfff);
+        let f = ((chunk >> 12) & 0xf) as u8;
+        Ok((Self { a, b, c, d, e, f }, buf))
+    }
+}
diff --git a/tests/generated/rust/struct_decl_grand_children_big_endian.rs b/tests/generated/rust/struct_decl_grand_children_big_endian.rs
new file mode 100644
index 0000000..e3c124c
--- /dev/null
+++ b/tests/generated/rust/struct_decl_grand_children_big_endian.rs
@@ -0,0 +1,598 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))]
+pub enum Enum16 {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u16> for Enum16 {
+    type Error = u16;
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Enum16::A),
+            0x2 => Ok(Enum16::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum16> for u16 {
+    fn from(value: &Enum16) -> Self {
+        match value {
+            Enum16::A => 0x1,
+            Enum16::B => 0x2,
+        }
+    }
+}
+impl From<Enum16> for u16 {
+    fn from(value: Enum16) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum16> for i32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for i64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Parent {
+    pub foo: Enum16,
+    pub bar: Enum16,
+    pub baz: Enum16,
+    pub payload: Vec<u8>,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum ParentChild {
+    Child(Child),
+    None,
+}
+impl Parent {
+    pub fn specialize(&self) -> Result<ParentChild, DecodeError> {
+        Ok(
+            match (self.foo,) {
+                (Enum16::A,) => ParentChild::Child(self.try_into()?),
+                _ => ParentChild::None,
+            },
+        )
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn foo(&self) -> Enum16 {
+        self.foo
+    }
+    pub fn bar(&self) -> Enum16 {
+        self.bar
+    }
+    pub fn baz(&self) -> Enum16 {
+        self.baz
+    }
+}
+impl Packet for Parent {
+    fn encoded_len(&self) -> usize {
+        7 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16(u16::from(self.foo()));
+        buf.put_u16(u16::from(self.bar()));
+        buf.put_u16(u16::from(self.baz()));
+        if self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(self.payload.len() as u8);
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let foo = Enum16::try_from(buf.get_u16())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "foo",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let bar = Enum16::try_from(buf.get_u16())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "bar",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let baz = Enum16::try_from(buf.get_u16())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "baz",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let payload_size = buf.get_u8() as usize;
+        if buf.remaining() < payload_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: payload_size,
+                got: buf.remaining(),
+            });
+        }
+        let payload = buf[..payload_size].to_vec();
+        buf.advance(payload_size);
+        let payload = Vec::from(payload);
+        Ok((Self { payload, foo, bar, baz }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Child {
+    pub quux: Enum16,
+    pub bar: Enum16,
+    pub baz: Enum16,
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&Parent> for Child {
+    type Error = DecodeError;
+    fn try_from(parent: &Parent) -> Result<Child, Self::Error> {
+        Child::decode_partial(&parent)
+    }
+}
+impl TryFrom<Parent> for Child {
+    type Error = DecodeError;
+    fn try_from(parent: Parent) -> Result<Child, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&Child> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &Child) -> Result<Parent, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Parent {
+            foo: Enum16::A,
+            bar: packet.bar,
+            baz: packet.baz,
+            payload,
+        })
+    }
+}
+impl TryFrom<Child> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: Child) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum ChildChild {
+    GrandChild(GrandChild),
+    None,
+}
+impl Child {
+    pub fn specialize(&self) -> Result<ChildChild, DecodeError> {
+        Ok(
+            match (self.bar, self.quux) {
+                (Enum16::A, Enum16::A) => ChildChild::GrandChild(self.try_into()?),
+                _ => ChildChild::None,
+            },
+        )
+    }
+    fn decode_partial(parent: &Parent) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.foo() != Enum16::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "Child",
+                field: "foo",
+                expected: "Enum16::A",
+                actual: format!("{:?}", parent.foo()),
+            });
+        }
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Child",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let quux = Enum16::try_from(buf.get_u16())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Child",
+                field: "quux",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        let payload = Vec::from(payload);
+        if buf.is_empty() {
+            Ok(Self {
+                payload,
+                quux,
+                bar: parent.bar,
+                baz: parent.baz,
+            })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16(u16::from(self.quux()));
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn quux(&self) -> Enum16 {
+        self.quux
+    }
+    pub fn bar(&self) -> Enum16 {
+        self.bar
+    }
+    pub fn baz(&self) -> Enum16 {
+        self.baz
+    }
+    pub fn foo(&self) -> Enum16 {
+        Enum16::A
+    }
+}
+impl Packet for Child {
+    fn encoded_len(&self) -> usize {
+        9 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16(u16::from(self.foo()));
+        buf.put_u16(u16::from(self.bar()));
+        buf.put_u16(u16::from(self.baz()));
+        if 2 + self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: 2 + self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 + self.payload.len() as u8);
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Parent::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct GrandChild {
+    pub baz: Enum16,
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&Child> for GrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: &Child) -> Result<GrandChild, Self::Error> {
+        GrandChild::decode_partial(&parent)
+    }
+}
+impl TryFrom<Child> for GrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: Child) -> Result<GrandChild, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&GrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandChild) -> Result<Child, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Child {
+            quux: Enum16::A,
+            bar: Enum16::A,
+            baz: packet.baz,
+            payload,
+        })
+    }
+}
+impl TryFrom<GrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: GrandChild) -> Result<Child, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl TryFrom<&GrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandChild) -> Result<Parent, Self::Error> {
+        (&Child::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<GrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: GrandChild) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum GrandChildChild {
+    GrandGrandChild(GrandGrandChild),
+    None,
+}
+impl GrandChild {
+    pub fn specialize(&self) -> Result<GrandChildChild, DecodeError> {
+        Ok(
+            match (self.baz,) {
+                (Enum16::A,) => GrandChildChild::GrandGrandChild(self.try_into()?),
+                _ => GrandChildChild::None,
+            },
+        )
+    }
+    fn decode_partial(parent: &Child) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.bar() != Enum16::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "GrandChild",
+                field: "bar",
+                expected: "Enum16::A",
+                actual: format!("{:?}", parent.bar()),
+            });
+        }
+        if parent.quux() != Enum16::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "GrandChild",
+                field: "quux",
+                expected: "Enum16::A",
+                actual: format!("{:?}", parent.quux()),
+            });
+        }
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        let payload = Vec::from(payload);
+        if buf.is_empty() {
+            Ok(Self { payload, baz: parent.baz })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn baz(&self) -> Enum16 {
+        self.baz
+    }
+    pub fn quux(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn foo(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn bar(&self) -> Enum16 {
+        Enum16::A
+    }
+}
+impl Packet for GrandChild {
+    fn encoded_len(&self) -> usize {
+        9 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16(u16::from(self.foo()));
+        buf.put_u16(u16::from(self.bar()));
+        buf.put_u16(u16::from(self.baz()));
+        if 2 + self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: 2 + self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 + self.payload.len() as u8);
+        buf.put_u16(u16::from(self.quux()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Child::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct GrandGrandChild {
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&GrandChild> for GrandGrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: &GrandChild) -> Result<GrandGrandChild, Self::Error> {
+        GrandGrandChild::decode_partial(&parent)
+    }
+}
+impl TryFrom<GrandChild> for GrandGrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: GrandChild) -> Result<GrandGrandChild, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&GrandGrandChild> for GrandChild {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<GrandChild, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(GrandChild {
+            baz: Enum16::A,
+            payload,
+        })
+    }
+}
+impl TryFrom<GrandGrandChild> for GrandChild {
+    type Error = EncodeError;
+    fn try_from(packet: GrandGrandChild) -> Result<GrandChild, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl TryFrom<&GrandGrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<Child, Self::Error> {
+        (&GrandChild::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<GrandGrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: GrandGrandChild) -> Result<Child, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl TryFrom<&GrandGrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<Parent, Self::Error> {
+        (&GrandChild::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<GrandGrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: GrandGrandChild) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl GrandGrandChild {
+    fn decode_partial(parent: &GrandChild) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.baz() != Enum16::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "GrandGrandChild",
+                field: "baz",
+                expected: "Enum16::A",
+                actual: format!("{:?}", parent.baz()),
+            });
+        }
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        let payload = Vec::from(payload);
+        if buf.is_empty() {
+            Ok(Self { payload })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn quux(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn foo(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn bar(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn baz(&self) -> Enum16 {
+        Enum16::A
+    }
+}
+impl Packet for GrandGrandChild {
+    fn encoded_len(&self) -> usize {
+        9 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16(u16::from(self.foo()));
+        buf.put_u16(u16::from(self.bar()));
+        buf.put_u16(u16::from(self.baz()));
+        if 2 + self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: 2 + self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 + self.payload.len() as u8);
+        buf.put_u16(u16::from(self.quux()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = GrandChild::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
diff --git a/tests/generated/rust/struct_decl_grand_children_little_endian.rs b/tests/generated/rust/struct_decl_grand_children_little_endian.rs
new file mode 100644
index 0000000..5e638d1
--- /dev/null
+++ b/tests/generated/rust/struct_decl_grand_children_little_endian.rs
@@ -0,0 +1,598 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))]
+pub enum Enum16 {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u16> for Enum16 {
+    type Error = u16;
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Enum16::A),
+            0x2 => Ok(Enum16::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum16> for u16 {
+    fn from(value: &Enum16) -> Self {
+        match value {
+            Enum16::A => 0x1,
+            Enum16::B => 0x2,
+        }
+    }
+}
+impl From<Enum16> for u16 {
+    fn from(value: Enum16) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum16> for i32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for i64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Parent {
+    pub foo: Enum16,
+    pub bar: Enum16,
+    pub baz: Enum16,
+    pub payload: Vec<u8>,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum ParentChild {
+    Child(Child),
+    None,
+}
+impl Parent {
+    pub fn specialize(&self) -> Result<ParentChild, DecodeError> {
+        Ok(
+            match (self.foo,) {
+                (Enum16::A,) => ParentChild::Child(self.try_into()?),
+                _ => ParentChild::None,
+            },
+        )
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn foo(&self) -> Enum16 {
+        self.foo
+    }
+    pub fn bar(&self) -> Enum16 {
+        self.bar
+    }
+    pub fn baz(&self) -> Enum16 {
+        self.baz
+    }
+}
+impl Packet for Parent {
+    fn encoded_len(&self) -> usize {
+        7 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16_le(u16::from(self.foo()));
+        buf.put_u16_le(u16::from(self.bar()));
+        buf.put_u16_le(u16::from(self.baz()));
+        if self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(self.payload.len() as u8);
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let foo = Enum16::try_from(buf.get_u16_le())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "foo",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let bar = Enum16::try_from(buf.get_u16_le())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "bar",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let baz = Enum16::try_from(buf.get_u16_le())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "baz",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let payload_size = buf.get_u8() as usize;
+        if buf.remaining() < payload_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: payload_size,
+                got: buf.remaining(),
+            });
+        }
+        let payload = buf[..payload_size].to_vec();
+        buf.advance(payload_size);
+        let payload = Vec::from(payload);
+        Ok((Self { payload, foo, bar, baz }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Child {
+    pub quux: Enum16,
+    pub bar: Enum16,
+    pub baz: Enum16,
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&Parent> for Child {
+    type Error = DecodeError;
+    fn try_from(parent: &Parent) -> Result<Child, Self::Error> {
+        Child::decode_partial(&parent)
+    }
+}
+impl TryFrom<Parent> for Child {
+    type Error = DecodeError;
+    fn try_from(parent: Parent) -> Result<Child, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&Child> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &Child) -> Result<Parent, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Parent {
+            foo: Enum16::A,
+            bar: packet.bar,
+            baz: packet.baz,
+            payload,
+        })
+    }
+}
+impl TryFrom<Child> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: Child) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum ChildChild {
+    GrandChild(GrandChild),
+    None,
+}
+impl Child {
+    pub fn specialize(&self) -> Result<ChildChild, DecodeError> {
+        Ok(
+            match (self.bar, self.quux) {
+                (Enum16::A, Enum16::A) => ChildChild::GrandChild(self.try_into()?),
+                _ => ChildChild::None,
+            },
+        )
+    }
+    fn decode_partial(parent: &Parent) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.foo() != Enum16::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "Child",
+                field: "foo",
+                expected: "Enum16::A",
+                actual: format!("{:?}", parent.foo()),
+            });
+        }
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Child",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let quux = Enum16::try_from(buf.get_u16_le())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Child",
+                field: "quux",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        let payload = Vec::from(payload);
+        if buf.is_empty() {
+            Ok(Self {
+                payload,
+                quux,
+                bar: parent.bar,
+                baz: parent.baz,
+            })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16_le(u16::from(self.quux()));
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn quux(&self) -> Enum16 {
+        self.quux
+    }
+    pub fn bar(&self) -> Enum16 {
+        self.bar
+    }
+    pub fn baz(&self) -> Enum16 {
+        self.baz
+    }
+    pub fn foo(&self) -> Enum16 {
+        Enum16::A
+    }
+}
+impl Packet for Child {
+    fn encoded_len(&self) -> usize {
+        9 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16_le(u16::from(self.foo()));
+        buf.put_u16_le(u16::from(self.bar()));
+        buf.put_u16_le(u16::from(self.baz()));
+        if 2 + self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: 2 + self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 + self.payload.len() as u8);
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Parent::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct GrandChild {
+    pub baz: Enum16,
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&Child> for GrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: &Child) -> Result<GrandChild, Self::Error> {
+        GrandChild::decode_partial(&parent)
+    }
+}
+impl TryFrom<Child> for GrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: Child) -> Result<GrandChild, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&GrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandChild) -> Result<Child, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Child {
+            quux: Enum16::A,
+            bar: Enum16::A,
+            baz: packet.baz,
+            payload,
+        })
+    }
+}
+impl TryFrom<GrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: GrandChild) -> Result<Child, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl TryFrom<&GrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandChild) -> Result<Parent, Self::Error> {
+        (&Child::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<GrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: GrandChild) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum GrandChildChild {
+    GrandGrandChild(GrandGrandChild),
+    None,
+}
+impl GrandChild {
+    pub fn specialize(&self) -> Result<GrandChildChild, DecodeError> {
+        Ok(
+            match (self.baz,) {
+                (Enum16::A,) => GrandChildChild::GrandGrandChild(self.try_into()?),
+                _ => GrandChildChild::None,
+            },
+        )
+    }
+    fn decode_partial(parent: &Child) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.bar() != Enum16::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "GrandChild",
+                field: "bar",
+                expected: "Enum16::A",
+                actual: format!("{:?}", parent.bar()),
+            });
+        }
+        if parent.quux() != Enum16::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "GrandChild",
+                field: "quux",
+                expected: "Enum16::A",
+                actual: format!("{:?}", parent.quux()),
+            });
+        }
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        let payload = Vec::from(payload);
+        if buf.is_empty() {
+            Ok(Self { payload, baz: parent.baz })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn baz(&self) -> Enum16 {
+        self.baz
+    }
+    pub fn quux(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn foo(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn bar(&self) -> Enum16 {
+        Enum16::A
+    }
+}
+impl Packet for GrandChild {
+    fn encoded_len(&self) -> usize {
+        9 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16_le(u16::from(self.foo()));
+        buf.put_u16_le(u16::from(self.bar()));
+        buf.put_u16_le(u16::from(self.baz()));
+        if 2 + self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: 2 + self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 + self.payload.len() as u8);
+        buf.put_u16_le(u16::from(self.quux()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Child::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct GrandGrandChild {
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&GrandChild> for GrandGrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: &GrandChild) -> Result<GrandGrandChild, Self::Error> {
+        GrandGrandChild::decode_partial(&parent)
+    }
+}
+impl TryFrom<GrandChild> for GrandGrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: GrandChild) -> Result<GrandGrandChild, Self::Error> {
+        (&parent).try_into()
+    }
+}
+impl TryFrom<&GrandGrandChild> for GrandChild {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<GrandChild, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(GrandChild {
+            baz: Enum16::A,
+            payload,
+        })
+    }
+}
+impl TryFrom<GrandGrandChild> for GrandChild {
+    type Error = EncodeError;
+    fn try_from(packet: GrandGrandChild) -> Result<GrandChild, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl TryFrom<&GrandGrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<Child, Self::Error> {
+        (&GrandChild::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<GrandGrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: GrandGrandChild) -> Result<Child, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl TryFrom<&GrandGrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<Parent, Self::Error> {
+        (&GrandChild::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<GrandGrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: GrandGrandChild) -> Result<Parent, Self::Error> {
+        (&packet).try_into()
+    }
+}
+impl GrandGrandChild {
+    fn decode_partial(parent: &GrandChild) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if parent.baz() != Enum16::A {
+            return Err(DecodeError::InvalidFieldValue {
+                packet: "GrandGrandChild",
+                field: "baz",
+                expected: "Enum16::A",
+                actual: format!("{:?}", parent.baz()),
+            });
+        }
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        let payload = Vec::from(payload);
+        if buf.is_empty() {
+            Ok(Self { payload })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn quux(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn foo(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn bar(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn baz(&self) -> Enum16 {
+        Enum16::A
+    }
+}
+impl Packet for GrandGrandChild {
+    fn encoded_len(&self) -> usize {
+        9 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16_le(u16::from(self.foo()));
+        buf.put_u16_le(u16::from(self.bar()));
+        buf.put_u16_le(u16::from(self.baz()));
+        if 2 + self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: 2 + self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 + self.payload.len() as u8);
+        buf.put_u16_le(u16::from(self.quux()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = GrandChild::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
diff --git a/tests/generated/custom_field_declaration_big_endian.rs b/tests/generated/rust_legacy/custom_field_declaration_big_endian.rs
similarity index 81%
rename from tests/generated/custom_field_declaration_big_endian.rs
rename to tests/generated/rust_legacy/custom_field_declaration_big_endian.rs
index eb70e2f..79810e9 100644
--- a/tests/generated/custom_field_declaration_big_endian.rs
+++ b/tests/generated/rust_legacy/custom_field_declaration_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 #[cfg_attr(feature = "serde", serde(from = "u32", into = "u32"))]
@@ -53,7 +58,7 @@
 }
 impl TryFrom<u32> for TruncatedSize {
     type Error = u32;
-    fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
         if value > 0xff_ffff { Err(value) } else { Ok(TruncatedSize(value)) }
     }
 }
diff --git a/tests/generated/custom_field_declaration_big_endian.rs b/tests/generated/rust_legacy/custom_field_declaration_little_endian.rs
similarity index 81%
copy from tests/generated/custom_field_declaration_big_endian.rs
copy to tests/generated/rust_legacy/custom_field_declaration_little_endian.rs
index eb70e2f..79810e9 100644
--- a/tests/generated/custom_field_declaration_big_endian.rs
+++ b/tests/generated/rust_legacy/custom_field_declaration_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 #[cfg_attr(feature = "serde", serde(from = "u32", into = "u32"))]
@@ -53,7 +58,7 @@
 }
 impl TryFrom<u32> for TruncatedSize {
     type Error = u32;
-    fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
         if value > 0xff_ffff { Err(value) } else { Ok(TruncatedSize(value)) }
     }
 }
diff --git a/tests/generated/enum_declaration_big_endian.rs b/tests/generated/rust_legacy/enum_declaration_big_endian.rs
similarity index 95%
copy from tests/generated/enum_declaration_big_endian.rs
copy to tests/generated/rust_legacy/enum_declaration_big_endian.rs
index bd90591..dcff08e 100644
--- a/tests/generated/enum_declaration_big_endian.rs
+++ b/tests/generated/rust_legacy/enum_declaration_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u8> for IncompleteTruncatedClosed {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(IncompleteTruncatedClosed::A),
             0x1 => Ok(IncompleteTruncatedClosed::B),
@@ -94,7 +99,7 @@
 }
 impl TryFrom<u8> for IncompleteTruncatedOpen {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(IncompleteTruncatedOpen::A),
             0x1 => Ok(IncompleteTruncatedOpen::B),
@@ -163,7 +168,7 @@
 }
 impl TryFrom<u8> for IncompleteTruncatedClosedWithRange {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(IncompleteTruncatedClosedWithRange::A),
             0x1 => Ok(IncompleteTruncatedClosedWithRange::X),
@@ -235,7 +240,7 @@
 }
 impl TryFrom<u8> for IncompleteTruncatedOpenWithRange {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(IncompleteTruncatedOpenWithRange::A),
             0x1 => Ok(IncompleteTruncatedOpenWithRange::X),
@@ -313,7 +318,7 @@
 }
 impl TryFrom<u8> for CompleteTruncated {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(CompleteTruncated::A),
             0x1 => Ok(CompleteTruncated::B),
@@ -392,7 +397,7 @@
 }
 impl TryFrom<u8> for CompleteTruncatedWithRange {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(CompleteTruncatedWithRange::A),
             0x1 => Ok(CompleteTruncatedWithRange::X),
@@ -462,7 +467,7 @@
 }
 impl TryFrom<u8> for CompleteWithRange {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(CompleteWithRange::A),
             0x1 => Ok(CompleteWithRange::B),
diff --git a/tests/generated/enum_declaration_big_endian.rs b/tests/generated/rust_legacy/enum_declaration_little_endian.rs
similarity index 95%
copy from tests/generated/enum_declaration_big_endian.rs
copy to tests/generated/rust_legacy/enum_declaration_little_endian.rs
index bd90591..dcff08e 100644
--- a/tests/generated/enum_declaration_big_endian.rs
+++ b/tests/generated/rust_legacy/enum_declaration_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u8> for IncompleteTruncatedClosed {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(IncompleteTruncatedClosed::A),
             0x1 => Ok(IncompleteTruncatedClosed::B),
@@ -94,7 +99,7 @@
 }
 impl TryFrom<u8> for IncompleteTruncatedOpen {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(IncompleteTruncatedOpen::A),
             0x1 => Ok(IncompleteTruncatedOpen::B),
@@ -163,7 +168,7 @@
 }
 impl TryFrom<u8> for IncompleteTruncatedClosedWithRange {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(IncompleteTruncatedClosedWithRange::A),
             0x1 => Ok(IncompleteTruncatedClosedWithRange::X),
@@ -235,7 +240,7 @@
 }
 impl TryFrom<u8> for IncompleteTruncatedOpenWithRange {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(IncompleteTruncatedOpenWithRange::A),
             0x1 => Ok(IncompleteTruncatedOpenWithRange::X),
@@ -313,7 +318,7 @@
 }
 impl TryFrom<u8> for CompleteTruncated {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(CompleteTruncated::A),
             0x1 => Ok(CompleteTruncated::B),
@@ -392,7 +397,7 @@
 }
 impl TryFrom<u8> for CompleteTruncatedWithRange {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(CompleteTruncatedWithRange::A),
             0x1 => Ok(CompleteTruncatedWithRange::X),
@@ -462,7 +467,7 @@
 }
 impl TryFrom<u8> for CompleteWithRange {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(CompleteWithRange::A),
             0x1 => Ok(CompleteWithRange::B),
diff --git a/tests/generated/packet_decl_24bit_enum_array_big_endian.rs b/tests/generated/rust_legacy/packet_decl_24bit_enum_array_big_endian.rs
similarity index 65%
rename from tests/generated/packet_decl_24bit_enum_array_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_24bit_enum_array_big_endian.rs
index d1bba97..d2b9d2f 100644
--- a/tests/generated/packet_decl_24bit_enum_array_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_24bit_enum_array_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u32> for Foo {
     type Error = u32;
-    fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Foo::FooBar),
             0x2 => Ok(Foo::Baz),
@@ -84,15 +89,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 15
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 5 * 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
                 wanted: 5 * 3,
                 got: bytes.get().remaining(),
             });
@@ -100,22 +105,23 @@
         let x = (0..5)
             .map(|_| {
                 Foo::try_from(bytes.get_mut().get_uint(3) as u32)
-                    .map_err(|unknown_val| Error::InvalidEnumValueError {
-                        obj: "Bar".to_string(),
-                        field: String::new(),
+                    .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                        obj: "Bar",
+                        field: "",
                         value: unknown_val as u64,
-                        type_: "Foo".to_string(),
+                        type_: "Foo",
                     })
             })
-            .collect::<Result<Vec<_>>>()?
+            .collect::<Result<Vec<_>, DecodeError>>()?
             .try_into()
-            .map_err(|_| Error::InvalidPacketError)?;
+            .map_err(|_| DecodeError::InvalidPacketError)?;
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         for elem in &self.x {
             buffer.put_uint(u32::from(elem) as u64, 3);
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -125,42 +131,45 @@
     }
 }
 impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.bar.get_size());
-        self.bar.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Bar {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = BarData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(bar: BarData) -> Result<Self> {
+    fn new(bar: BarData) -> Result<Self, DecodeError> {
         Ok(Self { bar })
     }
     pub fn get_x(&self) -> &[Foo; 5] {
         &self.bar.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.bar.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_24bit_enum_array_little_endian.rs b/tests/generated/rust_legacy/packet_decl_24bit_enum_array_little_endian.rs
similarity index 65%
rename from tests/generated/packet_decl_24bit_enum_array_little_endian.rs
rename to tests/generated/rust_legacy/packet_decl_24bit_enum_array_little_endian.rs
index 9a48b4b..c7e2ba2 100644
--- a/tests/generated/packet_decl_24bit_enum_array_little_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_24bit_enum_array_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u32> for Foo {
     type Error = u32;
-    fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Foo::FooBar),
             0x2 => Ok(Foo::Baz),
@@ -84,15 +89,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 15
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 5 * 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
                 wanted: 5 * 3,
                 got: bytes.get().remaining(),
             });
@@ -100,22 +105,23 @@
         let x = (0..5)
             .map(|_| {
                 Foo::try_from(bytes.get_mut().get_uint_le(3) as u32)
-                    .map_err(|unknown_val| Error::InvalidEnumValueError {
-                        obj: "Bar".to_string(),
-                        field: String::new(),
+                    .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                        obj: "Bar",
+                        field: "",
                         value: unknown_val as u64,
-                        type_: "Foo".to_string(),
+                        type_: "Foo",
                     })
             })
-            .collect::<Result<Vec<_>>>()?
+            .collect::<Result<Vec<_>, DecodeError>>()?
             .try_into()
-            .map_err(|_| Error::InvalidPacketError)?;
+            .map_err(|_| DecodeError::InvalidPacketError)?;
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         for elem in &self.x {
             buffer.put_uint_le(u32::from(elem) as u64, 3);
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -125,42 +131,45 @@
     }
 }
 impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.bar.get_size());
-        self.bar.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Bar {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = BarData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(bar: BarData) -> Result<Self> {
+    fn new(bar: BarData) -> Result<Self, DecodeError> {
         Ok(Self { bar })
     }
     pub fn get_x(&self) -> &[Foo; 5] {
         &self.bar.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.bar.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_24bit_enum_big_endian.rs b/tests/generated/rust_legacy/packet_decl_24bit_enum_big_endian.rs
similarity index 66%
rename from tests/generated/packet_decl_24bit_enum_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_24bit_enum_big_endian.rs
index 64b6a81..38a7066 100644
--- a/tests/generated/packet_decl_24bit_enum_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_24bit_enum_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u32> for Foo {
     type Error = u32;
-    fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Foo::A),
             0x2 => Ok(Foo::B),
@@ -84,30 +89,31 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 3
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
                 wanted: 3,
                 got: bytes.get().remaining(),
             });
         }
         let x = Foo::try_from(bytes.get_mut().get_uint(3) as u32)
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Bar".to_string(),
-                field: "x".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Bar",
+                field: "x",
                 value: unknown_val as u64,
-                type_: "Foo".to_string(),
+                type_: "Foo",
             })?;
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_uint(u32::from(self.x) as u64, 3);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -117,42 +123,45 @@
     }
 }
 impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.bar.get_size());
-        self.bar.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Bar {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = BarData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(bar: BarData) -> Result<Self> {
+    fn new(bar: BarData) -> Result<Self, DecodeError> {
         Ok(Self { bar })
     }
     pub fn get_x(&self) -> Foo {
         self.bar.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.bar.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_24bit_enum_little_endian.rs b/tests/generated/rust_legacy/packet_decl_24bit_enum_little_endian.rs
similarity index 66%
rename from tests/generated/packet_decl_24bit_enum_little_endian.rs
rename to tests/generated/rust_legacy/packet_decl_24bit_enum_little_endian.rs
index cd916a7..0a0818b 100644
--- a/tests/generated/packet_decl_24bit_enum_little_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_24bit_enum_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u32> for Foo {
     type Error = u32;
-    fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Foo::A),
             0x2 => Ok(Foo::B),
@@ -84,30 +89,31 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 3
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
                 wanted: 3,
                 got: bytes.get().remaining(),
             });
         }
         let x = Foo::try_from(bytes.get_mut().get_uint_le(3) as u32)
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Bar".to_string(),
-                field: "x".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Bar",
+                field: "x",
                 value: unknown_val as u64,
-                type_: "Foo".to_string(),
+                type_: "Foo",
             })?;
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_uint_le(u32::from(self.x) as u64, 3);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -117,42 +123,45 @@
     }
 }
 impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.bar.get_size());
-        self.bar.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Bar {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = BarData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(bar: BarData) -> Result<Self> {
+    fn new(bar: BarData) -> Result<Self, DecodeError> {
         Ok(Self { bar })
     }
     pub fn get_x(&self) -> Foo {
         self.bar.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.bar.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/rust_legacy/packet_decl_24bit_scalar_array_big_endian.rs b/tests/generated/rust_legacy/packet_decl_24bit_scalar_array_big_endian.rs
new file mode 100644
index 0000000..53692ce
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_24bit_scalar_array_big_endian.rs
@@ -0,0 +1,135 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {
+    x: [u32; 5],
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {
+    pub x: [u32; 5],
+}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 15
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 5 * 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 5 * 3,
+                got: bytes.get().remaining(),
+            });
+        }
+        let x = (0..5)
+            .map(|_| Ok::<_, DecodeError>(bytes.get_mut().get_uint(3) as u32))
+            .collect::<Result<Vec<_>, DecodeError>>()?
+            .try_into()
+            .map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok(Self { x })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        for elem in &self.x {
+            buffer.put_uint(*elem as u64, 3);
+        }
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        15
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    pub fn get_x(&self) -> &[u32; 5] {
+        &self.foo.x
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData { x: self.x };
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/rust_legacy/packet_decl_24bit_scalar_array_little_endian.rs b/tests/generated/rust_legacy/packet_decl_24bit_scalar_array_little_endian.rs
new file mode 100644
index 0000000..69758a1
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_24bit_scalar_array_little_endian.rs
@@ -0,0 +1,135 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {
+    x: [u32; 5],
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {
+    pub x: [u32; 5],
+}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 15
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 5 * 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 5 * 3,
+                got: bytes.get().remaining(),
+            });
+        }
+        let x = (0..5)
+            .map(|_| Ok::<_, DecodeError>(bytes.get_mut().get_uint_le(3) as u32))
+            .collect::<Result<Vec<_>, DecodeError>>()?
+            .try_into()
+            .map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok(Self { x })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        for elem in &self.x {
+            buffer.put_uint_le(*elem as u64, 3);
+        }
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        15
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    pub fn get_x(&self) -> &[u32; 5] {
+        &self.foo.x
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData { x: self.x };
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/rust_legacy/packet_decl_24bit_scalar_big_endian.rs b/tests/generated/rust_legacy/packet_decl_24bit_scalar_big_endian.rs
new file mode 100644
index 0000000..45b5b29
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_24bit_scalar_big_endian.rs
@@ -0,0 +1,137 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {
+    x: u32,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {
+    pub x: u32,
+}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 3
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: bytes.get().remaining(),
+            });
+        }
+        let x = bytes.get_mut().get_uint(3) as u32;
+        Ok(Self { x })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        if self.x > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "x",
+                value: self.x as u64,
+                maximum_value: 0xff_ffff,
+            });
+        }
+        buffer.put_uint(self.x as u64, 3);
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        3
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    pub fn get_x(&self) -> u32 {
+        self.foo.x
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData { x: self.x };
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/rust_legacy/packet_decl_24bit_scalar_little_endian.rs b/tests/generated/rust_legacy/packet_decl_24bit_scalar_little_endian.rs
new file mode 100644
index 0000000..04e6057
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_24bit_scalar_little_endian.rs
@@ -0,0 +1,137 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {
+    x: u32,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {
+    pub x: u32,
+}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 3
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: bytes.get().remaining(),
+            });
+        }
+        let x = bytes.get_mut().get_uint_le(3) as u32;
+        Ok(Self { x })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        if self.x > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "x",
+                value: self.x as u64,
+                maximum_value: 0xff_ffff,
+            });
+        }
+        buffer.put_uint_le(self.x as u64, 3);
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        3
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    pub fn get_x(&self) -> u32 {
+        self.foo.x
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData { x: self.x };
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/packet_decl_64bit_enum_array_big_endian.rs b/tests/generated/rust_legacy/packet_decl_64bit_enum_array_big_endian.rs
similarity index 63%
rename from tests/generated/packet_decl_64bit_enum_array_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_64bit_enum_array_big_endian.rs
index fce2ae1..d0a6e8f 100644
--- a/tests/generated/packet_decl_64bit_enum_array_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_64bit_enum_array_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u64> for Foo {
     type Error = u64;
-    fn try_from(value: u64) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u64) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Foo::FooBar),
             0x2 => Ok(Foo::Baz),
@@ -69,15 +74,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 56
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 7 * 8 {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
                 wanted: 7 * 8,
                 got: bytes.get().remaining(),
             });
@@ -85,22 +90,23 @@
         let x = (0..7)
             .map(|_| {
                 Foo::try_from(bytes.get_mut().get_u64())
-                    .map_err(|unknown_val| Error::InvalidEnumValueError {
-                        obj: "Bar".to_string(),
-                        field: String::new(),
+                    .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                        obj: "Bar",
+                        field: "",
                         value: unknown_val as u64,
-                        type_: "Foo".to_string(),
+                        type_: "Foo",
                     })
             })
-            .collect::<Result<Vec<_>>>()?
+            .collect::<Result<Vec<_>, DecodeError>>()?
             .try_into()
-            .map_err(|_| Error::InvalidPacketError)?;
+            .map_err(|_| DecodeError::InvalidPacketError)?;
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         for elem in &self.x {
             buffer.put_u64(u64::from(elem));
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -110,42 +116,45 @@
     }
 }
 impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.bar.get_size());
-        self.bar.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Bar {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = BarData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(bar: BarData) -> Result<Self> {
+    fn new(bar: BarData) -> Result<Self, DecodeError> {
         Ok(Self { bar })
     }
     pub fn get_x(&self) -> &[Foo; 7] {
         &self.bar.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.bar.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_64bit_enum_array_little_endian.rs b/tests/generated/rust_legacy/packet_decl_64bit_enum_array_little_endian.rs
similarity index 63%
rename from tests/generated/packet_decl_64bit_enum_array_little_endian.rs
rename to tests/generated/rust_legacy/packet_decl_64bit_enum_array_little_endian.rs
index 8d7c2a1..e8fd91f 100644
--- a/tests/generated/packet_decl_64bit_enum_array_little_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_64bit_enum_array_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u64> for Foo {
     type Error = u64;
-    fn try_from(value: u64) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u64) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Foo::FooBar),
             0x2 => Ok(Foo::Baz),
@@ -69,15 +74,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 56
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 7 * 8 {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
                 wanted: 7 * 8,
                 got: bytes.get().remaining(),
             });
@@ -85,22 +90,23 @@
         let x = (0..7)
             .map(|_| {
                 Foo::try_from(bytes.get_mut().get_u64_le())
-                    .map_err(|unknown_val| Error::InvalidEnumValueError {
-                        obj: "Bar".to_string(),
-                        field: String::new(),
+                    .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                        obj: "Bar",
+                        field: "",
                         value: unknown_val as u64,
-                        type_: "Foo".to_string(),
+                        type_: "Foo",
                     })
             })
-            .collect::<Result<Vec<_>>>()?
+            .collect::<Result<Vec<_>, DecodeError>>()?
             .try_into()
-            .map_err(|_| Error::InvalidPacketError)?;
+            .map_err(|_| DecodeError::InvalidPacketError)?;
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         for elem in &self.x {
             buffer.put_u64_le(u64::from(elem));
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -110,42 +116,45 @@
     }
 }
 impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.bar.get_size());
-        self.bar.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Bar {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = BarData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(bar: BarData) -> Result<Self> {
+    fn new(bar: BarData) -> Result<Self, DecodeError> {
         Ok(Self { bar })
     }
     pub fn get_x(&self) -> &[Foo; 7] {
         &self.bar.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.bar.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_64bit_enum_big_endian.rs b/tests/generated/rust_legacy/packet_decl_64bit_enum_big_endian.rs
similarity index 64%
rename from tests/generated/packet_decl_64bit_enum_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_64bit_enum_big_endian.rs
index 2a0c784..b1bd38b 100644
--- a/tests/generated/packet_decl_64bit_enum_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_64bit_enum_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u64> for Foo {
     type Error = u64;
-    fn try_from(value: u64) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u64) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Foo::A),
             0x2 => Ok(Foo::B),
@@ -69,30 +74,31 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 8
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 8 {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
                 wanted: 8,
                 got: bytes.get().remaining(),
             });
         }
         let x = Foo::try_from(bytes.get_mut().get_u64())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Bar".to_string(),
-                field: "x".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Bar",
+                field: "x",
                 value: unknown_val as u64,
-                type_: "Foo".to_string(),
+                type_: "Foo",
             })?;
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u64(u64::from(self.x));
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -102,42 +108,45 @@
     }
 }
 impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.bar.get_size());
-        self.bar.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Bar {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = BarData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(bar: BarData) -> Result<Self> {
+    fn new(bar: BarData) -> Result<Self, DecodeError> {
         Ok(Self { bar })
     }
     pub fn get_x(&self) -> Foo {
         self.bar.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.bar.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_64bit_enum_little_endian.rs b/tests/generated/rust_legacy/packet_decl_64bit_enum_little_endian.rs
similarity index 64%
rename from tests/generated/packet_decl_64bit_enum_little_endian.rs
rename to tests/generated/rust_legacy/packet_decl_64bit_enum_little_endian.rs
index 0fcaa48..a472b7f 100644
--- a/tests/generated/packet_decl_64bit_enum_little_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_64bit_enum_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u64> for Foo {
     type Error = u64;
-    fn try_from(value: u64) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u64) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Foo::A),
             0x2 => Ok(Foo::B),
@@ -69,30 +74,31 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 8
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 8 {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
                 wanted: 8,
                 got: bytes.get().remaining(),
             });
         }
         let x = Foo::try_from(bytes.get_mut().get_u64_le())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Bar".to_string(),
-                field: "x".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Bar",
+                field: "x",
                 value: unknown_val as u64,
-                type_: "Foo".to_string(),
+                type_: "Foo",
             })?;
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u64_le(u64::from(self.x));
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -102,42 +108,45 @@
     }
 }
 impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.bar.get_size());
-        self.bar.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Bar {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = BarData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(bar: BarData) -> Result<Self> {
+    fn new(bar: BarData) -> Result<Self, DecodeError> {
         Ok(Self { bar })
     }
     pub fn get_x(&self) -> Foo {
         self.bar.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.bar.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/rust_legacy/packet_decl_64bit_scalar_array_big_endian.rs b/tests/generated/rust_legacy/packet_decl_64bit_scalar_array_big_endian.rs
new file mode 100644
index 0000000..83d690e
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_64bit_scalar_array_big_endian.rs
@@ -0,0 +1,135 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {
+    x: [u64; 7],
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {
+    pub x: [u64; 7],
+}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 56
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 7 * 8 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 7 * 8,
+                got: bytes.get().remaining(),
+            });
+        }
+        let x = (0..7)
+            .map(|_| Ok::<_, DecodeError>(bytes.get_mut().get_u64()))
+            .collect::<Result<Vec<_>, DecodeError>>()?
+            .try_into()
+            .map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok(Self { x })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        for elem in &self.x {
+            buffer.put_u64(*elem);
+        }
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        56
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    pub fn get_x(&self) -> &[u64; 7] {
+        &self.foo.x
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData { x: self.x };
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/rust_legacy/packet_decl_64bit_scalar_array_little_endian.rs b/tests/generated/rust_legacy/packet_decl_64bit_scalar_array_little_endian.rs
new file mode 100644
index 0000000..85b05df
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_64bit_scalar_array_little_endian.rs
@@ -0,0 +1,135 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {
+    x: [u64; 7],
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {
+    pub x: [u64; 7],
+}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 56
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 7 * 8 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 7 * 8,
+                got: bytes.get().remaining(),
+            });
+        }
+        let x = (0..7)
+            .map(|_| Ok::<_, DecodeError>(bytes.get_mut().get_u64_le()))
+            .collect::<Result<Vec<_>, DecodeError>>()?
+            .try_into()
+            .map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok(Self { x })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        for elem in &self.x {
+            buffer.put_u64_le(*elem);
+        }
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        56
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    pub fn get_x(&self) -> &[u64; 7] {
+        &self.foo.x
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData { x: self.x };
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/packet_decl_64bit_scalar_big_endian.rs b/tests/generated/rust_legacy/packet_decl_64bit_scalar_big_endian.rs
similarity index 60%
rename from tests/generated/packet_decl_64bit_scalar_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_64bit_scalar_big_endian.rs
index e067fac..2d3e07d 100644
--- a/tests/generated/packet_decl_64bit_scalar_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_64bit_scalar_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub struct FooData {
@@ -38,15 +43,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 8
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 8 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 8,
                 got: bytes.get().remaining(),
             });
@@ -54,8 +59,9 @@
         let x = bytes.get_mut().get_u64();
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u64(self.x);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -65,42 +71,45 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_x(&self) -> u64 {
         self.foo.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_64bit_scalar_little_endian.rs b/tests/generated/rust_legacy/packet_decl_64bit_scalar_little_endian.rs
similarity index 60%
rename from tests/generated/packet_decl_64bit_scalar_little_endian.rs
rename to tests/generated/rust_legacy/packet_decl_64bit_scalar_little_endian.rs
index 815d0b1..37bf6bd 100644
--- a/tests/generated/packet_decl_64bit_scalar_little_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_64bit_scalar_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub struct FooData {
@@ -38,15 +43,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 8
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 8 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 8,
                 got: bytes.get().remaining(),
             });
@@ -54,8 +59,9 @@
         let x = bytes.get_mut().get_u64_le();
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u64_le(self.x);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -65,42 +71,45 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_x(&self) -> u64 {
         self.foo.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_8bit_enum_array_big_endian.rs b/tests/generated/rust_legacy/packet_decl_8bit_enum_array_big_endian.rs
similarity index 67%
rename from tests/generated/packet_decl_8bit_enum_array_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_8bit_enum_array_big_endian.rs
index ba959a6..4af419c 100644
--- a/tests/generated/packet_decl_8bit_enum_array_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_8bit_enum_array_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u8> for Foo {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Foo::FooBar),
             0x2 => Ok(Foo::Baz),
@@ -99,15 +104,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 3
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
                 wanted: 3,
                 got: bytes.get().remaining(),
             });
@@ -115,22 +120,23 @@
         let x = (0..3)
             .map(|_| {
                 Foo::try_from(bytes.get_mut().get_u8())
-                    .map_err(|unknown_val| Error::InvalidEnumValueError {
-                        obj: "Bar".to_string(),
-                        field: String::new(),
+                    .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                        obj: "Bar",
+                        field: "",
                         value: unknown_val as u64,
-                        type_: "Foo".to_string(),
+                        type_: "Foo",
                     })
             })
-            .collect::<Result<Vec<_>>>()?
+            .collect::<Result<Vec<_>, DecodeError>>()?
             .try_into()
-            .map_err(|_| Error::InvalidPacketError)?;
+            .map_err(|_| DecodeError::InvalidPacketError)?;
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         for elem in &self.x {
             buffer.put_u8(u8::from(elem));
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -140,42 +146,45 @@
     }
 }
 impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.bar.get_size());
-        self.bar.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Bar {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = BarData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(bar: BarData) -> Result<Self> {
+    fn new(bar: BarData) -> Result<Self, DecodeError> {
         Ok(Self { bar })
     }
     pub fn get_x(&self) -> &[Foo; 3] {
         &self.bar.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.bar.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_8bit_enum_array_little_endian.rs b/tests/generated/rust_legacy/packet_decl_8bit_enum_array_little_endian.rs
similarity index 67%
rename from tests/generated/packet_decl_8bit_enum_array_little_endian.rs
rename to tests/generated/rust_legacy/packet_decl_8bit_enum_array_little_endian.rs
index ba959a6..4af419c 100644
--- a/tests/generated/packet_decl_8bit_enum_array_little_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_8bit_enum_array_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u8> for Foo {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Foo::FooBar),
             0x2 => Ok(Foo::Baz),
@@ -99,15 +104,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 3
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
                 wanted: 3,
                 got: bytes.get().remaining(),
             });
@@ -115,22 +120,23 @@
         let x = (0..3)
             .map(|_| {
                 Foo::try_from(bytes.get_mut().get_u8())
-                    .map_err(|unknown_val| Error::InvalidEnumValueError {
-                        obj: "Bar".to_string(),
-                        field: String::new(),
+                    .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                        obj: "Bar",
+                        field: "",
                         value: unknown_val as u64,
-                        type_: "Foo".to_string(),
+                        type_: "Foo",
                     })
             })
-            .collect::<Result<Vec<_>>>()?
+            .collect::<Result<Vec<_>, DecodeError>>()?
             .try_into()
-            .map_err(|_| Error::InvalidPacketError)?;
+            .map_err(|_| DecodeError::InvalidPacketError)?;
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         for elem in &self.x {
             buffer.put_u8(u8::from(elem));
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -140,42 +146,45 @@
     }
 }
 impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.bar.get_size());
-        self.bar.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Bar {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = BarData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(bar: BarData) -> Result<Self> {
+    fn new(bar: BarData) -> Result<Self, DecodeError> {
         Ok(Self { bar })
     }
     pub fn get_x(&self) -> &[Foo; 3] {
         &self.bar.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.bar.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_8bit_enum_big_endian.rs b/tests/generated/rust_legacy/packet_decl_8bit_enum_big_endian.rs
similarity index 67%
rename from tests/generated/packet_decl_8bit_enum_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_8bit_enum_big_endian.rs
index 03bec5d..3278fb5 100644
--- a/tests/generated/packet_decl_8bit_enum_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_8bit_enum_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u8> for Foo {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Foo::A),
             0x2 => Ok(Foo::B),
@@ -99,30 +104,31 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 1
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
         }
         let x = Foo::try_from(bytes.get_mut().get_u8())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Bar".to_string(),
-                field: "x".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Bar",
+                field: "x",
                 value: unknown_val as u64,
-                type_: "Foo".to_string(),
+                type_: "Foo",
             })?;
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u8(u8::from(self.x));
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -132,42 +138,45 @@
     }
 }
 impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.bar.get_size());
-        self.bar.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Bar {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = BarData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(bar: BarData) -> Result<Self> {
+    fn new(bar: BarData) -> Result<Self, DecodeError> {
         Ok(Self { bar })
     }
     pub fn get_x(&self) -> Foo {
         self.bar.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.bar.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_8bit_enum_big_endian.rs b/tests/generated/rust_legacy/packet_decl_8bit_enum_little_endian.rs
similarity index 67%
copy from tests/generated/packet_decl_8bit_enum_big_endian.rs
copy to tests/generated/rust_legacy/packet_decl_8bit_enum_little_endian.rs
index 03bec5d..3278fb5 100644
--- a/tests/generated/packet_decl_8bit_enum_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_8bit_enum_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u8> for Foo {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Foo::A),
             0x2 => Ok(Foo::B),
@@ -99,30 +104,31 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 1
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
         }
         let x = Foo::try_from(bytes.get_mut().get_u8())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Bar".to_string(),
-                field: "x".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Bar",
+                field: "x",
                 value: unknown_val as u64,
-                type_: "Foo".to_string(),
+                type_: "Foo",
             })?;
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u8(u8::from(self.x));
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -132,42 +138,45 @@
     }
 }
 impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.bar.get_size());
-        self.bar.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Bar {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = BarData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(bar: BarData) -> Result<Self> {
+    fn new(bar: BarData) -> Result<Self, DecodeError> {
         Ok(Self { bar })
     }
     pub fn get_x(&self) -> Foo {
         self.bar.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.bar.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/rust_legacy/packet_decl_8bit_scalar_array_big_endian.rs b/tests/generated/rust_legacy/packet_decl_8bit_scalar_array_big_endian.rs
new file mode 100644
index 0000000..4cbe85e
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_8bit_scalar_array_big_endian.rs
@@ -0,0 +1,135 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {
+    x: [u8; 3],
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {
+    pub x: [u8; 3],
+}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 3
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: bytes.get().remaining(),
+            });
+        }
+        let x = (0..3)
+            .map(|_| Ok::<_, DecodeError>(bytes.get_mut().get_u8()))
+            .collect::<Result<Vec<_>, DecodeError>>()?
+            .try_into()
+            .map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok(Self { x })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        for elem in &self.x {
+            buffer.put_u8(*elem);
+        }
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        3
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    pub fn get_x(&self) -> &[u8; 3] {
+        &self.foo.x
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData { x: self.x };
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/rust_legacy/packet_decl_8bit_scalar_array_little_endian.rs b/tests/generated/rust_legacy/packet_decl_8bit_scalar_array_little_endian.rs
new file mode 100644
index 0000000..4cbe85e
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_8bit_scalar_array_little_endian.rs
@@ -0,0 +1,135 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {
+    x: [u8; 3],
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {
+    pub x: [u8; 3],
+}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 3
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: bytes.get().remaining(),
+            });
+        }
+        let x = (0..3)
+            .map(|_| Ok::<_, DecodeError>(bytes.get_mut().get_u8()))
+            .collect::<Result<Vec<_>, DecodeError>>()?
+            .try_into()
+            .map_err(|_| DecodeError::InvalidPacketError)?;
+        Ok(Self { x })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        for elem in &self.x {
+            buffer.put_u8(*elem);
+        }
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        3
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    pub fn get_x(&self) -> &[u8; 3] {
+        &self.foo.x
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData { x: self.x };
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/packet_decl_8bit_scalar_big_endian.rs b/tests/generated/rust_legacy/packet_decl_8bit_scalar_big_endian.rs
similarity index 60%
rename from tests/generated/packet_decl_8bit_scalar_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_8bit_scalar_big_endian.rs
index de13f31..27089b2 100644
--- a/tests/generated/packet_decl_8bit_scalar_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_8bit_scalar_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub struct FooData {
@@ -38,15 +43,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 1
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
@@ -54,8 +59,9 @@
         let x = bytes.get_mut().get_u8();
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u8(self.x);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -65,42 +71,45 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_x(&self) -> u8 {
         self.foo.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_8bit_scalar_big_endian.rs b/tests/generated/rust_legacy/packet_decl_8bit_scalar_little_endian.rs
similarity index 60%
copy from tests/generated/packet_decl_8bit_scalar_big_endian.rs
copy to tests/generated/rust_legacy/packet_decl_8bit_scalar_little_endian.rs
index de13f31..27089b2 100644
--- a/tests/generated/packet_decl_8bit_scalar_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_8bit_scalar_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub struct FooData {
@@ -38,15 +43,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 1
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
@@ -54,8 +59,9 @@
         let x = bytes.get_mut().get_u8();
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u8(self.x);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -65,42 +71,45 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_x(&self) -> u8 {
         self.foo.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/rust_legacy/packet_decl_array_dynamic_count_big_endian.rs b/tests/generated/rust_legacy/packet_decl_array_dynamic_count_big_endian.rs
new file mode 100644
index 0000000..b8a5124
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_array_dynamic_count_big_endian.rs
@@ -0,0 +1,169 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {
+    padding: u8,
+    x: Vec<u32>,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {
+    pub padding: u8,
+    pub x: Vec<u32>,
+}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 1
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: bytes.get().remaining(),
+            });
+        }
+        let chunk = bytes.get_mut().get_u8();
+        let x_count = (chunk & 0x1f) as usize;
+        let padding = ((chunk >> 5) & 0x7);
+        if bytes.get().remaining() < x_count * 3usize {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: x_count * 3usize,
+                got: bytes.get().remaining(),
+            });
+        }
+        let x = (0..x_count)
+            .map(|_| Ok::<_, DecodeError>(bytes.get_mut().get_uint(3) as u32))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        Ok(Self { padding, x })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        if self.x.len() > 0x1f {
+            return Err(EncodeError::CountOverflow {
+                packet: "Foo",
+                field: "x",
+                count: self.x.len(),
+                maximum_count: 0x1f,
+            });
+        }
+        if self.padding > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "padding",
+                value: self.padding as u64,
+                maximum_value: 0x7,
+            });
+        }
+        let value = self.x.len() as u8 | (self.padding << 5);
+        buffer.put_u8(value);
+        for elem in &self.x {
+            buffer.put_uint(*elem as u64, 3);
+        }
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        1 + self.x.len() * 3
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    pub fn get_padding(&self) -> u8 {
+        self.foo.padding
+    }
+    pub fn get_x(&self) -> &Vec<u32> {
+        &self.foo.x
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData {
+            padding: self.padding,
+            x: self.x,
+        };
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/rust_legacy/packet_decl_array_dynamic_count_little_endian.rs b/tests/generated/rust_legacy/packet_decl_array_dynamic_count_little_endian.rs
new file mode 100644
index 0000000..dd02c56
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_array_dynamic_count_little_endian.rs
@@ -0,0 +1,169 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {
+    padding: u8,
+    x: Vec<u32>,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {
+    pub padding: u8,
+    pub x: Vec<u32>,
+}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 1
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: bytes.get().remaining(),
+            });
+        }
+        let chunk = bytes.get_mut().get_u8();
+        let x_count = (chunk & 0x1f) as usize;
+        let padding = ((chunk >> 5) & 0x7);
+        if bytes.get().remaining() < x_count * 3usize {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: x_count * 3usize,
+                got: bytes.get().remaining(),
+            });
+        }
+        let x = (0..x_count)
+            .map(|_| Ok::<_, DecodeError>(bytes.get_mut().get_uint_le(3) as u32))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        Ok(Self { padding, x })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        if self.x.len() > 0x1f {
+            return Err(EncodeError::CountOverflow {
+                packet: "Foo",
+                field: "x",
+                count: self.x.len(),
+                maximum_count: 0x1f,
+            });
+        }
+        if self.padding > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "padding",
+                value: self.padding as u64,
+                maximum_value: 0x7,
+            });
+        }
+        let value = self.x.len() as u8 | (self.padding << 5);
+        buffer.put_u8(value);
+        for elem in &self.x {
+            buffer.put_uint_le(*elem as u64, 3);
+        }
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        1 + self.x.len() * 3
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    pub fn get_padding(&self) -> u8 {
+        self.foo.padding
+    }
+    pub fn get_x(&self) -> &Vec<u32> {
+        &self.foo.x
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData {
+            padding: self.padding,
+            x: self.x,
+        };
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/packet_decl_array_dynamic_size_big_endian.rs b/tests/generated/rust_legacy/packet_decl_array_dynamic_size_big_endian.rs
similarity index 60%
rename from tests/generated/packet_decl_array_dynamic_size_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_array_dynamic_size_big_endian.rs
index a4899a1..3616fe5 100644
--- a/tests/generated/packet_decl_array_dynamic_size_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_array_dynamic_size_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub struct FooData {
@@ -40,15 +45,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 1
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
@@ -57,14 +62,14 @@
         let x_size = (chunk & 0x1f) as usize;
         let padding = ((chunk >> 5) & 0x7);
         if bytes.get().remaining() < x_size {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: x_size,
                 got: bytes.get().remaining(),
             });
         }
         if x_size % 3 != 0 {
-            return Err(Error::InvalidArraySize {
+            return Err(DecodeError::InvalidArraySize {
                 array: x_size,
                 element: 3,
             });
@@ -72,27 +77,33 @@
         let x_count = x_size / 3;
         let mut x = Vec::with_capacity(x_count);
         for _ in 0..x_count {
-            x.push(Ok::<_, Error>(bytes.get_mut().get_uint(3) as u32)?);
+            x.push(Ok::<_, DecodeError>(bytes.get_mut().get_uint(3) as u32)?);
         }
         Ok(Self { padding, x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         if (self.x.len() * 3) > 0x1f {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Foo", "x", (self.x.len() * 3),
-                0x1f
-            );
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "x",
+                size: (self.x.len() * 3),
+                maximum_size: 0x1f,
+            });
         }
         if self.padding > 0x7 {
-            panic!(
-                "Invalid value for {}::{}: {} > {}", "Foo", "padding", self.padding, 0x7
-            );
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "padding",
+                value: self.padding as u64,
+                maximum_value: 0x7,
+            });
         }
         let value = (self.x.len() * 3) as u8 | (self.padding << 5);
         buffer.put_u8(value);
         for elem in &self.x {
             buffer.put_uint(*elem as u64, 3);
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -102,36 +113,39 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_padding(&self) -> u8 {
@@ -140,7 +154,7 @@
     pub fn get_x(&self) -> &Vec<u32> {
         &self.foo.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_array_dynamic_size_little_endian.rs b/tests/generated/rust_legacy/packet_decl_array_dynamic_size_little_endian.rs
similarity index 60%
rename from tests/generated/packet_decl_array_dynamic_size_little_endian.rs
rename to tests/generated/rust_legacy/packet_decl_array_dynamic_size_little_endian.rs
index d048bfc..a5f3406 100644
--- a/tests/generated/packet_decl_array_dynamic_size_little_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_array_dynamic_size_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub struct FooData {
@@ -40,15 +45,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 1
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
@@ -57,14 +62,14 @@
         let x_size = (chunk & 0x1f) as usize;
         let padding = ((chunk >> 5) & 0x7);
         if bytes.get().remaining() < x_size {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: x_size,
                 got: bytes.get().remaining(),
             });
         }
         if x_size % 3 != 0 {
-            return Err(Error::InvalidArraySize {
+            return Err(DecodeError::InvalidArraySize {
                 array: x_size,
                 element: 3,
             });
@@ -72,27 +77,33 @@
         let x_count = x_size / 3;
         let mut x = Vec::with_capacity(x_count);
         for _ in 0..x_count {
-            x.push(Ok::<_, Error>(bytes.get_mut().get_uint_le(3) as u32)?);
+            x.push(Ok::<_, DecodeError>(bytes.get_mut().get_uint_le(3) as u32)?);
         }
         Ok(Self { padding, x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         if (self.x.len() * 3) > 0x1f {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Foo", "x", (self.x.len() * 3),
-                0x1f
-            );
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "x",
+                size: (self.x.len() * 3),
+                maximum_size: 0x1f,
+            });
         }
         if self.padding > 0x7 {
-            panic!(
-                "Invalid value for {}::{}: {} > {}", "Foo", "padding", self.padding, 0x7
-            );
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "padding",
+                value: self.padding as u64,
+                maximum_value: 0x7,
+            });
         }
         let value = (self.x.len() * 3) as u8 | (self.padding << 5);
         buffer.put_u8(value);
         for elem in &self.x {
             buffer.put_uint_le(*elem as u64, 3);
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -102,36 +113,39 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_padding(&self) -> u8 {
@@ -140,7 +154,7 @@
     pub fn get_x(&self) -> &Vec<u32> {
         &self.foo.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/rust_legacy/packet_decl_array_unknown_element_width_dynamic_count_big_endian.rs b/tests/generated/rust_legacy/packet_decl_array_unknown_element_width_dynamic_count_big_endian.rs
new file mode 100644
index 0000000..09ee1ca
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_array_unknown_element_width_dynamic_count_big_endian.rs
@@ -0,0 +1,200 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: Vec<u16>,
+}
+impl Foo {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 5
+    }
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 5,
+                got: bytes.get().remaining(),
+            });
+        }
+        let a_count = bytes.get_mut().get_uint(5) as usize;
+        if bytes.get().remaining() < a_count * 2usize {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: a_count * 2usize,
+                got: bytes.get().remaining(),
+            });
+        }
+        let a = (0..a_count)
+            .map(|_| Ok::<_, DecodeError>(bytes.get_mut().get_u16()))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        Ok(Self { a })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        if self.a.len() > 0xff_ffff_ffff_usize {
+            return Err(EncodeError::CountOverflow {
+                packet: "Foo",
+                field: "a",
+                count: self.a.len(),
+                maximum_count: 0xff_ffff_ffff_usize,
+            });
+        }
+        buffer.put_uint(self.a.len() as u64, 5);
+        for elem in &self.a {
+            buffer.put_u16(*elem);
+        }
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        5 + self.a.len() * 2
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct BarData {
+    x: Vec<Foo>,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    bar: BarData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct BarBuilder {
+    pub x: Vec<Foo>,
+}
+impl BarData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 5
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 5,
+                got: bytes.get().remaining(),
+            });
+        }
+        let x_count = bytes.get_mut().get_uint(5) as usize;
+        let x = (0..x_count)
+            .map(|_| Foo::parse_inner(bytes))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        Ok(Self { x })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        if self.x.len() > 0xff_ffff_ffff_usize {
+            return Err(EncodeError::CountOverflow {
+                packet: "Bar",
+                field: "x",
+                count: self.x.len(),
+                maximum_count: 0xff_ffff_ffff_usize,
+            });
+        }
+        buffer.put_uint(self.x.len() as u64, 5);
+        for elem in &self.x {
+            elem.write_to(buffer)?;
+        }
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        5 + self.x.iter().map(|elem| elem.get_size()).sum::<usize>()
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Bar {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = BarData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(bar: BarData) -> Result<Self, DecodeError> {
+        Ok(Self { bar })
+    }
+    pub fn get_x(&self) -> &Vec<Foo> {
+        &self.bar.x
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.bar.get_size()
+    }
+}
+impl BarBuilder {
+    pub fn build(self) -> Bar {
+        let bar = BarData { x: self.x };
+        Bar::new(bar).unwrap()
+    }
+}
+impl From<BarBuilder> for Bar {
+    fn from(builder: BarBuilder) -> Bar {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/rust_legacy/packet_decl_array_unknown_element_width_dynamic_count_little_endian.rs b/tests/generated/rust_legacy/packet_decl_array_unknown_element_width_dynamic_count_little_endian.rs
new file mode 100644
index 0000000..81861ee
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_array_unknown_element_width_dynamic_count_little_endian.rs
@@ -0,0 +1,200 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: Vec<u16>,
+}
+impl Foo {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 5
+    }
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 5,
+                got: bytes.get().remaining(),
+            });
+        }
+        let a_count = bytes.get_mut().get_uint_le(5) as usize;
+        if bytes.get().remaining() < a_count * 2usize {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: a_count * 2usize,
+                got: bytes.get().remaining(),
+            });
+        }
+        let a = (0..a_count)
+            .map(|_| Ok::<_, DecodeError>(bytes.get_mut().get_u16_le()))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        Ok(Self { a })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        if self.a.len() > 0xff_ffff_ffff_usize {
+            return Err(EncodeError::CountOverflow {
+                packet: "Foo",
+                field: "a",
+                count: self.a.len(),
+                maximum_count: 0xff_ffff_ffff_usize,
+            });
+        }
+        buffer.put_uint_le(self.a.len() as u64, 5);
+        for elem in &self.a {
+            buffer.put_u16_le(*elem);
+        }
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        5 + self.a.len() * 2
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct BarData {
+    x: Vec<Foo>,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    bar: BarData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct BarBuilder {
+    pub x: Vec<Foo>,
+}
+impl BarData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 5
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 5,
+                got: bytes.get().remaining(),
+            });
+        }
+        let x_count = bytes.get_mut().get_uint_le(5) as usize;
+        let x = (0..x_count)
+            .map(|_| Foo::parse_inner(bytes))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        Ok(Self { x })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        if self.x.len() > 0xff_ffff_ffff_usize {
+            return Err(EncodeError::CountOverflow {
+                packet: "Bar",
+                field: "x",
+                count: self.x.len(),
+                maximum_count: 0xff_ffff_ffff_usize,
+            });
+        }
+        buffer.put_uint_le(self.x.len() as u64, 5);
+        for elem in &self.x {
+            elem.write_to(buffer)?;
+        }
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        5 + self.x.iter().map(|elem| elem.get_size()).sum::<usize>()
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Bar {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = BarData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(bar: BarData) -> Result<Self, DecodeError> {
+        Ok(Self { bar })
+    }
+    pub fn get_x(&self) -> &Vec<Foo> {
+        &self.bar.x
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.bar.get_size()
+    }
+}
+impl BarBuilder {
+    pub fn build(self) -> Bar {
+        let bar = BarData { x: self.x };
+        Bar::new(bar).unwrap()
+    }
+}
+impl From<BarBuilder> for Bar {
+    fn from(builder: BarBuilder) -> Bar {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/packet_decl_array_unknown_element_width_dynamic_size_big_endian.rs b/tests/generated/rust_legacy/packet_decl_array_unknown_element_width_dynamic_size_big_endian.rs
similarity index 61%
rename from tests/generated/packet_decl_array_unknown_element_width_dynamic_size_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_array_unknown_element_width_dynamic_size_big_endian.rs
index 63d2dc2..c2e7884 100644
--- a/tests/generated/packet_decl_array_unknown_element_width_dynamic_size_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_array_unknown_element_width_dynamic_size_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub struct Foo {
@@ -27,43 +32,46 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 5
     }
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 5 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 5,
                 got: bytes.get().remaining(),
             });
         }
         let a_count = bytes.get_mut().get_uint(5) as usize;
         if bytes.get().remaining() < a_count * 2usize {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: a_count * 2usize,
                 got: bytes.get().remaining(),
             });
         }
         let a = (0..a_count)
-            .map(|_| Ok::<_, Error>(bytes.get_mut().get_u16()))
-            .collect::<Result<Vec<_>>>()?;
+            .map(|_| Ok::<_, DecodeError>(bytes.get_mut().get_u16()))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
         Ok(Self { a })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         if self.a.len() > 0xff_ffff_ffff_usize {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Foo", "a", self.a.len(),
-                0xff_ffff_ffff_usize
-            );
+            return Err(EncodeError::CountOverflow {
+                packet: "Foo",
+                field: "a",
+                count: self.a.len(),
+                maximum_count: 0xff_ffff_ffff_usize,
+            });
         }
         buffer.put_uint(self.a.len() as u64, 5);
         for elem in &self.a {
             buffer.put_u16(*elem);
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -92,23 +100,23 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 5
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 5 {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
                 wanted: 5,
                 got: bytes.get().remaining(),
             });
         }
         let x_size = bytes.get_mut().get_uint(5) as usize;
         if bytes.get().remaining() < x_size {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
                 wanted: x_size,
                 got: bytes.get().remaining(),
             });
@@ -122,18 +130,21 @@
         }
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         let x_size = self.x.iter().map(|elem| elem.get_size()).sum::<usize>();
         if x_size > 0xff_ffff_ffff_usize {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Bar", "x", x_size,
-                0xff_ffff_ffff_usize
-            );
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "x",
+                size: x_size,
+                maximum_size: 0xff_ffff_ffff_usize,
+            });
         }
         buffer.put_uint(x_size as u64, 5);
         for elem in &self.x {
-            elem.write_to(buffer);
+            elem.write_to(buffer)?;
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -143,42 +154,45 @@
     }
 }
 impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.bar.get_size());
-        self.bar.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Bar {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = BarData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(bar: BarData) -> Result<Self> {
+    fn new(bar: BarData) -> Result<Self, DecodeError> {
         Ok(Self { bar })
     }
     pub fn get_x(&self) -> &Vec<Foo> {
         &self.bar.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.bar.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_array_unknown_element_width_dynamic_size_little_endian.rs b/tests/generated/rust_legacy/packet_decl_array_unknown_element_width_dynamic_size_little_endian.rs
similarity index 61%
rename from tests/generated/packet_decl_array_unknown_element_width_dynamic_size_little_endian.rs
rename to tests/generated/rust_legacy/packet_decl_array_unknown_element_width_dynamic_size_little_endian.rs
index 30ef3ba..8c03cbf 100644
--- a/tests/generated/packet_decl_array_unknown_element_width_dynamic_size_little_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_array_unknown_element_width_dynamic_size_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub struct Foo {
@@ -27,43 +32,46 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 5
     }
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 5 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 5,
                 got: bytes.get().remaining(),
             });
         }
         let a_count = bytes.get_mut().get_uint_le(5) as usize;
         if bytes.get().remaining() < a_count * 2usize {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: a_count * 2usize,
                 got: bytes.get().remaining(),
             });
         }
         let a = (0..a_count)
-            .map(|_| Ok::<_, Error>(bytes.get_mut().get_u16_le()))
-            .collect::<Result<Vec<_>>>()?;
+            .map(|_| Ok::<_, DecodeError>(bytes.get_mut().get_u16_le()))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
         Ok(Self { a })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         if self.a.len() > 0xff_ffff_ffff_usize {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Foo", "a", self.a.len(),
-                0xff_ffff_ffff_usize
-            );
+            return Err(EncodeError::CountOverflow {
+                packet: "Foo",
+                field: "a",
+                count: self.a.len(),
+                maximum_count: 0xff_ffff_ffff_usize,
+            });
         }
         buffer.put_uint_le(self.a.len() as u64, 5);
         for elem in &self.a {
             buffer.put_u16_le(*elem);
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -92,23 +100,23 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 5
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 5 {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
                 wanted: 5,
                 got: bytes.get().remaining(),
             });
         }
         let x_size = bytes.get_mut().get_uint_le(5) as usize;
         if bytes.get().remaining() < x_size {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
                 wanted: x_size,
                 got: bytes.get().remaining(),
             });
@@ -122,18 +130,21 @@
         }
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         let x_size = self.x.iter().map(|elem| elem.get_size()).sum::<usize>();
         if x_size > 0xff_ffff_ffff_usize {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Bar", "x", x_size,
-                0xff_ffff_ffff_usize
-            );
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "x",
+                size: x_size,
+                maximum_size: 0xff_ffff_ffff_usize,
+            });
         }
         buffer.put_uint_le(x_size as u64, 5);
         for elem in &self.x {
-            elem.write_to(buffer);
+            elem.write_to(buffer)?;
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -143,42 +154,45 @@
     }
 }
 impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.bar.get_size());
-        self.bar.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Bar {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = BarData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(bar: BarData) -> Result<Self> {
+    fn new(bar: BarData) -> Result<Self, DecodeError> {
         Ok(Self { bar })
     }
     pub fn get_x(&self) -> &Vec<Foo> {
         &self.bar.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.bar.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/rust_legacy/packet_decl_array_with_padding_big_endian.rs b/tests/generated/rust_legacy/packet_decl_array_with_padding_big_endian.rs
new file mode 100644
index 0000000..ed28697
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_array_with_padding_big_endian.rs
@@ -0,0 +1,204 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: Vec<u16>,
+}
+impl Foo {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 5
+    }
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 5,
+                got: bytes.get().remaining(),
+            });
+        }
+        let a_count = bytes.get_mut().get_uint(5) as usize;
+        if bytes.get().remaining() < a_count * 2usize {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: a_count * 2usize,
+                got: bytes.get().remaining(),
+            });
+        }
+        let a = (0..a_count)
+            .map(|_| Ok::<_, DecodeError>(bytes.get_mut().get_u16()))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        Ok(Self { a })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        if self.a.len() > 0xff_ffff_ffff_usize {
+            return Err(EncodeError::CountOverflow {
+                packet: "Foo",
+                field: "a",
+                count: self.a.len(),
+                maximum_count: 0xff_ffff_ffff_usize,
+            });
+        }
+        buffer.put_uint(self.a.len() as u64, 5);
+        for elem in &self.a {
+            buffer.put_u16(*elem);
+        }
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        5 + self.a.len() * 2
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct BarData {
+    a: Vec<Foo>,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    bar: BarData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct BarBuilder {
+    pub a: Vec<Foo>,
+}
+impl BarData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 128
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 128usize {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 128usize,
+                got: bytes.get().remaining(),
+            });
+        }
+        let (head, tail) = bytes.get().split_at(128usize);
+        let mut head = &mut Cell::new(head);
+        bytes.replace(tail);
+        let mut a = Vec::new();
+        while !head.get().is_empty() {
+            a.push(Foo::parse_inner(head)?);
+        }
+        Ok(Self { a })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        let array_size = self.a.iter().fold(0, |size, elem| size + elem.get_size());
+        if array_size > 128usize {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "a",
+                size: array_size,
+                maximum_size: 128usize,
+            });
+        }
+        for elem in &self.a {
+            elem.write_to(buffer)?;
+        }
+        buffer.put_bytes(0, 128usize - array_size);
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        128
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Bar {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = BarData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(bar: BarData) -> Result<Self, DecodeError> {
+        Ok(Self { bar })
+    }
+    pub fn get_a(&self) -> &Vec<Foo> {
+        &self.bar.a
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.bar.get_size()
+    }
+}
+impl BarBuilder {
+    pub fn build(self) -> Bar {
+        let bar = BarData { a: self.a };
+        Bar::new(bar).unwrap()
+    }
+}
+impl From<BarBuilder> for Bar {
+    fn from(builder: BarBuilder) -> Bar {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/rust_legacy/packet_decl_array_with_padding_little_endian.rs b/tests/generated/rust_legacy/packet_decl_array_with_padding_little_endian.rs
new file mode 100644
index 0000000..df72439
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_array_with_padding_little_endian.rs
@@ -0,0 +1,204 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: Vec<u16>,
+}
+impl Foo {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 5
+    }
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 5,
+                got: bytes.get().remaining(),
+            });
+        }
+        let a_count = bytes.get_mut().get_uint_le(5) as usize;
+        if bytes.get().remaining() < a_count * 2usize {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: a_count * 2usize,
+                got: bytes.get().remaining(),
+            });
+        }
+        let a = (0..a_count)
+            .map(|_| Ok::<_, DecodeError>(bytes.get_mut().get_u16_le()))
+            .collect::<Result<Vec<_>, DecodeError>>()?;
+        Ok(Self { a })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        if self.a.len() > 0xff_ffff_ffff_usize {
+            return Err(EncodeError::CountOverflow {
+                packet: "Foo",
+                field: "a",
+                count: self.a.len(),
+                maximum_count: 0xff_ffff_ffff_usize,
+            });
+        }
+        buffer.put_uint_le(self.a.len() as u64, 5);
+        for elem in &self.a {
+            buffer.put_u16_le(*elem);
+        }
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        5 + self.a.len() * 2
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct BarData {
+    a: Vec<Foo>,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    bar: BarData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct BarBuilder {
+    pub a: Vec<Foo>,
+}
+impl BarData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 128
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 128usize {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 128usize,
+                got: bytes.get().remaining(),
+            });
+        }
+        let (head, tail) = bytes.get().split_at(128usize);
+        let mut head = &mut Cell::new(head);
+        bytes.replace(tail);
+        let mut a = Vec::new();
+        while !head.get().is_empty() {
+            a.push(Foo::parse_inner(head)?);
+        }
+        Ok(Self { a })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        let array_size = self.a.iter().fold(0, |size, elem| size + elem.get_size());
+        if array_size > 128usize {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Bar",
+                field: "a",
+                size: array_size,
+                maximum_size: 128usize,
+            });
+        }
+        for elem in &self.a {
+            elem.write_to(buffer)?;
+        }
+        buffer.put_bytes(0, 128usize - array_size);
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        128
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Bar {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = BarData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(bar: BarData) -> Result<Self, DecodeError> {
+        Ok(Self { bar })
+    }
+    pub fn get_a(&self) -> &Vec<Foo> {
+        &self.bar.a
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.bar.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.bar.get_size()
+    }
+}
+impl BarBuilder {
+    pub fn build(self) -> Bar {
+        let bar = BarData { a: self.a };
+        Bar::new(bar).unwrap()
+    }
+}
+impl From<BarBuilder> for Bar {
+    fn from(builder: BarBuilder) -> Bar {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/packet_decl_child_packets_big_endian.rs b/tests/generated/rust_legacy/packet_decl_child_packets_big_endian.rs
similarity index 70%
rename from tests/generated/packet_decl_child_packets_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_child_packets_big_endian.rs
index 3498cae..3cb5980 100644
--- a/tests/generated/packet_decl_child_packets_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_child_packets_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u16> for Enum16 {
     type Error = u16;
-    fn try_from(value: u16) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Enum16::A),
             0x2 => Ok(Enum16::B),
@@ -119,45 +124,45 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 4
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
         }
         let a = bytes.get_mut().get_u8();
         if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 2,
                 got: bytes.get().remaining(),
             });
         }
         let b = Enum16::try_from(bytes.get_mut().get_u16())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Foo".to_string(),
-                field: "b".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Foo",
+                field: "b",
                 value: unknown_val as u64,
-                type_: "Enum16".to_string(),
+                type_: "Enum16",
             })?;
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
         }
         let payload_size = bytes.get_mut().get_u8() as usize;
         if bytes.get().remaining() < payload_size {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: payload_size,
                 got: bytes.get().remaining(),
             });
@@ -182,22 +187,25 @@
         };
         Ok(Self { a, b, child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u8(self.a);
         buffer.put_u16(u16::from(self.b));
         if self.child.get_total_size() > 0xff {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Foo", "_payload_", self.child
-                .get_total_size(), 0xff
-            );
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: self.child.get_total_size(),
+                maximum_size: 0xff,
+            });
         }
         buffer.put_u8(self.child.get_total_size() as u8);
         match &self.child {
-            FooDataChild::Bar(child) => child.write_to(buffer),
-            FooDataChild::Baz(child) => child.write_to(buffer),
+            FooDataChild::Bar(child) => child.write_to(buffer)?,
+            FooDataChild::Baz(child) => child.write_to(buffer)?,
             FooDataChild::Payload(payload) => buffer.put_slice(payload),
             FooDataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -207,32 +215,35 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -244,7 +255,7 @@
             FooDataChild::None => FooChild::None,
         }
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_a(&self) -> u8 {
@@ -253,7 +264,7 @@
     pub fn get_b(&self) -> Enum16 {
         self.foo.b
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -301,15 +312,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 1
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
@@ -317,8 +328,9 @@
         let x = bytes.get_mut().get_u8();
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u8(self.x);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -328,23 +340,26 @@
     }
 }
 impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<Bar> for Foo {
@@ -353,26 +368,26 @@
     }
 }
 impl TryFrom<Foo> for Bar {
-    type Error = Error;
-    fn try_from(packet: Foo) -> Result<Bar> {
+    type Error = DecodeError;
+    fn try_from(packet: Foo) -> Result<Bar, Self::Error> {
         Bar::new(packet.foo)
     }
 }
 impl Bar {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         let bar = match &foo.child {
             FooDataChild::Bar(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(FooDataChild::Bar),
                     actual: format!("{:?}", & foo.child),
                 });
@@ -389,7 +404,7 @@
     pub fn get_x(&self) -> u8 {
         self.bar.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.bar.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -440,15 +455,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 2
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Baz".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Baz",
                 wanted: 2,
                 got: bytes.get().remaining(),
             });
@@ -456,8 +471,9 @@
         let y = bytes.get_mut().get_u16();
         Ok(Self { y })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u16(self.y);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -467,23 +483,26 @@
     }
 }
 impl Packet for Baz {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Baz> for Bytes {
-    fn from(packet: Baz) -> Self {
-        packet.to_bytes()
+impl TryFrom<Baz> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Baz) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Baz> for Vec<u8> {
-    fn from(packet: Baz) -> Self {
-        packet.to_vec()
+impl TryFrom<Baz> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Baz) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<Baz> for Foo {
@@ -492,26 +511,26 @@
     }
 }
 impl TryFrom<Foo> for Baz {
-    type Error = Error;
-    fn try_from(packet: Foo) -> Result<Baz> {
+    type Error = DecodeError;
+    fn try_from(packet: Foo) -> Result<Baz, Self::Error> {
         Baz::new(packet.foo)
     }
 }
 impl Baz {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         let baz = match &foo.child {
             FooDataChild::Baz(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(FooDataChild::Baz),
                     actual: format!("{:?}", & foo.child),
                 });
@@ -528,7 +547,7 @@
     pub fn get_y(&self) -> u16 {
         self.baz.y
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.baz.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_child_packets_little_endian.rs b/tests/generated/rust_legacy/packet_decl_child_packets_little_endian.rs
similarity index 70%
rename from tests/generated/packet_decl_child_packets_little_endian.rs
rename to tests/generated/rust_legacy/packet_decl_child_packets_little_endian.rs
index cebc67e..b4a96a4 100644
--- a/tests/generated/packet_decl_child_packets_little_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_child_packets_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u16> for Enum16 {
     type Error = u16;
-    fn try_from(value: u16) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Enum16::A),
             0x2 => Ok(Enum16::B),
@@ -119,45 +124,45 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 4
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
         }
         let a = bytes.get_mut().get_u8();
         if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 2,
                 got: bytes.get().remaining(),
             });
         }
         let b = Enum16::try_from(bytes.get_mut().get_u16_le())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Foo".to_string(),
-                field: "b".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Foo",
+                field: "b",
                 value: unknown_val as u64,
-                type_: "Enum16".to_string(),
+                type_: "Enum16",
             })?;
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
         }
         let payload_size = bytes.get_mut().get_u8() as usize;
         if bytes.get().remaining() < payload_size {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: payload_size,
                 got: bytes.get().remaining(),
             });
@@ -182,22 +187,25 @@
         };
         Ok(Self { a, b, child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u8(self.a);
         buffer.put_u16_le(u16::from(self.b));
         if self.child.get_total_size() > 0xff {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Foo", "_payload_", self.child
-                .get_total_size(), 0xff
-            );
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: self.child.get_total_size(),
+                maximum_size: 0xff,
+            });
         }
         buffer.put_u8(self.child.get_total_size() as u8);
         match &self.child {
-            FooDataChild::Bar(child) => child.write_to(buffer),
-            FooDataChild::Baz(child) => child.write_to(buffer),
+            FooDataChild::Bar(child) => child.write_to(buffer)?,
+            FooDataChild::Baz(child) => child.write_to(buffer)?,
             FooDataChild::Payload(payload) => buffer.put_slice(payload),
             FooDataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -207,32 +215,35 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -244,7 +255,7 @@
             FooDataChild::None => FooChild::None,
         }
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_a(&self) -> u8 {
@@ -253,7 +264,7 @@
     pub fn get_b(&self) -> Enum16 {
         self.foo.b
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -301,15 +312,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 1
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Bar".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
@@ -317,8 +328,9 @@
         let x = bytes.get_mut().get_u8();
         Ok(Self { x })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u8(self.x);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -328,23 +340,26 @@
     }
 }
 impl Packet for Bar {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Bar> for Bytes {
-    fn from(packet: Bar) -> Self {
-        packet.to_bytes()
+impl TryFrom<Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Bar> for Vec<u8> {
-    fn from(packet: Bar) -> Self {
-        packet.to_vec()
+impl TryFrom<Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<Bar> for Foo {
@@ -353,26 +368,26 @@
     }
 }
 impl TryFrom<Foo> for Bar {
-    type Error = Error;
-    fn try_from(packet: Foo) -> Result<Bar> {
+    type Error = DecodeError;
+    fn try_from(packet: Foo) -> Result<Bar, Self::Error> {
         Bar::new(packet.foo)
     }
 }
 impl Bar {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         let bar = match &foo.child {
             FooDataChild::Bar(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(FooDataChild::Bar),
                     actual: format!("{:?}", & foo.child),
                 });
@@ -389,7 +404,7 @@
     pub fn get_x(&self) -> u8 {
         self.bar.x
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.bar.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -440,15 +455,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 2
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Baz".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Baz",
                 wanted: 2,
                 got: bytes.get().remaining(),
             });
@@ -456,8 +471,9 @@
         let y = bytes.get_mut().get_u16_le();
         Ok(Self { y })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u16_le(self.y);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -467,23 +483,26 @@
     }
 }
 impl Packet for Baz {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Baz> for Bytes {
-    fn from(packet: Baz) -> Self {
-        packet.to_bytes()
+impl TryFrom<Baz> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Baz) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Baz> for Vec<u8> {
-    fn from(packet: Baz) -> Self {
-        packet.to_vec()
+impl TryFrom<Baz> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Baz) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<Baz> for Foo {
@@ -492,26 +511,26 @@
     }
 }
 impl TryFrom<Foo> for Baz {
-    type Error = Error;
-    fn try_from(packet: Foo) -> Result<Baz> {
+    type Error = DecodeError;
+    fn try_from(packet: Foo) -> Result<Baz, Self::Error> {
         Baz::new(packet.foo)
     }
 }
 impl Baz {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         let baz = match &foo.child {
             FooDataChild::Baz(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(FooDataChild::Baz),
                     actual: format!("{:?}", & foo.child),
                 });
@@ -528,7 +547,7 @@
     pub fn get_y(&self) -> u16 {
         self.baz.y
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.baz.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/rust_legacy/packet_decl_complex_scalars_big_endian.rs b/tests/generated/rust_legacy/packet_decl_complex_scalars_big_endian.rs
new file mode 100644
index 0000000..af50b91
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_complex_scalars_big_endian.rs
@@ -0,0 +1,226 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {
+    a: u8,
+    b: u8,
+    c: u8,
+    d: u32,
+    e: u16,
+    f: u8,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {
+    pub a: u8,
+    pub b: u8,
+    pub c: u8,
+    pub d: u32,
+    pub e: u16,
+    pub f: u8,
+}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 7
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: bytes.get().remaining(),
+            });
+        }
+        let chunk = bytes.get_mut().get_u16();
+        let a = (chunk & 0x7) as u8;
+        let b = (chunk >> 3) as u8;
+        let c = ((chunk >> 11) & 0x1f) as u8;
+        if bytes.get().remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: bytes.get().remaining(),
+            });
+        }
+        let d = bytes.get_mut().get_uint(3) as u32;
+        if bytes.get().remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: bytes.get().remaining(),
+            });
+        }
+        let chunk = bytes.get_mut().get_u16();
+        let e = (chunk & 0xfff);
+        let f = ((chunk >> 12) & 0xf) as u8;
+        Ok(Self { a, b, c, d, e, f })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        if self.a > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a as u64,
+                maximum_value: 0x7,
+            });
+        }
+        if self.c > 0x1f {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "c",
+                value: self.c as u64,
+                maximum_value: 0x1f,
+            });
+        }
+        let value = (self.a as u16) | ((self.b as u16) << 3) | ((self.c as u16) << 11);
+        buffer.put_u16(value);
+        if self.d > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "d",
+                value: self.d as u64,
+                maximum_value: 0xff_ffff,
+            });
+        }
+        buffer.put_uint(self.d as u64, 3);
+        if self.e > 0xfff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "e",
+                value: self.e as u64,
+                maximum_value: 0xfff,
+            });
+        }
+        if self.f > 0xf {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "f",
+                value: self.f as u64,
+                maximum_value: 0xf,
+            });
+        }
+        let value = self.e | ((self.f as u16) << 12);
+        buffer.put_u16(value);
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        7
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    pub fn get_a(&self) -> u8 {
+        self.foo.a
+    }
+    pub fn get_b(&self) -> u8 {
+        self.foo.b
+    }
+    pub fn get_c(&self) -> u8 {
+        self.foo.c
+    }
+    pub fn get_d(&self) -> u32 {
+        self.foo.d
+    }
+    pub fn get_e(&self) -> u16 {
+        self.foo.e
+    }
+    pub fn get_f(&self) -> u8 {
+        self.foo.f
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData {
+            a: self.a,
+            b: self.b,
+            c: self.c,
+            d: self.d,
+            e: self.e,
+            f: self.f,
+        };
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/rust_legacy/packet_decl_complex_scalars_little_endian.rs b/tests/generated/rust_legacy/packet_decl_complex_scalars_little_endian.rs
new file mode 100644
index 0000000..c3b8827
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_complex_scalars_little_endian.rs
@@ -0,0 +1,226 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {
+    a: u8,
+    b: u8,
+    c: u8,
+    d: u32,
+    e: u16,
+    f: u8,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {
+    pub a: u8,
+    pub b: u8,
+    pub c: u8,
+    pub d: u32,
+    pub e: u16,
+    pub f: u8,
+}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 7
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: bytes.get().remaining(),
+            });
+        }
+        let chunk = bytes.get_mut().get_u16_le();
+        let a = (chunk & 0x7) as u8;
+        let b = (chunk >> 3) as u8;
+        let c = ((chunk >> 11) & 0x1f) as u8;
+        if bytes.get().remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: bytes.get().remaining(),
+            });
+        }
+        let d = bytes.get_mut().get_uint_le(3) as u32;
+        if bytes.get().remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: bytes.get().remaining(),
+            });
+        }
+        let chunk = bytes.get_mut().get_u16_le();
+        let e = (chunk & 0xfff);
+        let f = ((chunk >> 12) & 0xf) as u8;
+        Ok(Self { a, b, c, d, e, f })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        if self.a > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a as u64,
+                maximum_value: 0x7,
+            });
+        }
+        if self.c > 0x1f {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "c",
+                value: self.c as u64,
+                maximum_value: 0x1f,
+            });
+        }
+        let value = (self.a as u16) | ((self.b as u16) << 3) | ((self.c as u16) << 11);
+        buffer.put_u16_le(value);
+        if self.d > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "d",
+                value: self.d as u64,
+                maximum_value: 0xff_ffff,
+            });
+        }
+        buffer.put_uint_le(self.d as u64, 3);
+        if self.e > 0xfff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "e",
+                value: self.e as u64,
+                maximum_value: 0xfff,
+            });
+        }
+        if self.f > 0xf {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "f",
+                value: self.f as u64,
+                maximum_value: 0xf,
+            });
+        }
+        let value = self.e | ((self.f as u16) << 12);
+        buffer.put_u16_le(value);
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        7
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    pub fn get_a(&self) -> u8 {
+        self.foo.a
+    }
+    pub fn get_b(&self) -> u8 {
+        self.foo.b
+    }
+    pub fn get_c(&self) -> u8 {
+        self.foo.c
+    }
+    pub fn get_d(&self) -> u32 {
+        self.foo.d
+    }
+    pub fn get_e(&self) -> u16 {
+        self.foo.e
+    }
+    pub fn get_f(&self) -> u8 {
+        self.foo.f
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData {
+            a: self.a,
+            b: self.b,
+            c: self.c,
+            d: self.d,
+            e: self.e,
+            f: self.f,
+        };
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/packet_decl_custom_field_big_endian.rs b/tests/generated/rust_legacy/packet_decl_custom_field_big_endian.rs
similarity index 69%
rename from tests/generated/packet_decl_custom_field_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_custom_field_big_endian.rs
index 43b2237..757c0af 100644
--- a/tests/generated/packet_decl_custom_field_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_custom_field_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 #[cfg_attr(feature = "serde", serde(try_from = "u32", into = "u32"))]
@@ -34,7 +39,7 @@
 }
 impl TryFrom<u32> for Bar1 {
     type Error = u32;
-    fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
         if value > 0xff_ffff { Err(value) } else { Ok(Bar1(value)) }
     }
 }
@@ -79,19 +84,20 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 7
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let a = (bytes.get_mut().get_uint(3) as u32).try_into().unwrap();
         let b = bytes.get_mut().get_u32().into();
         Ok(Self { a, b })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_uint(u32::from(self.a) as u64, 3);
         buffer.put_u32(u32::from(self.b));
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -101,36 +107,39 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_a(&self) -> Bar1 {
@@ -139,7 +148,7 @@
     pub fn get_b(&self) -> Bar2 {
         self.foo.b
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_custom_field_little_endian.rs b/tests/generated/rust_legacy/packet_decl_custom_field_little_endian.rs
similarity index 69%
rename from tests/generated/packet_decl_custom_field_little_endian.rs
rename to tests/generated/rust_legacy/packet_decl_custom_field_little_endian.rs
index f1b9d0a..e714d39 100644
--- a/tests/generated/packet_decl_custom_field_little_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_custom_field_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 #[cfg_attr(feature = "serde", serde(try_from = "u32", into = "u32"))]
@@ -34,7 +39,7 @@
 }
 impl TryFrom<u32> for Bar1 {
     type Error = u32;
-    fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
         if value > 0xff_ffff { Err(value) } else { Ok(Bar1(value)) }
     }
 }
@@ -79,19 +84,20 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 7
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let a = (bytes.get_mut().get_uint_le(3) as u32).try_into().unwrap();
         let b = bytes.get_mut().get_u32_le().into();
         Ok(Self { a, b })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_uint_le(u32::from(self.a) as u64, 3);
         buffer.put_u32_le(u32::from(self.b));
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -101,36 +107,39 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_a(&self) -> Bar1 {
@@ -139,7 +148,7 @@
     pub fn get_b(&self) -> Bar2 {
         self.foo.b
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/rust_legacy/packet_decl_empty_big_endian.rs b/tests/generated/rust_legacy/packet_decl_empty_big_endian.rs
new file mode 100644
index 0000000..e28e34c
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_empty_big_endian.rs
@@ -0,0 +1,113 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        true
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        Ok(Self {})
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        0
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData {};
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/rust_legacy/packet_decl_empty_little_endian.rs b/tests/generated/rust_legacy/packet_decl_empty_little_endian.rs
new file mode 100644
index 0000000..e28e34c
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_empty_little_endian.rs
@@ -0,0 +1,113 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        true
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        Ok(Self {})
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        0
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData {};
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/packet_decl_fixed_enum_field_big_endian.rs b/tests/generated/rust_legacy/packet_decl_fixed_enum_field_big_endian.rs
similarity index 69%
rename from tests/generated/packet_decl_fixed_enum_field_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_fixed_enum_field_big_endian.rs
index 78b2b99..e45ea28 100644
--- a/tests/generated/packet_decl_fixed_enum_field_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_fixed_enum_field_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u8> for Enum7 {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Enum7::A),
             0x2 => Ok(Enum7::B),
@@ -104,15 +109,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 8
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 8 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 8,
                 got: bytes.get().remaining(),
             });
@@ -120,7 +125,7 @@
         let chunk = bytes.get_mut().get_u64();
         let fixed_value = (chunk & 0x7f) as u8;
         if fixed_value != u8::from(Enum7::A) {
-            return Err(Error::InvalidFixedValue {
+            return Err(DecodeError::InvalidFixedValue {
                 expected: u8::from(Enum7::A) as u64,
                 actual: fixed_value as u64,
             });
@@ -128,15 +133,18 @@
         let b = ((chunk >> 7) & 0x1ff_ffff_ffff_ffff_u64);
         Ok(Self { b })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         if self.b > 0x1ff_ffff_ffff_ffff_u64 {
-            panic!(
-                "Invalid value for {}::{}: {} > {}", "Foo", "b", self.b,
-                0x1ff_ffff_ffff_ffff_u64
-            );
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "b",
+                value: self.b as u64,
+                maximum_value: 0x1ff_ffff_ffff_ffff_u64,
+            });
         }
         let value = (u8::from(Enum7::A) as u64) | (self.b << 7);
         buffer.put_u64(value);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -146,42 +154,45 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_b(&self) -> u64 {
         self.foo.b
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_fixed_enum_field_little_endian.rs b/tests/generated/rust_legacy/packet_decl_fixed_enum_field_little_endian.rs
similarity index 69%
rename from tests/generated/packet_decl_fixed_enum_field_little_endian.rs
rename to tests/generated/rust_legacy/packet_decl_fixed_enum_field_little_endian.rs
index dfb4c25..cba5f86 100644
--- a/tests/generated/packet_decl_fixed_enum_field_little_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_fixed_enum_field_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u8> for Enum7 {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Enum7::A),
             0x2 => Ok(Enum7::B),
@@ -104,15 +109,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 8
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 8 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 8,
                 got: bytes.get().remaining(),
             });
@@ -120,7 +125,7 @@
         let chunk = bytes.get_mut().get_u64_le();
         let fixed_value = (chunk & 0x7f) as u8;
         if fixed_value != u8::from(Enum7::A) {
-            return Err(Error::InvalidFixedValue {
+            return Err(DecodeError::InvalidFixedValue {
                 expected: u8::from(Enum7::A) as u64,
                 actual: fixed_value as u64,
             });
@@ -128,15 +133,18 @@
         let b = ((chunk >> 7) & 0x1ff_ffff_ffff_ffff_u64);
         Ok(Self { b })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         if self.b > 0x1ff_ffff_ffff_ffff_u64 {
-            panic!(
-                "Invalid value for {}::{}: {} > {}", "Foo", "b", self.b,
-                0x1ff_ffff_ffff_ffff_u64
-            );
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "b",
+                value: self.b as u64,
+                maximum_value: 0x1ff_ffff_ffff_ffff_u64,
+            });
         }
         let value = (u8::from(Enum7::A) as u64) | (self.b << 7);
         buffer.put_u64_le(value);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -146,42 +154,45 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_b(&self) -> u64 {
         self.foo.b
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/rust_legacy/packet_decl_fixed_scalar_field_big_endian.rs b/tests/generated/rust_legacy/packet_decl_fixed_scalar_field_big_endian.rs
new file mode 100644
index 0000000..d4525df
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_fixed_scalar_field_big_endian.rs
@@ -0,0 +1,146 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {
+    b: u64,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {
+    pub b: u64,
+}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 8
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 8 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 8,
+                got: bytes.get().remaining(),
+            });
+        }
+        let chunk = bytes.get_mut().get_u64();
+        let fixed_value = (chunk & 0x7f) as u8;
+        if fixed_value != 7 {
+            return Err(DecodeError::InvalidFixedValue {
+                expected: 7,
+                actual: fixed_value as u64,
+            });
+        }
+        let b = ((chunk >> 7) & 0x1ff_ffff_ffff_ffff_u64);
+        Ok(Self { b })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        if self.b > 0x1ff_ffff_ffff_ffff_u64 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "b",
+                value: self.b as u64,
+                maximum_value: 0x1ff_ffff_ffff_ffff_u64,
+            });
+        }
+        let value = (7 as u64) | (self.b << 7);
+        buffer.put_u64(value);
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        8
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    pub fn get_b(&self) -> u64 {
+        self.foo.b
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData { b: self.b };
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/rust_legacy/packet_decl_fixed_scalar_field_little_endian.rs b/tests/generated/rust_legacy/packet_decl_fixed_scalar_field_little_endian.rs
new file mode 100644
index 0000000..85b3010
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_fixed_scalar_field_little_endian.rs
@@ -0,0 +1,146 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {
+    b: u64,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {
+    pub b: u64,
+}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 8
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 8 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 8,
+                got: bytes.get().remaining(),
+            });
+        }
+        let chunk = bytes.get_mut().get_u64_le();
+        let fixed_value = (chunk & 0x7f) as u8;
+        if fixed_value != 7 {
+            return Err(DecodeError::InvalidFixedValue {
+                expected: 7,
+                actual: fixed_value as u64,
+            });
+        }
+        let b = ((chunk >> 7) & 0x1ff_ffff_ffff_ffff_u64);
+        Ok(Self { b })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        if self.b > 0x1ff_ffff_ffff_ffff_u64 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "b",
+                value: self.b as u64,
+                maximum_value: 0x1ff_ffff_ffff_ffff_u64,
+            });
+        }
+        let value = (7 as u64) | (self.b << 7);
+        buffer.put_u64_le(value);
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        8
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    pub fn get_b(&self) -> u64 {
+        self.foo.b
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData { b: self.b };
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/packet_decl_grand_children_big_endian.rs b/tests/generated/rust_legacy/packet_decl_grand_children_big_endian.rs
similarity index 77%
rename from tests/generated/packet_decl_grand_children_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_grand_children_big_endian.rs
index 64ca83f..68a8ad5 100644
--- a/tests/generated/packet_decl_grand_children_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_grand_children_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u16> for Enum16 {
     type Error = u16;
-    fn try_from(value: u16) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Enum16::A),
             0x2 => Ok(Enum16::B),
@@ -118,65 +123,65 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 7
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Parent".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
                 wanted: 2,
                 got: bytes.get().remaining(),
             });
         }
         let foo = Enum16::try_from(bytes.get_mut().get_u16())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Parent".to_string(),
-                field: "foo".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "foo",
                 value: unknown_val as u64,
-                type_: "Enum16".to_string(),
+                type_: "Enum16",
             })?;
         if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Parent".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
                 wanted: 2,
                 got: bytes.get().remaining(),
             });
         }
         let bar = Enum16::try_from(bytes.get_mut().get_u16())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Parent".to_string(),
-                field: "bar".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "bar",
                 value: unknown_val as u64,
-                type_: "Enum16".to_string(),
+                type_: "Enum16",
             })?;
         if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Parent".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
                 wanted: 2,
                 got: bytes.get().remaining(),
             });
         }
         let baz = Enum16::try_from(bytes.get_mut().get_u16())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Parent".to_string(),
-                field: "baz".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "baz",
                 value: unknown_val as u64,
-                type_: "Enum16".to_string(),
+                type_: "Enum16",
             })?;
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Parent".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
         }
         let payload_size = bytes.get_mut().get_u8() as usize;
         if bytes.get().remaining() < payload_size {
-            return Err(Error::InvalidLengthError {
-                obj: "Parent".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
                 wanted: payload_size,
                 got: bytes.get().remaining(),
             });
@@ -196,22 +201,25 @@
         };
         Ok(Self { foo, bar, baz, child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u16(u16::from(self.foo));
         buffer.put_u16(u16::from(self.bar));
         buffer.put_u16(u16::from(self.baz));
         if self.child.get_total_size() > 0xff {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Parent", "_payload_", self.child
-                .get_total_size(), 0xff
-            );
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: self.child.get_total_size(),
+                maximum_size: 0xff,
+            });
         }
         buffer.put_u8(self.child.get_total_size() as u8);
         match &self.child {
-            ParentDataChild::Child(child) => child.write_to(buffer),
+            ParentDataChild::Child(child) => child.write_to(buffer)?,
             ParentDataChild::Payload(payload) => buffer.put_slice(payload),
             ParentDataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -221,32 +229,35 @@
     }
 }
 impl Packet for Parent {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Parent> for Bytes {
-    fn from(packet: Parent) -> Self {
-        packet.to_bytes()
+impl TryFrom<Parent> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Parent) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Parent> for Vec<u8> {
-    fn from(packet: Parent) -> Self {
-        packet.to_vec()
+impl TryFrom<Parent> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Parent) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Parent {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -259,7 +270,7 @@
             ParentDataChild::None => ParentChild::None,
         }
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         Ok(Self { parent })
     }
     pub fn get_bar(&self) -> Enum16 {
@@ -271,7 +282,7 @@
     pub fn get_foo(&self) -> Enum16 {
         self.parent.foo
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.parent.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -346,7 +357,7 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 2
     }
-    fn parse(bytes: &[u8], bar: Enum16, baz: Enum16) -> Result<Self> {
+    fn parse(bytes: &[u8], bar: Enum16, baz: Enum16) -> Result<Self, DecodeError> {
         let mut cell = Cell::new(bytes);
         let packet = Self::parse_inner(&mut cell, bar, baz)?;
         Ok(packet)
@@ -355,20 +366,20 @@
         mut bytes: &mut Cell<&[u8]>,
         bar: Enum16,
         baz: Enum16,
-    ) -> Result<Self> {
+    ) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Child".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Child",
                 wanted: 2,
                 got: bytes.get().remaining(),
             });
         }
         let quux = Enum16::try_from(bytes.get_mut().get_u16())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Child".to_string(),
-                field: "quux".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Child",
+                field: "quux",
                 value: unknown_val as u64,
-                type_: "Enum16".to_string(),
+                type_: "Enum16",
             })?;
         let payload = bytes.get();
         bytes.get_mut().advance(payload.len());
@@ -385,13 +396,14 @@
         };
         Ok(Self { quux, child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u16(u16::from(self.quux));
         match &self.child {
-            ChildDataChild::GrandChild(child) => child.write_to(buffer),
+            ChildDataChild::GrandChild(child) => child.write_to(buffer)?,
             ChildDataChild::Payload(payload) => buffer.put_slice(payload),
             ChildDataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -401,23 +413,26 @@
     }
 }
 impl Packet for Child {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Child> for Bytes {
-    fn from(packet: Child) -> Self {
-        packet.to_bytes()
+impl TryFrom<Child> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Child) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Child> for Vec<u8> {
-    fn from(packet: Child) -> Self {
-        packet.to_vec()
+impl TryFrom<Child> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Child) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<Child> for Parent {
@@ -426,18 +441,18 @@
     }
 }
 impl TryFrom<Parent> for Child {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<Child> {
+    type Error = DecodeError;
+    fn try_from(packet: Parent) -> Result<Child, Self::Error> {
         Child::new(packet.parent)
     }
 }
 impl Child {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -450,11 +465,11 @@
             ChildDataChild::None => ChildChild::None,
         }
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         let child = match &parent.child {
             ParentDataChild::Child(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ParentDataChild::Child),
                     actual: format!("{:?}", & parent.child),
                 });
@@ -474,7 +489,7 @@
     pub fn get_quux(&self) -> Enum16 {
         self.child.quux
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.child.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -557,12 +572,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         true
     }
-    fn parse(bytes: &[u8], baz: Enum16) -> Result<Self> {
+    fn parse(bytes: &[u8], baz: Enum16) -> Result<Self, DecodeError> {
         let mut cell = Cell::new(bytes);
         let packet = Self::parse_inner(&mut cell, baz)?;
         Ok(packet)
     }
-    fn parse_inner(mut bytes: &mut Cell<&[u8]>, baz: Enum16) -> Result<Self> {
+    fn parse_inner(
+        mut bytes: &mut Cell<&[u8]>,
+        baz: Enum16,
+    ) -> Result<Self, DecodeError> {
         let payload = bytes.get();
         bytes.get_mut().advance(payload.len());
         let child = match (baz) {
@@ -578,12 +596,13 @@
         };
         Ok(Self { child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         match &self.child {
-            GrandChildDataChild::GrandGrandChild(child) => child.write_to(buffer),
+            GrandChildDataChild::GrandGrandChild(child) => child.write_to(buffer)?,
             GrandChildDataChild::Payload(payload) => buffer.put_slice(payload),
             GrandChildDataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -593,23 +612,26 @@
     }
 }
 impl Packet for GrandChild {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<GrandChild> for Bytes {
-    fn from(packet: GrandChild) -> Self {
-        packet.to_bytes()
+impl TryFrom<GrandChild> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: GrandChild) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<GrandChild> for Vec<u8> {
-    fn from(packet: GrandChild) -> Self {
-        packet.to_vec()
+impl TryFrom<GrandChild> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: GrandChild) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<GrandChild> for Parent {
@@ -623,18 +645,18 @@
     }
 }
 impl TryFrom<Parent> for GrandChild {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<GrandChild> {
+    type Error = DecodeError;
+    fn try_from(packet: Parent) -> Result<GrandChild, Self::Error> {
         GrandChild::new(packet.parent)
     }
 }
 impl GrandChild {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -651,11 +673,11 @@
             GrandChildDataChild::None => GrandChildChild::None,
         }
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         let child = match &parent.child {
             ParentDataChild::Child(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ParentDataChild::Child),
                     actual: format!("{:?}", & parent.child),
                 });
@@ -664,7 +686,7 @@
         let grandchild = match &child.child {
             ChildDataChild::GrandChild(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ChildDataChild::GrandChild),
                     actual: format!("{:?}", & child.child),
                 });
@@ -684,7 +706,7 @@
     pub fn get_quux(&self) -> Enum16 {
         self.child.quux
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.grandchild.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -773,12 +795,12 @@
     fn conforms(bytes: &[u8]) -> bool {
         true
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let payload = bytes.get();
         bytes.get_mut().advance(payload.len());
         let child = match () {
@@ -789,11 +811,12 @@
         };
         Ok(Self { child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         match &self.child {
             GrandGrandChildDataChild::Payload(payload) => buffer.put_slice(payload),
             GrandGrandChildDataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -803,23 +826,26 @@
     }
 }
 impl Packet for GrandGrandChild {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<GrandGrandChild> for Bytes {
-    fn from(packet: GrandGrandChild) -> Self {
-        packet.to_bytes()
+impl TryFrom<GrandGrandChild> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: GrandGrandChild) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<GrandGrandChild> for Vec<u8> {
-    fn from(packet: GrandGrandChild) -> Self {
-        packet.to_vec()
+impl TryFrom<GrandGrandChild> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: GrandGrandChild) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<GrandGrandChild> for Parent {
@@ -838,18 +864,18 @@
     }
 }
 impl TryFrom<Parent> for GrandGrandChild {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<GrandGrandChild> {
+    type Error = DecodeError;
+    fn try_from(packet: Parent) -> Result<GrandGrandChild, Self::Error> {
         GrandGrandChild::new(packet.parent)
     }
 }
 impl GrandGrandChild {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -861,11 +887,11 @@
             GrandGrandChildDataChild::None => GrandGrandChildChild::None,
         }
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         let child = match &parent.child {
             ParentDataChild::Child(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ParentDataChild::Child),
                     actual: format!("{:?}", & parent.child),
                 });
@@ -874,7 +900,7 @@
         let grandchild = match &child.child {
             ChildDataChild::GrandChild(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ChildDataChild::GrandChild),
                     actual: format!("{:?}", & child.child),
                 });
@@ -883,7 +909,7 @@
         let grandgrandchild = match &grandchild.child {
             GrandChildDataChild::GrandGrandChild(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(GrandChildDataChild::GrandGrandChild),
                     actual: format!("{:?}", & grandchild.child),
                 });
@@ -914,7 +940,7 @@
             GrandGrandChildDataChild::None => &[],
         }
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.grandgrandchild.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_grand_children_little_endian.rs b/tests/generated/rust_legacy/packet_decl_grand_children_little_endian.rs
similarity index 77%
rename from tests/generated/packet_decl_grand_children_little_endian.rs
rename to tests/generated/rust_legacy/packet_decl_grand_children_little_endian.rs
index 9c03220..baa83db 100644
--- a/tests/generated/packet_decl_grand_children_little_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_grand_children_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u16> for Enum16 {
     type Error = u16;
-    fn try_from(value: u16) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Enum16::A),
             0x2 => Ok(Enum16::B),
@@ -118,65 +123,65 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 7
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Parent".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
                 wanted: 2,
                 got: bytes.get().remaining(),
             });
         }
         let foo = Enum16::try_from(bytes.get_mut().get_u16_le())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Parent".to_string(),
-                field: "foo".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "foo",
                 value: unknown_val as u64,
-                type_: "Enum16".to_string(),
+                type_: "Enum16",
             })?;
         if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Parent".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
                 wanted: 2,
                 got: bytes.get().remaining(),
             });
         }
         let bar = Enum16::try_from(bytes.get_mut().get_u16_le())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Parent".to_string(),
-                field: "bar".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "bar",
                 value: unknown_val as u64,
-                type_: "Enum16".to_string(),
+                type_: "Enum16",
             })?;
         if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Parent".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
                 wanted: 2,
                 got: bytes.get().remaining(),
             });
         }
         let baz = Enum16::try_from(bytes.get_mut().get_u16_le())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Parent".to_string(),
-                field: "baz".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "baz",
                 value: unknown_val as u64,
-                type_: "Enum16".to_string(),
+                type_: "Enum16",
             })?;
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Parent".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
         }
         let payload_size = bytes.get_mut().get_u8() as usize;
         if bytes.get().remaining() < payload_size {
-            return Err(Error::InvalidLengthError {
-                obj: "Parent".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
                 wanted: payload_size,
                 got: bytes.get().remaining(),
             });
@@ -196,22 +201,25 @@
         };
         Ok(Self { foo, bar, baz, child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u16_le(u16::from(self.foo));
         buffer.put_u16_le(u16::from(self.bar));
         buffer.put_u16_le(u16::from(self.baz));
         if self.child.get_total_size() > 0xff {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Parent", "_payload_", self.child
-                .get_total_size(), 0xff
-            );
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: self.child.get_total_size(),
+                maximum_size: 0xff,
+            });
         }
         buffer.put_u8(self.child.get_total_size() as u8);
         match &self.child {
-            ParentDataChild::Child(child) => child.write_to(buffer),
+            ParentDataChild::Child(child) => child.write_to(buffer)?,
             ParentDataChild::Payload(payload) => buffer.put_slice(payload),
             ParentDataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -221,32 +229,35 @@
     }
 }
 impl Packet for Parent {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Parent> for Bytes {
-    fn from(packet: Parent) -> Self {
-        packet.to_bytes()
+impl TryFrom<Parent> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Parent) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Parent> for Vec<u8> {
-    fn from(packet: Parent) -> Self {
-        packet.to_vec()
+impl TryFrom<Parent> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Parent) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Parent {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -259,7 +270,7 @@
             ParentDataChild::None => ParentChild::None,
         }
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         Ok(Self { parent })
     }
     pub fn get_bar(&self) -> Enum16 {
@@ -271,7 +282,7 @@
     pub fn get_foo(&self) -> Enum16 {
         self.parent.foo
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.parent.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -346,7 +357,7 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 2
     }
-    fn parse(bytes: &[u8], bar: Enum16, baz: Enum16) -> Result<Self> {
+    fn parse(bytes: &[u8], bar: Enum16, baz: Enum16) -> Result<Self, DecodeError> {
         let mut cell = Cell::new(bytes);
         let packet = Self::parse_inner(&mut cell, bar, baz)?;
         Ok(packet)
@@ -355,20 +366,20 @@
         mut bytes: &mut Cell<&[u8]>,
         bar: Enum16,
         baz: Enum16,
-    ) -> Result<Self> {
+    ) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Child".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Child",
                 wanted: 2,
                 got: bytes.get().remaining(),
             });
         }
         let quux = Enum16::try_from(bytes.get_mut().get_u16_le())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Child".to_string(),
-                field: "quux".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Child",
+                field: "quux",
                 value: unknown_val as u64,
-                type_: "Enum16".to_string(),
+                type_: "Enum16",
             })?;
         let payload = bytes.get();
         bytes.get_mut().advance(payload.len());
@@ -385,13 +396,14 @@
         };
         Ok(Self { quux, child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u16_le(u16::from(self.quux));
         match &self.child {
-            ChildDataChild::GrandChild(child) => child.write_to(buffer),
+            ChildDataChild::GrandChild(child) => child.write_to(buffer)?,
             ChildDataChild::Payload(payload) => buffer.put_slice(payload),
             ChildDataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -401,23 +413,26 @@
     }
 }
 impl Packet for Child {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Child> for Bytes {
-    fn from(packet: Child) -> Self {
-        packet.to_bytes()
+impl TryFrom<Child> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Child) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Child> for Vec<u8> {
-    fn from(packet: Child) -> Self {
-        packet.to_vec()
+impl TryFrom<Child> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Child) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<Child> for Parent {
@@ -426,18 +441,18 @@
     }
 }
 impl TryFrom<Parent> for Child {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<Child> {
+    type Error = DecodeError;
+    fn try_from(packet: Parent) -> Result<Child, Self::Error> {
         Child::new(packet.parent)
     }
 }
 impl Child {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -450,11 +465,11 @@
             ChildDataChild::None => ChildChild::None,
         }
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         let child = match &parent.child {
             ParentDataChild::Child(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ParentDataChild::Child),
                     actual: format!("{:?}", & parent.child),
                 });
@@ -474,7 +489,7 @@
     pub fn get_quux(&self) -> Enum16 {
         self.child.quux
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.child.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -557,12 +572,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         true
     }
-    fn parse(bytes: &[u8], baz: Enum16) -> Result<Self> {
+    fn parse(bytes: &[u8], baz: Enum16) -> Result<Self, DecodeError> {
         let mut cell = Cell::new(bytes);
         let packet = Self::parse_inner(&mut cell, baz)?;
         Ok(packet)
     }
-    fn parse_inner(mut bytes: &mut Cell<&[u8]>, baz: Enum16) -> Result<Self> {
+    fn parse_inner(
+        mut bytes: &mut Cell<&[u8]>,
+        baz: Enum16,
+    ) -> Result<Self, DecodeError> {
         let payload = bytes.get();
         bytes.get_mut().advance(payload.len());
         let child = match (baz) {
@@ -578,12 +596,13 @@
         };
         Ok(Self { child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         match &self.child {
-            GrandChildDataChild::GrandGrandChild(child) => child.write_to(buffer),
+            GrandChildDataChild::GrandGrandChild(child) => child.write_to(buffer)?,
             GrandChildDataChild::Payload(payload) => buffer.put_slice(payload),
             GrandChildDataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -593,23 +612,26 @@
     }
 }
 impl Packet for GrandChild {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<GrandChild> for Bytes {
-    fn from(packet: GrandChild) -> Self {
-        packet.to_bytes()
+impl TryFrom<GrandChild> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: GrandChild) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<GrandChild> for Vec<u8> {
-    fn from(packet: GrandChild) -> Self {
-        packet.to_vec()
+impl TryFrom<GrandChild> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: GrandChild) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<GrandChild> for Parent {
@@ -623,18 +645,18 @@
     }
 }
 impl TryFrom<Parent> for GrandChild {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<GrandChild> {
+    type Error = DecodeError;
+    fn try_from(packet: Parent) -> Result<GrandChild, Self::Error> {
         GrandChild::new(packet.parent)
     }
 }
 impl GrandChild {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -651,11 +673,11 @@
             GrandChildDataChild::None => GrandChildChild::None,
         }
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         let child = match &parent.child {
             ParentDataChild::Child(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ParentDataChild::Child),
                     actual: format!("{:?}", & parent.child),
                 });
@@ -664,7 +686,7 @@
         let grandchild = match &child.child {
             ChildDataChild::GrandChild(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ChildDataChild::GrandChild),
                     actual: format!("{:?}", & child.child),
                 });
@@ -684,7 +706,7 @@
     pub fn get_quux(&self) -> Enum16 {
         self.child.quux
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.grandchild.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -773,12 +795,12 @@
     fn conforms(bytes: &[u8]) -> bool {
         true
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let payload = bytes.get();
         bytes.get_mut().advance(payload.len());
         let child = match () {
@@ -789,11 +811,12 @@
         };
         Ok(Self { child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         match &self.child {
             GrandGrandChildDataChild::Payload(payload) => buffer.put_slice(payload),
             GrandGrandChildDataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -803,23 +826,26 @@
     }
 }
 impl Packet for GrandGrandChild {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<GrandGrandChild> for Bytes {
-    fn from(packet: GrandGrandChild) -> Self {
-        packet.to_bytes()
+impl TryFrom<GrandGrandChild> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: GrandGrandChild) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<GrandGrandChild> for Vec<u8> {
-    fn from(packet: GrandGrandChild) -> Self {
-        packet.to_vec()
+impl TryFrom<GrandGrandChild> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: GrandGrandChild) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<GrandGrandChild> for Parent {
@@ -838,18 +864,18 @@
     }
 }
 impl TryFrom<Parent> for GrandGrandChild {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<GrandGrandChild> {
+    type Error = DecodeError;
+    fn try_from(packet: Parent) -> Result<GrandGrandChild, Self::Error> {
         GrandGrandChild::new(packet.parent)
     }
 }
 impl GrandGrandChild {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -861,11 +887,11 @@
             GrandGrandChildDataChild::None => GrandGrandChildChild::None,
         }
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         let child = match &parent.child {
             ParentDataChild::Child(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ParentDataChild::Child),
                     actual: format!("{:?}", & parent.child),
                 });
@@ -874,7 +900,7 @@
         let grandchild = match &child.child {
             ChildDataChild::GrandChild(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ChildDataChild::GrandChild),
                     actual: format!("{:?}", & child.child),
                 });
@@ -883,7 +909,7 @@
         let grandgrandchild = match &grandchild.child {
             GrandChildDataChild::GrandGrandChild(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(GrandChildDataChild::GrandGrandChild),
                     actual: format!("{:?}", & grandchild.child),
                 });
@@ -914,7 +940,7 @@
             GrandGrandChildDataChild::None => &[],
         }
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.grandgrandchild.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/rust_legacy/packet_decl_mask_scalar_value_big_endian.rs b/tests/generated/rust_legacy/packet_decl_mask_scalar_value_big_endian.rs
new file mode 100644
index 0000000..fc554df
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_mask_scalar_value_big_endian.rs
@@ -0,0 +1,171 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {
+    a: u8,
+    b: u32,
+    c: u8,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {
+    pub a: u8,
+    pub b: u32,
+    pub c: u8,
+}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 4
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 4 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 4,
+                got: bytes.get().remaining(),
+            });
+        }
+        let chunk = bytes.get_mut().get_u32();
+        let a = (chunk & 0x3) as u8;
+        let b = ((chunk >> 2) & 0xff_ffff);
+        let c = ((chunk >> 26) & 0x3f) as u8;
+        Ok(Self { a, b, c })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        if self.a > 0x3 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a as u64,
+                maximum_value: 0x3,
+            });
+        }
+        if self.b > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "b",
+                value: self.b as u64,
+                maximum_value: 0xff_ffff,
+            });
+        }
+        if self.c > 0x3f {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "c",
+                value: self.c as u64,
+                maximum_value: 0x3f,
+            });
+        }
+        let value = (self.a as u32) | (self.b << 2) | ((self.c as u32) << 26);
+        buffer.put_u32(value);
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        4
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    pub fn get_a(&self) -> u8 {
+        self.foo.a
+    }
+    pub fn get_b(&self) -> u32 {
+        self.foo.b
+    }
+    pub fn get_c(&self) -> u8 {
+        self.foo.c
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData {
+            a: self.a,
+            b: self.b,
+            c: self.c,
+        };
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/rust_legacy/packet_decl_mask_scalar_value_little_endian.rs b/tests/generated/rust_legacy/packet_decl_mask_scalar_value_little_endian.rs
new file mode 100644
index 0000000..a736eb7
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_mask_scalar_value_little_endian.rs
@@ -0,0 +1,171 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {
+    a: u8,
+    b: u32,
+    c: u8,
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {
+    pub a: u8,
+    pub b: u32,
+    pub c: u8,
+}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 4
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 4 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 4,
+                got: bytes.get().remaining(),
+            });
+        }
+        let chunk = bytes.get_mut().get_u32_le();
+        let a = (chunk & 0x3) as u8;
+        let b = ((chunk >> 2) & 0xff_ffff);
+        let c = ((chunk >> 26) & 0x3f) as u8;
+        Ok(Self { a, b, c })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        if self.a > 0x3 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a as u64,
+                maximum_value: 0x3,
+            });
+        }
+        if self.b > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "b",
+                value: self.b as u64,
+                maximum_value: 0xff_ffff,
+            });
+        }
+        if self.c > 0x3f {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "c",
+                value: self.c as u64,
+                maximum_value: 0x3f,
+            });
+        }
+        let value = (self.a as u32) | (self.b << 2) | ((self.c as u32) << 26);
+        buffer.put_u32_le(value);
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        4
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    pub fn get_a(&self) -> u8 {
+        self.foo.a
+    }
+    pub fn get_b(&self) -> u32 {
+        self.foo.b
+    }
+    pub fn get_c(&self) -> u8 {
+        self.foo.c
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData {
+            a: self.a,
+            b: self.b,
+            c: self.c,
+        };
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/packet_decl_mixed_scalars_enums_big_endian.rs b/tests/generated/rust_legacy/packet_decl_mixed_scalars_enums_big_endian.rs
similarity index 71%
rename from tests/generated/packet_decl_mixed_scalars_enums_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_mixed_scalars_enums_big_endian.rs
index 1bf676b..16f516b 100644
--- a/tests/generated/packet_decl_mixed_scalars_enums_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_mixed_scalars_enums_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u8> for Enum7 {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Enum7::A),
             0x2 => Ok(Enum7::B),
@@ -94,7 +99,7 @@
 }
 impl TryFrom<u16> for Enum9 {
     type Error = u16;
-    fn try_from(value: u16) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Enum9::A),
             0x2 => Ok(Enum9::B),
@@ -166,48 +171,59 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 3
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 3,
                 got: bytes.get().remaining(),
             });
         }
         let chunk = bytes.get_mut().get_uint(3) as u32;
         let x = Enum7::try_from((chunk & 0x7f) as u8)
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Foo".to_string(),
-                field: "x".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Foo",
+                field: "x",
                 value: unknown_val as u64,
-                type_: "Enum7".to_string(),
+                type_: "Enum7",
             })?;
         let y = ((chunk >> 7) & 0x1f) as u8;
         let z = Enum9::try_from(((chunk >> 12) & 0x1ff) as u16)
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Foo".to_string(),
-                field: "z".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Foo",
+                field: "z",
                 value: unknown_val as u64,
-                type_: "Enum9".to_string(),
+                type_: "Enum9",
             })?;
         let w = ((chunk >> 21) & 0x7) as u8;
         Ok(Self { x, y, z, w })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         if self.y > 0x1f {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "y", self.y, 0x1f);
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "y",
+                value: self.y as u64,
+                maximum_value: 0x1f,
+            });
         }
         if self.w > 0x7 {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "w", self.w, 0x7);
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "w",
+                value: self.w as u64,
+                maximum_value: 0x7,
+            });
         }
         let value = (u8::from(self.x) as u32) | ((self.y as u32) << 7)
             | ((u16::from(self.z) as u32) << 12) | ((self.w as u32) << 21);
         buffer.put_uint(value as u64, 3);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -217,36 +233,39 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_w(&self) -> u8 {
@@ -261,7 +280,7 @@
     pub fn get_z(&self) -> Enum9 {
         self.foo.z
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_mixed_scalars_enums_little_endian.rs b/tests/generated/rust_legacy/packet_decl_mixed_scalars_enums_little_endian.rs
similarity index 71%
rename from tests/generated/packet_decl_mixed_scalars_enums_little_endian.rs
rename to tests/generated/rust_legacy/packet_decl_mixed_scalars_enums_little_endian.rs
index baa27e3..74f1b15 100644
--- a/tests/generated/packet_decl_mixed_scalars_enums_little_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_mixed_scalars_enums_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -28,7 +33,7 @@
 }
 impl TryFrom<u8> for Enum7 {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Enum7::A),
             0x2 => Ok(Enum7::B),
@@ -94,7 +99,7 @@
 }
 impl TryFrom<u16> for Enum9 {
     type Error = u16;
-    fn try_from(value: u16) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
         match value {
             0x1 => Ok(Enum9::A),
             0x2 => Ok(Enum9::B),
@@ -166,48 +171,59 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 3
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 3,
                 got: bytes.get().remaining(),
             });
         }
         let chunk = bytes.get_mut().get_uint_le(3) as u32;
         let x = Enum7::try_from((chunk & 0x7f) as u8)
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Foo".to_string(),
-                field: "x".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Foo",
+                field: "x",
                 value: unknown_val as u64,
-                type_: "Enum7".to_string(),
+                type_: "Enum7",
             })?;
         let y = ((chunk >> 7) & 0x1f) as u8;
         let z = Enum9::try_from(((chunk >> 12) & 0x1ff) as u16)
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Foo".to_string(),
-                field: "z".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Foo",
+                field: "z",
                 value: unknown_val as u64,
-                type_: "Enum9".to_string(),
+                type_: "Enum9",
             })?;
         let w = ((chunk >> 21) & 0x7) as u8;
         Ok(Self { x, y, z, w })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         if self.y > 0x1f {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "y", self.y, 0x1f);
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "y",
+                value: self.y as u64,
+                maximum_value: 0x1f,
+            });
         }
         if self.w > 0x7 {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "w", self.w, 0x7);
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "w",
+                value: self.w as u64,
+                maximum_value: 0x7,
+            });
         }
         let value = (u8::from(self.x) as u32) | ((self.y as u32) << 7)
             | ((u16::from(self.z) as u32) << 12) | ((self.w as u32) << 21);
         buffer.put_uint_le(value as u64, 3);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -217,36 +233,39 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_w(&self) -> u8 {
@@ -261,7 +280,7 @@
     pub fn get_z(&self) -> Enum9 {
         self.foo.z
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_parent_with_alias_child_big_endian.rs b/tests/generated/rust_legacy/packet_decl_parent_with_alias_child_big_endian.rs
similarity index 76%
rename from tests/generated/packet_decl_parent_with_alias_child_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_parent_with_alias_child_big_endian.rs
index c0a1cf1..7622688 100644
--- a/tests/generated/packet_decl_parent_with_alias_child_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_parent_with_alias_child_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -29,7 +34,7 @@
 }
 impl TryFrom<u8> for Enum8 {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(Enum8::A),
             0x1 => Ok(Enum8::B),
@@ -130,25 +135,25 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 1
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Parent".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
         }
         let v = Enum8::try_from(bytes.get_mut().get_u8())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Parent".to_string(),
-                field: "v".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "v",
                 value: unknown_val as u64,
-                type_: "Enum8".to_string(),
+                type_: "Enum8",
             })?;
         let payload = bytes.get();
         bytes.get_mut().advance(payload.len());
@@ -170,14 +175,15 @@
         };
         Ok(Self { v, child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u8(u8::from(self.v));
         match &self.child {
-            ParentDataChild::AliasChild(child) => child.write_to(buffer),
-            ParentDataChild::NormalChild(child) => child.write_to(buffer),
+            ParentDataChild::AliasChild(child) => child.write_to(buffer)?,
+            ParentDataChild::NormalChild(child) => child.write_to(buffer)?,
             ParentDataChild::Payload(payload) => buffer.put_slice(payload),
             ParentDataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -187,32 +193,35 @@
     }
 }
 impl Packet for Parent {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Parent> for Bytes {
-    fn from(packet: Parent) -> Self {
-        packet.to_bytes()
+impl TryFrom<Parent> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Parent) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Parent> for Vec<u8> {
-    fn from(packet: Parent) -> Self {
-        packet.to_vec()
+impl TryFrom<Parent> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Parent) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Parent {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -228,13 +237,13 @@
             ParentDataChild::None => ParentChild::None,
         }
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         Ok(Self { parent })
     }
     pub fn get_v(&self) -> Enum8 {
         self.parent.v
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.parent.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -307,12 +316,12 @@
     fn conforms(bytes: &[u8]) -> bool {
         true
     }
-    fn parse(bytes: &[u8], v: Enum8) -> Result<Self> {
+    fn parse(bytes: &[u8], v: Enum8) -> Result<Self, DecodeError> {
         let mut cell = Cell::new(bytes);
         let packet = Self::parse_inner(&mut cell, v)?;
         Ok(packet)
     }
-    fn parse_inner(mut bytes: &mut Cell<&[u8]>, v: Enum8) -> Result<Self> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>, v: Enum8) -> Result<Self, DecodeError> {
         let payload = bytes.get();
         bytes.get_mut().advance(payload.len());
         let child = match (v) {
@@ -333,13 +342,14 @@
         };
         Ok(Self { child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         match &self.child {
-            AliasChildDataChild::NormalGrandChild1(child) => child.write_to(buffer),
-            AliasChildDataChild::NormalGrandChild2(child) => child.write_to(buffer),
+            AliasChildDataChild::NormalGrandChild1(child) => child.write_to(buffer)?,
+            AliasChildDataChild::NormalGrandChild2(child) => child.write_to(buffer)?,
             AliasChildDataChild::Payload(payload) => buffer.put_slice(payload),
             AliasChildDataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -349,23 +359,26 @@
     }
 }
 impl Packet for AliasChild {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<AliasChild> for Bytes {
-    fn from(packet: AliasChild) -> Self {
-        packet.to_bytes()
+impl TryFrom<AliasChild> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: AliasChild) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<AliasChild> for Vec<u8> {
-    fn from(packet: AliasChild) -> Self {
-        packet.to_vec()
+impl TryFrom<AliasChild> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: AliasChild) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<AliasChild> for Parent {
@@ -374,18 +387,18 @@
     }
 }
 impl TryFrom<Parent> for AliasChild {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<AliasChild> {
+    type Error = DecodeError;
+    fn try_from(packet: Parent) -> Result<AliasChild, Self::Error> {
         AliasChild::new(packet.parent)
     }
 }
 impl AliasChild {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -407,11 +420,11 @@
             AliasChildDataChild::None => AliasChildChild::None,
         }
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         let aliaschild = match &parent.child {
             ParentDataChild::AliasChild(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ParentDataChild::AliasChild),
                     actual: format!("{:?}", & parent.child),
                 });
@@ -422,7 +435,7 @@
     pub fn get_v(&self) -> Enum8 {
         self.parent.v
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.aliaschild.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -472,15 +485,17 @@
     fn conforms(bytes: &[u8]) -> bool {
         true
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         Ok(Self {})
     }
-    fn write_to(&self, buffer: &mut BytesMut) {}
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        Ok(())
+    }
     fn get_total_size(&self) -> usize {
         self.get_size()
     }
@@ -489,23 +504,26 @@
     }
 }
 impl Packet for NormalChild {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<NormalChild> for Bytes {
-    fn from(packet: NormalChild) -> Self {
-        packet.to_bytes()
+impl TryFrom<NormalChild> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: NormalChild) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<NormalChild> for Vec<u8> {
-    fn from(packet: NormalChild) -> Self {
-        packet.to_vec()
+impl TryFrom<NormalChild> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: NormalChild) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<NormalChild> for Parent {
@@ -514,26 +532,26 @@
     }
 }
 impl TryFrom<Parent> for NormalChild {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<NormalChild> {
+    type Error = DecodeError;
+    fn try_from(packet: Parent) -> Result<NormalChild, Self::Error> {
         NormalChild::new(packet.parent)
     }
 }
 impl NormalChild {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         let normalchild = match &parent.child {
             ParentDataChild::NormalChild(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ParentDataChild::NormalChild),
                     actual: format!("{:?}", & parent.child),
                 });
@@ -544,7 +562,7 @@
     pub fn get_v(&self) -> Enum8 {
         self.parent.v
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.normalchild.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -591,15 +609,17 @@
     fn conforms(bytes: &[u8]) -> bool {
         true
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         Ok(Self {})
     }
-    fn write_to(&self, buffer: &mut BytesMut) {}
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        Ok(())
+    }
     fn get_total_size(&self) -> usize {
         self.get_size()
     }
@@ -608,23 +628,26 @@
     }
 }
 impl Packet for NormalGrandChild1 {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<NormalGrandChild1> for Bytes {
-    fn from(packet: NormalGrandChild1) -> Self {
-        packet.to_bytes()
+impl TryFrom<NormalGrandChild1> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: NormalGrandChild1) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<NormalGrandChild1> for Vec<u8> {
-    fn from(packet: NormalGrandChild1) -> Self {
-        packet.to_vec()
+impl TryFrom<NormalGrandChild1> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: NormalGrandChild1) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<NormalGrandChild1> for Parent {
@@ -638,26 +661,26 @@
     }
 }
 impl TryFrom<Parent> for NormalGrandChild1 {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<NormalGrandChild1> {
+    type Error = DecodeError;
+    fn try_from(packet: Parent) -> Result<NormalGrandChild1, Self::Error> {
         NormalGrandChild1::new(packet.parent)
     }
 }
 impl NormalGrandChild1 {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         let aliaschild = match &parent.child {
             ParentDataChild::AliasChild(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ParentDataChild::AliasChild),
                     actual: format!("{:?}", & parent.child),
                 });
@@ -666,7 +689,7 @@
         let normalgrandchild1 = match &aliaschild.child {
             AliasChildDataChild::NormalGrandChild1(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(AliasChildDataChild::NormalGrandChild1),
                     actual: format!("{:?}", & aliaschild.child),
                 });
@@ -681,7 +704,7 @@
     pub fn get_v(&self) -> Enum8 {
         self.parent.v
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.normalgrandchild1.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -760,12 +783,12 @@
     fn conforms(bytes: &[u8]) -> bool {
         true
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let payload = bytes.get();
         bytes.get_mut().advance(payload.len());
         let child = match () {
@@ -776,11 +799,12 @@
         };
         Ok(Self { child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         match &self.child {
             NormalGrandChild2DataChild::Payload(payload) => buffer.put_slice(payload),
             NormalGrandChild2DataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -790,23 +814,26 @@
     }
 }
 impl Packet for NormalGrandChild2 {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<NormalGrandChild2> for Bytes {
-    fn from(packet: NormalGrandChild2) -> Self {
-        packet.to_bytes()
+impl TryFrom<NormalGrandChild2> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: NormalGrandChild2) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<NormalGrandChild2> for Vec<u8> {
-    fn from(packet: NormalGrandChild2) -> Self {
-        packet.to_vec()
+impl TryFrom<NormalGrandChild2> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: NormalGrandChild2) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<NormalGrandChild2> for Parent {
@@ -820,18 +847,18 @@
     }
 }
 impl TryFrom<Parent> for NormalGrandChild2 {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<NormalGrandChild2> {
+    type Error = DecodeError;
+    fn try_from(packet: Parent) -> Result<NormalGrandChild2, Self::Error> {
         NormalGrandChild2::new(packet.parent)
     }
 }
 impl NormalGrandChild2 {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -843,11 +870,11 @@
             NormalGrandChild2DataChild::None => NormalGrandChild2Child::None,
         }
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         let aliaschild = match &parent.child {
             ParentDataChild::AliasChild(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ParentDataChild::AliasChild),
                     actual: format!("{:?}", & parent.child),
                 });
@@ -856,7 +883,7 @@
         let normalgrandchild2 = match &aliaschild.child {
             AliasChildDataChild::NormalGrandChild2(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(AliasChildDataChild::NormalGrandChild2),
                     actual: format!("{:?}", & aliaschild.child),
                 });
@@ -877,7 +904,7 @@
             NormalGrandChild2DataChild::None => &[],
         }
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.normalgrandchild2.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_parent_with_alias_child_big_endian.rs b/tests/generated/rust_legacy/packet_decl_parent_with_alias_child_little_endian.rs
similarity index 76%
copy from tests/generated/packet_decl_parent_with_alias_child_big_endian.rs
copy to tests/generated/rust_legacy/packet_decl_parent_with_alias_child_little_endian.rs
index c0a1cf1..7622688 100644
--- a/tests/generated/packet_decl_parent_with_alias_child_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_parent_with_alias_child_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -29,7 +34,7 @@
 }
 impl TryFrom<u8> for Enum8 {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(Enum8::A),
             0x1 => Ok(Enum8::B),
@@ -130,25 +135,25 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 1
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Parent".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
         }
         let v = Enum8::try_from(bytes.get_mut().get_u8())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Parent".to_string(),
-                field: "v".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "v",
                 value: unknown_val as u64,
-                type_: "Enum8".to_string(),
+                type_: "Enum8",
             })?;
         let payload = bytes.get();
         bytes.get_mut().advance(payload.len());
@@ -170,14 +175,15 @@
         };
         Ok(Self { v, child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u8(u8::from(self.v));
         match &self.child {
-            ParentDataChild::AliasChild(child) => child.write_to(buffer),
-            ParentDataChild::NormalChild(child) => child.write_to(buffer),
+            ParentDataChild::AliasChild(child) => child.write_to(buffer)?,
+            ParentDataChild::NormalChild(child) => child.write_to(buffer)?,
             ParentDataChild::Payload(payload) => buffer.put_slice(payload),
             ParentDataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -187,32 +193,35 @@
     }
 }
 impl Packet for Parent {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Parent> for Bytes {
-    fn from(packet: Parent) -> Self {
-        packet.to_bytes()
+impl TryFrom<Parent> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Parent) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Parent> for Vec<u8> {
-    fn from(packet: Parent) -> Self {
-        packet.to_vec()
+impl TryFrom<Parent> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Parent) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Parent {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -228,13 +237,13 @@
             ParentDataChild::None => ParentChild::None,
         }
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         Ok(Self { parent })
     }
     pub fn get_v(&self) -> Enum8 {
         self.parent.v
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.parent.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -307,12 +316,12 @@
     fn conforms(bytes: &[u8]) -> bool {
         true
     }
-    fn parse(bytes: &[u8], v: Enum8) -> Result<Self> {
+    fn parse(bytes: &[u8], v: Enum8) -> Result<Self, DecodeError> {
         let mut cell = Cell::new(bytes);
         let packet = Self::parse_inner(&mut cell, v)?;
         Ok(packet)
     }
-    fn parse_inner(mut bytes: &mut Cell<&[u8]>, v: Enum8) -> Result<Self> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>, v: Enum8) -> Result<Self, DecodeError> {
         let payload = bytes.get();
         bytes.get_mut().advance(payload.len());
         let child = match (v) {
@@ -333,13 +342,14 @@
         };
         Ok(Self { child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         match &self.child {
-            AliasChildDataChild::NormalGrandChild1(child) => child.write_to(buffer),
-            AliasChildDataChild::NormalGrandChild2(child) => child.write_to(buffer),
+            AliasChildDataChild::NormalGrandChild1(child) => child.write_to(buffer)?,
+            AliasChildDataChild::NormalGrandChild2(child) => child.write_to(buffer)?,
             AliasChildDataChild::Payload(payload) => buffer.put_slice(payload),
             AliasChildDataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -349,23 +359,26 @@
     }
 }
 impl Packet for AliasChild {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<AliasChild> for Bytes {
-    fn from(packet: AliasChild) -> Self {
-        packet.to_bytes()
+impl TryFrom<AliasChild> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: AliasChild) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<AliasChild> for Vec<u8> {
-    fn from(packet: AliasChild) -> Self {
-        packet.to_vec()
+impl TryFrom<AliasChild> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: AliasChild) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<AliasChild> for Parent {
@@ -374,18 +387,18 @@
     }
 }
 impl TryFrom<Parent> for AliasChild {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<AliasChild> {
+    type Error = DecodeError;
+    fn try_from(packet: Parent) -> Result<AliasChild, Self::Error> {
         AliasChild::new(packet.parent)
     }
 }
 impl AliasChild {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -407,11 +420,11 @@
             AliasChildDataChild::None => AliasChildChild::None,
         }
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         let aliaschild = match &parent.child {
             ParentDataChild::AliasChild(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ParentDataChild::AliasChild),
                     actual: format!("{:?}", & parent.child),
                 });
@@ -422,7 +435,7 @@
     pub fn get_v(&self) -> Enum8 {
         self.parent.v
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.aliaschild.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -472,15 +485,17 @@
     fn conforms(bytes: &[u8]) -> bool {
         true
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         Ok(Self {})
     }
-    fn write_to(&self, buffer: &mut BytesMut) {}
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        Ok(())
+    }
     fn get_total_size(&self) -> usize {
         self.get_size()
     }
@@ -489,23 +504,26 @@
     }
 }
 impl Packet for NormalChild {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<NormalChild> for Bytes {
-    fn from(packet: NormalChild) -> Self {
-        packet.to_bytes()
+impl TryFrom<NormalChild> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: NormalChild) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<NormalChild> for Vec<u8> {
-    fn from(packet: NormalChild) -> Self {
-        packet.to_vec()
+impl TryFrom<NormalChild> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: NormalChild) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<NormalChild> for Parent {
@@ -514,26 +532,26 @@
     }
 }
 impl TryFrom<Parent> for NormalChild {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<NormalChild> {
+    type Error = DecodeError;
+    fn try_from(packet: Parent) -> Result<NormalChild, Self::Error> {
         NormalChild::new(packet.parent)
     }
 }
 impl NormalChild {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         let normalchild = match &parent.child {
             ParentDataChild::NormalChild(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ParentDataChild::NormalChild),
                     actual: format!("{:?}", & parent.child),
                 });
@@ -544,7 +562,7 @@
     pub fn get_v(&self) -> Enum8 {
         self.parent.v
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.normalchild.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -591,15 +609,17 @@
     fn conforms(bytes: &[u8]) -> bool {
         true
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         Ok(Self {})
     }
-    fn write_to(&self, buffer: &mut BytesMut) {}
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        Ok(())
+    }
     fn get_total_size(&self) -> usize {
         self.get_size()
     }
@@ -608,23 +628,26 @@
     }
 }
 impl Packet for NormalGrandChild1 {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<NormalGrandChild1> for Bytes {
-    fn from(packet: NormalGrandChild1) -> Self {
-        packet.to_bytes()
+impl TryFrom<NormalGrandChild1> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: NormalGrandChild1) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<NormalGrandChild1> for Vec<u8> {
-    fn from(packet: NormalGrandChild1) -> Self {
-        packet.to_vec()
+impl TryFrom<NormalGrandChild1> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: NormalGrandChild1) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<NormalGrandChild1> for Parent {
@@ -638,26 +661,26 @@
     }
 }
 impl TryFrom<Parent> for NormalGrandChild1 {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<NormalGrandChild1> {
+    type Error = DecodeError;
+    fn try_from(packet: Parent) -> Result<NormalGrandChild1, Self::Error> {
         NormalGrandChild1::new(packet.parent)
     }
 }
 impl NormalGrandChild1 {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         let aliaschild = match &parent.child {
             ParentDataChild::AliasChild(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ParentDataChild::AliasChild),
                     actual: format!("{:?}", & parent.child),
                 });
@@ -666,7 +689,7 @@
         let normalgrandchild1 = match &aliaschild.child {
             AliasChildDataChild::NormalGrandChild1(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(AliasChildDataChild::NormalGrandChild1),
                     actual: format!("{:?}", & aliaschild.child),
                 });
@@ -681,7 +704,7 @@
     pub fn get_v(&self) -> Enum8 {
         self.parent.v
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.normalgrandchild1.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -760,12 +783,12 @@
     fn conforms(bytes: &[u8]) -> bool {
         true
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let payload = bytes.get();
         bytes.get_mut().advance(payload.len());
         let child = match () {
@@ -776,11 +799,12 @@
         };
         Ok(Self { child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         match &self.child {
             NormalGrandChild2DataChild::Payload(payload) => buffer.put_slice(payload),
             NormalGrandChild2DataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -790,23 +814,26 @@
     }
 }
 impl Packet for NormalGrandChild2 {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<NormalGrandChild2> for Bytes {
-    fn from(packet: NormalGrandChild2) -> Self {
-        packet.to_bytes()
+impl TryFrom<NormalGrandChild2> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: NormalGrandChild2) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<NormalGrandChild2> for Vec<u8> {
-    fn from(packet: NormalGrandChild2) -> Self {
-        packet.to_vec()
+impl TryFrom<NormalGrandChild2> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: NormalGrandChild2) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<NormalGrandChild2> for Parent {
@@ -820,18 +847,18 @@
     }
 }
 impl TryFrom<Parent> for NormalGrandChild2 {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<NormalGrandChild2> {
+    type Error = DecodeError;
+    fn try_from(packet: Parent) -> Result<NormalGrandChild2, Self::Error> {
         NormalGrandChild2::new(packet.parent)
     }
 }
 impl NormalGrandChild2 {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -843,11 +870,11 @@
             NormalGrandChild2DataChild::None => NormalGrandChild2Child::None,
         }
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         let aliaschild = match &parent.child {
             ParentDataChild::AliasChild(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ParentDataChild::AliasChild),
                     actual: format!("{:?}", & parent.child),
                 });
@@ -856,7 +883,7 @@
         let normalgrandchild2 = match &aliaschild.child {
             AliasChildDataChild::NormalGrandChild2(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(AliasChildDataChild::NormalGrandChild2),
                     actual: format!("{:?}", & aliaschild.child),
                 });
@@ -877,7 +904,7 @@
             NormalGrandChild2DataChild::None => &[],
         }
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.normalgrandchild2.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_parent_with_no_payload_big_endian.rs b/tests/generated/rust_legacy/packet_decl_parent_with_no_payload_big_endian.rs
similarity index 71%
rename from tests/generated/packet_decl_parent_with_no_payload_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_parent_with_no_payload_big_endian.rs
index 4bb083b..a457c0a 100644
--- a/tests/generated/packet_decl_parent_with_no_payload_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_parent_with_no_payload_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -27,7 +32,7 @@
 }
 impl TryFrom<u8> for Enum8 {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(Enum8::A),
             _ => Err(value),
@@ -121,25 +126,25 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 1
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Parent".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
         }
         let v = Enum8::try_from(bytes.get_mut().get_u8())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Parent".to_string(),
-                field: "v".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "v",
                 value: unknown_val as u64,
-                type_: "Enum8".to_string(),
+                type_: "Enum8",
             })?;
         let payload: &[u8] = &[];
         let child = match (v) {
@@ -155,8 +160,9 @@
         };
         Ok(Self { v, child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u8(u8::from(self.v));
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -166,32 +172,35 @@
     }
 }
 impl Packet for Parent {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Parent> for Bytes {
-    fn from(packet: Parent) -> Self {
-        packet.to_bytes()
+impl TryFrom<Parent> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Parent) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Parent> for Vec<u8> {
-    fn from(packet: Parent) -> Self {
-        packet.to_vec()
+impl TryFrom<Parent> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Parent) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Parent {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -204,13 +213,13 @@
             ParentDataChild::None => ParentChild::None,
         }
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         Ok(Self { parent })
     }
     pub fn get_v(&self) -> Enum8 {
         self.parent.v
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.parent.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -249,15 +258,17 @@
     fn conforms(bytes: &[u8]) -> bool {
         true
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         Ok(Self {})
     }
-    fn write_to(&self, buffer: &mut BytesMut) {}
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        Ok(())
+    }
     fn get_total_size(&self) -> usize {
         self.get_size()
     }
@@ -266,23 +277,26 @@
     }
 }
 impl Packet for Child {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Child> for Bytes {
-    fn from(packet: Child) -> Self {
-        packet.to_bytes()
+impl TryFrom<Child> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Child) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Child> for Vec<u8> {
-    fn from(packet: Child) -> Self {
-        packet.to_vec()
+impl TryFrom<Child> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Child) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<Child> for Parent {
@@ -291,26 +305,26 @@
     }
 }
 impl TryFrom<Parent> for Child {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<Child> {
+    type Error = DecodeError;
+    fn try_from(packet: Parent) -> Result<Child, Self::Error> {
         Child::new(packet.parent)
     }
 }
 impl Child {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         let child = match &parent.child {
             ParentDataChild::Child(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ParentDataChild::Child),
                     actual: format!("{:?}", & parent.child),
                 });
@@ -321,7 +335,7 @@
     pub fn get_v(&self) -> Enum8 {
         self.parent.v
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.child.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_parent_with_no_payload_big_endian.rs b/tests/generated/rust_legacy/packet_decl_parent_with_no_payload_little_endian.rs
similarity index 71%
copy from tests/generated/packet_decl_parent_with_no_payload_big_endian.rs
copy to tests/generated/rust_legacy/packet_decl_parent_with_no_payload_little_endian.rs
index 4bb083b..a457c0a 100644
--- a/tests/generated/packet_decl_parent_with_no_payload_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_parent_with_no_payload_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[repr(u64)]
 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -27,7 +32,7 @@
 }
 impl TryFrom<u8> for Enum8 {
     type Error = u8;
-    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
             0x0 => Ok(Enum8::A),
             _ => Err(value),
@@ -121,25 +126,25 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 1
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Parent".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
         }
         let v = Enum8::try_from(bytes.get_mut().get_u8())
-            .map_err(|unknown_val| Error::InvalidEnumValueError {
-                obj: "Parent".to_string(),
-                field: "v".to_string(),
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "v",
                 value: unknown_val as u64,
-                type_: "Enum8".to_string(),
+                type_: "Enum8",
             })?;
         let payload: &[u8] = &[];
         let child = match (v) {
@@ -155,8 +160,9 @@
         };
         Ok(Self { v, child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u8(u8::from(self.v));
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -166,32 +172,35 @@
     }
 }
 impl Packet for Parent {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Parent> for Bytes {
-    fn from(packet: Parent) -> Self {
-        packet.to_bytes()
+impl TryFrom<Parent> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Parent) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Parent> for Vec<u8> {
-    fn from(packet: Parent) -> Self {
-        packet.to_vec()
+impl TryFrom<Parent> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Parent) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Parent {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -204,13 +213,13 @@
             ParentDataChild::None => ParentChild::None,
         }
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         Ok(Self { parent })
     }
     pub fn get_v(&self) -> Enum8 {
         self.parent.v
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.parent.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
@@ -249,15 +258,17 @@
     fn conforms(bytes: &[u8]) -> bool {
         true
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         Ok(Self {})
     }
-    fn write_to(&self, buffer: &mut BytesMut) {}
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        Ok(())
+    }
     fn get_total_size(&self) -> usize {
         self.get_size()
     }
@@ -266,23 +277,26 @@
     }
 }
 impl Packet for Child {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.parent.get_size());
-        self.parent.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.parent.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Child> for Bytes {
-    fn from(packet: Child) -> Self {
-        packet.to_bytes()
+impl TryFrom<Child> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Child) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Child> for Vec<u8> {
-    fn from(packet: Child) -> Self {
-        packet.to_vec()
+impl TryFrom<Child> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Child) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl From<Child> for Parent {
@@ -291,26 +305,26 @@
     }
 }
 impl TryFrom<Parent> for Child {
-    type Error = Error;
-    fn try_from(packet: Parent) -> Result<Child> {
+    type Error = DecodeError;
+    fn try_from(packet: Parent) -> Result<Child, Self::Error> {
         Child::new(packet.parent)
     }
 }
 impl Child {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = ParentData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(parent: ParentData) -> Result<Self> {
+    fn new(parent: ParentData) -> Result<Self, DecodeError> {
         let child = match &parent.child {
             ParentDataChild::Child(value) => value.clone(),
             _ => {
-                return Err(Error::InvalidChildError {
+                return Err(DecodeError::InvalidChildError {
                     expected: stringify!(ParentDataChild::Child),
                     actual: format!("{:?}", & parent.child),
                 });
@@ -321,7 +335,7 @@
     pub fn get_v(&self) -> Enum8 {
         self.parent.v
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.child.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_payload_field_unknown_size_big_endian.rs b/tests/generated/rust_legacy/packet_decl_payload_field_unknown_size_big_endian.rs
similarity index 70%
rename from tests/generated/packet_decl_payload_field_unknown_size_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_payload_field_unknown_size_big_endian.rs
index bfbffe7..c5fdf91 100644
--- a/tests/generated/packet_decl_payload_field_unknown_size_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_payload_field_unknown_size_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub enum FooDataChild {
@@ -60,15 +65,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 3
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 3,
                 got: bytes.get().remaining(),
             });
@@ -84,15 +89,21 @@
         };
         Ok(Self { a, child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         if self.a > 0xff_ffff {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0xff_ffff);
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a as u64,
+                maximum_value: 0xff_ffff,
+            });
         }
         buffer.put_uint(self.a as u64, 3);
         match &self.child {
             FooDataChild::Payload(payload) => buffer.put_slice(payload),
             FooDataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -102,32 +113,35 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -137,7 +151,7 @@
             FooDataChild::None => FooChild::None,
         }
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_a(&self) -> u32 {
@@ -149,7 +163,7 @@
             FooDataChild::None => &[],
         }
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_payload_field_unknown_size_little_endian.rs b/tests/generated/rust_legacy/packet_decl_payload_field_unknown_size_little_endian.rs
similarity index 70%
rename from tests/generated/packet_decl_payload_field_unknown_size_little_endian.rs
rename to tests/generated/rust_legacy/packet_decl_payload_field_unknown_size_little_endian.rs
index e473774..43cbfa1 100644
--- a/tests/generated/packet_decl_payload_field_unknown_size_little_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_payload_field_unknown_size_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub enum FooDataChild {
@@ -60,15 +65,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 3
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 3,
                 got: bytes.get().remaining(),
             });
@@ -84,15 +89,21 @@
         };
         Ok(Self { a, child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         if self.a > 0xff_ffff {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0xff_ffff);
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a as u64,
+                maximum_value: 0xff_ffff,
+            });
         }
         buffer.put_uint_le(self.a as u64, 3);
         match &self.child {
             FooDataChild::Payload(payload) => buffer.put_slice(payload),
             FooDataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -102,32 +113,35 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -137,7 +151,7 @@
             FooDataChild::None => FooChild::None,
         }
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_a(&self) -> u32 {
@@ -149,7 +163,7 @@
             FooDataChild::None => &[],
         }
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_payload_field_unknown_size_terminal_big_endian.rs b/tests/generated/rust_legacy/packet_decl_payload_field_unknown_size_terminal_big_endian.rs
similarity index 69%
rename from tests/generated/packet_decl_payload_field_unknown_size_terminal_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_payload_field_unknown_size_terminal_big_endian.rs
index c37ff2b..0c1f2e9 100644
--- a/tests/generated/packet_decl_payload_field_unknown_size_terminal_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_payload_field_unknown_size_terminal_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub enum FooDataChild {
@@ -60,15 +65,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 3
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 3,
                 got: bytes.get().remaining(),
             });
@@ -76,8 +81,8 @@
         let payload = &bytes.get()[..bytes.get().len() - 3];
         bytes.get_mut().advance(payload.len());
         if bytes.get().remaining() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 3,
                 got: bytes.get().remaining(),
             });
@@ -91,15 +96,21 @@
         };
         Ok(Self { a, child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         match &self.child {
             FooDataChild::Payload(payload) => buffer.put_slice(payload),
             FooDataChild::None => {}
         }
         if self.a > 0xff_ffff {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0xff_ffff);
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a as u64,
+                maximum_value: 0xff_ffff,
+            });
         }
         buffer.put_uint(self.a as u64, 3);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -109,32 +120,35 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -144,7 +158,7 @@
             FooDataChild::None => FooChild::None,
         }
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_a(&self) -> u32 {
@@ -156,7 +170,7 @@
             FooDataChild::None => &[],
         }
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_payload_field_unknown_size_terminal_little_endian.rs b/tests/generated/rust_legacy/packet_decl_payload_field_unknown_size_terminal_little_endian.rs
similarity index 69%
rename from tests/generated/packet_decl_payload_field_unknown_size_terminal_little_endian.rs
rename to tests/generated/rust_legacy/packet_decl_payload_field_unknown_size_terminal_little_endian.rs
index 2e22410..29da976 100644
--- a/tests/generated/packet_decl_payload_field_unknown_size_terminal_little_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_payload_field_unknown_size_terminal_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub enum FooDataChild {
@@ -60,15 +65,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 3
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 3,
                 got: bytes.get().remaining(),
             });
@@ -76,8 +81,8 @@
         let payload = &bytes.get()[..bytes.get().len() - 3];
         bytes.get_mut().advance(payload.len());
         if bytes.get().remaining() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 3,
                 got: bytes.get().remaining(),
             });
@@ -91,15 +96,21 @@
         };
         Ok(Self { a, child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         match &self.child {
             FooDataChild::Payload(payload) => buffer.put_slice(payload),
             FooDataChild::None => {}
         }
         if self.a > 0xff_ffff {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0xff_ffff);
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a as u64,
+                maximum_value: 0xff_ffff,
+            });
         }
         buffer.put_uint_le(self.a as u64, 3);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -109,32 +120,35 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -144,7 +158,7 @@
             FooDataChild::None => FooChild::None,
         }
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_a(&self) -> u32 {
@@ -156,7 +170,7 @@
             FooDataChild::None => &[],
         }
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_payload_field_variable_size_big_endian.rs b/tests/generated/rust_legacy/packet_decl_payload_field_variable_size_big_endian.rs
similarity index 70%
rename from tests/generated/packet_decl_payload_field_variable_size_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_payload_field_variable_size_big_endian.rs
index 5df7232..164875c 100644
--- a/tests/generated/packet_decl_payload_field_variable_size_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_payload_field_variable_size_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub enum FooDataChild {
@@ -62,31 +67,31 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 4
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
         }
         let a = bytes.get_mut().get_u8();
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
         }
         let payload_size = bytes.get_mut().get_u8() as usize;
         if bytes.get().remaining() < payload_size {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: payload_size,
                 got: bytes.get().remaining(),
             });
@@ -94,8 +99,8 @@
         let payload = &bytes.get()[..payload_size];
         bytes.get_mut().advance(payload_size);
         if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 2,
                 got: bytes.get().remaining(),
             });
@@ -109,13 +114,15 @@
         };
         Ok(Self { a, b, child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u8(self.a);
         if self.child.get_total_size() > 0xff {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Foo", "_payload_", self.child
-                .get_total_size(), 0xff
-            );
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: self.child.get_total_size(),
+                maximum_size: 0xff,
+            });
         }
         buffer.put_u8(self.child.get_total_size() as u8);
         match &self.child {
@@ -123,6 +130,7 @@
             FooDataChild::None => {}
         }
         buffer.put_u16(self.b);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -132,32 +140,35 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -167,7 +178,7 @@
             FooDataChild::None => FooChild::None,
         }
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_a(&self) -> u8 {
@@ -182,7 +193,7 @@
             FooDataChild::None => &[],
         }
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_payload_field_variable_size_little_endian.rs b/tests/generated/rust_legacy/packet_decl_payload_field_variable_size_little_endian.rs
similarity index 70%
rename from tests/generated/packet_decl_payload_field_variable_size_little_endian.rs
rename to tests/generated/rust_legacy/packet_decl_payload_field_variable_size_little_endian.rs
index 477c8b6..ff77f86 100644
--- a/tests/generated/packet_decl_payload_field_variable_size_little_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_payload_field_variable_size_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub enum FooDataChild {
@@ -62,31 +67,31 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 4
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
         }
         let a = bytes.get_mut().get_u8();
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
         }
         let payload_size = bytes.get_mut().get_u8() as usize;
         if bytes.get().remaining() < payload_size {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: payload_size,
                 got: bytes.get().remaining(),
             });
@@ -94,8 +99,8 @@
         let payload = &bytes.get()[..payload_size];
         bytes.get_mut().advance(payload_size);
         if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 2,
                 got: bytes.get().remaining(),
             });
@@ -109,13 +114,15 @@
         };
         Ok(Self { a, b, child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u8(self.a);
         if self.child.get_total_size() > 0xff {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Foo", "_payload_", self.child
-                .get_total_size(), 0xff
-            );
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: self.child.get_total_size(),
+                maximum_size: 0xff,
+            });
         }
         buffer.put_u8(self.child.get_total_size() as u8);
         match &self.child {
@@ -123,6 +130,7 @@
             FooDataChild::None => {}
         }
         buffer.put_u16_le(self.b);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -132,32 +140,35 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -167,7 +178,7 @@
             FooDataChild::None => FooChild::None,
         }
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_a(&self) -> u8 {
@@ -182,7 +193,7 @@
             FooDataChild::None => &[],
         }
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/rust_legacy/packet_decl_reserved_field_big_endian.rs b/tests/generated/rust_legacy/packet_decl_reserved_field_big_endian.rs
new file mode 100644
index 0000000..288680c
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_reserved_field_big_endian.rs
@@ -0,0 +1,122 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 5
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 5,
+                got: bytes.get().remaining(),
+            });
+        }
+        bytes.get_mut().advance(5);
+        Ok(Self {})
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        buffer.put_bytes(0, 5);
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        5
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData {};
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/rust_legacy/packet_decl_reserved_field_little_endian.rs b/tests/generated/rust_legacy/packet_decl_reserved_field_little_endian.rs
new file mode 100644
index 0000000..288680c
--- /dev/null
+++ b/tests/generated/rust_legacy/packet_decl_reserved_field_little_endian.rs
@@ -0,0 +1,122 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooData {}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    #[cfg_attr(feature = "serde", serde(flatten))]
+    foo: FooData,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {}
+impl FooData {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 5
+    }
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 5 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 5,
+                got: bytes.get().remaining(),
+            });
+        }
+        bytes.get_mut().advance(5);
+        Ok(Self {})
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        buffer.put_bytes(0, 5);
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        5
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        self.get_size()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
+    }
+}
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Foo {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        let data = FooData::parse_inner(&mut bytes)?;
+        Self::new(data)
+    }
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
+        Ok(Self { foo })
+    }
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buffer)
+    }
+    pub fn get_size(&self) -> usize {
+        self.foo.get_size()
+    }
+}
+impl FooBuilder {
+    pub fn build(self) -> Foo {
+        let foo = FooData {};
+        Foo::new(foo).unwrap()
+    }
+}
+impl From<FooBuilder> for Foo {
+    fn from(builder: FooBuilder) -> Foo {
+        builder.build().into()
+    }
+}
diff --git a/tests/generated/packet_decl_simple_scalars_big_endian.rs b/tests/generated/rust_legacy/packet_decl_simple_scalars_big_endian.rs
similarity index 61%
rename from tests/generated/packet_decl_simple_scalars_big_endian.rs
rename to tests/generated/rust_legacy/packet_decl_simple_scalars_big_endian.rs
index 8c31583..f538606 100644
--- a/tests/generated/packet_decl_simple_scalars_big_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_simple_scalars_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub struct FooData {
@@ -42,31 +47,31 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 6
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
         }
         let x = bytes.get_mut().get_u8();
         if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 2,
                 got: bytes.get().remaining(),
             });
         }
         let y = bytes.get_mut().get_u16();
         if bytes.get().remaining() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 3,
                 got: bytes.get().remaining(),
             });
@@ -74,13 +79,19 @@
         let z = bytes.get_mut().get_uint(3) as u32;
         Ok(Self { x, y, z })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u8(self.x);
         buffer.put_u16(self.y);
         if self.z > 0xff_ffff {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "z", self.z, 0xff_ffff);
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "z",
+                value: self.z as u64,
+                maximum_value: 0xff_ffff,
+            });
         }
         buffer.put_uint(self.z as u64, 3);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -90,36 +101,39 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_x(&self) -> u8 {
@@ -131,7 +145,7 @@
     pub fn get_z(&self) -> u32 {
         self.foo.z
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/packet_decl_simple_scalars_little_endian.rs b/tests/generated/rust_legacy/packet_decl_simple_scalars_little_endian.rs
similarity index 61%
rename from tests/generated/packet_decl_simple_scalars_little_endian.rs
rename to tests/generated/rust_legacy/packet_decl_simple_scalars_little_endian.rs
index d1c3655..fccc759 100644
--- a/tests/generated/packet_decl_simple_scalars_little_endian.rs
+++ b/tests/generated/rust_legacy/packet_decl_simple_scalars_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub struct FooData {
@@ -42,31 +47,31 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 6
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
         }
         let x = bytes.get_mut().get_u8();
         if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 2,
                 got: bytes.get().remaining(),
             });
         }
         let y = bytes.get_mut().get_u16_le();
         if bytes.get().remaining() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
                 wanted: 3,
                 got: bytes.get().remaining(),
             });
@@ -74,13 +79,19 @@
         let z = bytes.get_mut().get_uint_le(3) as u32;
         Ok(Self { x, y, z })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u8(self.x);
         buffer.put_u16_le(self.y);
         if self.z > 0xff_ffff {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "z", self.z, 0xff_ffff);
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "z",
+                value: self.z as u64,
+                maximum_value: 0xff_ffff,
+            });
         }
         buffer.put_uint_le(self.z as u64, 3);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -90,36 +101,39 @@
     }
 }
 impl Packet for Foo {
-    fn to_bytes(self) -> Bytes {
-        let mut buffer = BytesMut::with_capacity(self.foo.get_size());
-        self.foo.write_to(&mut buffer);
-        buffer.freeze()
+    fn encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.foo.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Foo> for Bytes {
-    fn from(packet: Foo) -> Self {
-        packet.to_bytes()
+impl TryFrom<Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Foo> for Vec<u8> {
-    fn from(packet: Foo) -> Self {
-        packet.to_vec()
+impl TryFrom<Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Foo {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = FooData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(foo: FooData) -> Result<Self> {
+    fn new(foo: FooData) -> Result<Self, DecodeError> {
         Ok(Self { foo })
     }
     pub fn get_x(&self) -> u8 {
@@ -131,7 +145,7 @@
     pub fn get_z(&self) -> u32 {
         self.foo.z
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.foo.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/payload_with_size_modifier_big_endian.rs b/tests/generated/rust_legacy/payload_with_size_modifier_big_endian.rs
similarity index 69%
rename from tests/generated/payload_with_size_modifier_big_endian.rs
rename to tests/generated/rust_legacy/payload_with_size_modifier_big_endian.rs
index beec02b..b0c4277 100644
--- a/tests/generated/payload_with_size_modifier_big_endian.rs
+++ b/tests/generated/rust_legacy/payload_with_size_modifier_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub enum TestDataChild {
@@ -58,31 +63,31 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 1
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Test".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Test",
                 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(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Test",
                 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(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Test",
                 wanted: payload_size,
                 got: bytes.get().remaining(),
             });
@@ -97,18 +102,21 @@
         };
         Ok(Self { child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         if (self.child.get_total_size() + 1) > 0xff {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Test", "_payload_", (self.child
-                .get_total_size() + 1), 0xff
-            );
+            return Err(EncodeError::SizeOverflow {
+                packet: "Test",
+                field: "_payload_",
+                size: (self.child.get_total_size() + 1),
+                maximum_size: 0xff,
+            });
         }
         buffer.put_u8((self.child.get_total_size() + 1) as u8);
         match &self.child {
             TestDataChild::Payload(payload) => buffer.put_slice(payload),
             TestDataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -118,32 +126,35 @@
     }
 }
 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 encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.test.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Test> for Bytes {
-    fn from(packet: Test) -> Self {
-        packet.to_bytes()
+impl TryFrom<Test> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Test) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Test> for Vec<u8> {
-    fn from(packet: Test) -> Self {
-        packet.to_vec()
+impl TryFrom<Test> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Test) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Test {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = TestData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -153,7 +164,7 @@
             TestDataChild::None => TestChild::None,
         }
     }
-    fn new(test: TestData) -> Result<Self> {
+    fn new(test: TestData) -> Result<Self, DecodeError> {
         Ok(Self { test })
     }
     pub fn get_payload(&self) -> &[u8] {
@@ -162,7 +173,7 @@
             TestDataChild::None => &[],
         }
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.test.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/payload_with_size_modifier_little_endian.rs b/tests/generated/rust_legacy/payload_with_size_modifier_little_endian.rs
similarity index 69%
rename from tests/generated/payload_with_size_modifier_little_endian.rs
rename to tests/generated/rust_legacy/payload_with_size_modifier_little_endian.rs
index beec02b..b0c4277 100644
--- a/tests/generated/payload_with_size_modifier_little_endian.rs
+++ b/tests/generated/rust_legacy/payload_with_size_modifier_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub enum TestDataChild {
@@ -58,31 +63,31 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 1
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Test".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Test",
                 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(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Test",
                 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(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Test",
                 wanted: payload_size,
                 got: bytes.get().remaining(),
             });
@@ -97,18 +102,21 @@
         };
         Ok(Self { child })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         if (self.child.get_total_size() + 1) > 0xff {
-            panic!(
-                "Invalid length for {}::{}: {} > {}", "Test", "_payload_", (self.child
-                .get_total_size() + 1), 0xff
-            );
+            return Err(EncodeError::SizeOverflow {
+                packet: "Test",
+                field: "_payload_",
+                size: (self.child.get_total_size() + 1),
+                maximum_size: 0xff,
+            });
         }
         buffer.put_u8((self.child.get_total_size() + 1) as u8);
         match &self.child {
             TestDataChild::Payload(payload) => buffer.put_slice(payload),
             TestDataChild::None => {}
         }
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -118,32 +126,35 @@
     }
 }
 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 encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.test.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Test> for Bytes {
-    fn from(packet: Test) -> Self {
-        packet.to_bytes()
+impl TryFrom<Test> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Test) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Test> for Vec<u8> {
-    fn from(packet: Test) -> Self {
-        packet.to_vec()
+impl TryFrom<Test> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Test) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Test {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = TestData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
@@ -153,7 +164,7 @@
             TestDataChild::None => TestChild::None,
         }
     }
-    fn new(test: TestData) -> Result<Self> {
+    fn new(test: TestData) -> Result<Self, DecodeError> {
         Ok(Self { test })
     }
     pub fn get_payload(&self) -> &[u8] {
@@ -162,7 +173,7 @@
             TestDataChild::None => &[],
         }
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.test.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/rust_legacy/preamble.rs b/tests/generated/rust_legacy/preamble.rs
new file mode 100644
index 0000000..ab77b58
--- /dev/null
+++ b/tests/generated/rust_legacy/preamble.rs
@@ -0,0 +1,25 @@
+#![rustfmt::skip]
+/// @generated rust packets from foo.pdl.
+use bytes::{Buf, BufMut, Bytes, BytesMut};
+use std::convert::{TryFrom, TryInto};
+use std::cell::Cell;
+use std::fmt;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
diff --git a/tests/generated/reserved_identifier_big_endian.rs b/tests/generated/rust_legacy/reserved_identifier_big_endian.rs
similarity index 61%
rename from tests/generated/reserved_identifier_big_endian.rs
rename to tests/generated/rust_legacy/reserved_identifier_big_endian.rs
index f346dd1..4fce5c3 100644
--- a/tests/generated/reserved_identifier_big_endian.rs
+++ b/tests/generated/rust_legacy/reserved_identifier_big_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub struct TestData {
@@ -38,15 +43,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 1
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Test".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Test",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
@@ -54,8 +59,9 @@
         let r#type = bytes.get_mut().get_u8();
         Ok(Self { r#type })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u8(self.r#type);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -65,42 +71,45 @@
     }
 }
 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 encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.test.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Test> for Bytes {
-    fn from(packet: Test) -> Self {
-        packet.to_bytes()
+impl TryFrom<Test> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Test) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Test> for Vec<u8> {
-    fn from(packet: Test) -> Self {
-        packet.to_vec()
+impl TryFrom<Test> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Test) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Test {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = TestData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(test: TestData) -> Result<Self> {
+    fn new(test: TestData) -> Result<Self, DecodeError> {
         Ok(Self { test })
     }
     pub fn get_type(&self) -> u8 {
         self.test.r#type
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.test.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/reserved_identifier_little_endian.rs b/tests/generated/rust_legacy/reserved_identifier_little_endian.rs
similarity index 61%
rename from tests/generated/reserved_identifier_little_endian.rs
rename to tests/generated/rust_legacy/reserved_identifier_little_endian.rs
index f346dd1..4fce5c3 100644
--- a/tests/generated/reserved_identifier_little_endian.rs
+++ b/tests/generated/rust_legacy/reserved_identifier_little_endian.rs
@@ -4,13 +4,13 @@
 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>;
+use std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
 /// 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)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Private<T>(T);
 impl<T> std::ops::Deref for Private<T> {
     type Target = T;
@@ -18,6 +18,11 @@
         &self.0
     }
 }
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub struct TestData {
@@ -38,15 +43,15 @@
     fn conforms(bytes: &[u8]) -> bool {
         bytes.len() >= 1
     }
-    fn parse(bytes: &[u8]) -> Result<Self> {
+    fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         if bytes.get().remaining() < 1 {
-            return Err(Error::InvalidLengthError {
-                obj: "Test".to_string(),
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Test",
                 wanted: 1,
                 got: bytes.get().remaining(),
             });
@@ -54,8 +59,9 @@
         let r#type = bytes.get_mut().get_u8();
         Ok(Self { r#type })
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
         buffer.put_u8(self.r#type);
+        Ok(())
     }
     fn get_total_size(&self) -> usize {
         self.get_size()
@@ -65,42 +71,45 @@
     }
 }
 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 encoded_len(&self) -> usize {
+        self.get_size()
     }
-    fn to_vec(self) -> Vec<u8> {
-        self.to_bytes().to_vec()
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        self.test.write_to(buf)
+    }
+    fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        unimplemented!("Rust legacy does not implement full packet trait")
     }
 }
-impl From<Test> for Bytes {
-    fn from(packet: Test) -> Self {
-        packet.to_bytes()
+impl TryFrom<Test> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: Test) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
     }
 }
-impl From<Test> for Vec<u8> {
-    fn from(packet: Test) -> Self {
-        packet.to_vec()
+impl TryFrom<Test> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: Test) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
     }
 }
 impl Test {
-    pub fn parse(bytes: &[u8]) -> Result<Self> {
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
         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> {
+    fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
         let data = TestData::parse_inner(&mut bytes)?;
         Self::new(data)
     }
-    fn new(test: TestData) -> Result<Self> {
+    fn new(test: TestData) -> Result<Self, DecodeError> {
         Ok(Self { test })
     }
     pub fn get_type(&self) -> u8 {
         self.test.r#type
     }
-    fn write_to(&self, buffer: &mut BytesMut) {
+    fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
         self.test.write_to(buffer)
     }
     pub fn get_size(&self) -> usize {
diff --git a/tests/generated/rust_legacy/struct_decl_complex_scalars_big_endian.rs b/tests/generated/rust_legacy/struct_decl_complex_scalars_big_endian.rs
new file mode 100644
index 0000000..42b0858
--- /dev/null
+++ b/tests/generated/rust_legacy/struct_decl_complex_scalars_big_endian.rs
@@ -0,0 +1,131 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u8,
+    pub b: u8,
+    pub c: u8,
+    pub d: u32,
+    pub e: u16,
+    pub f: u8,
+}
+impl Foo {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 7
+    }
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: bytes.get().remaining(),
+            });
+        }
+        let chunk = bytes.get_mut().get_u16();
+        let a = (chunk & 0x7) as u8;
+        let b = (chunk >> 3) as u8;
+        let c = ((chunk >> 11) & 0x1f) as u8;
+        if bytes.get().remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: bytes.get().remaining(),
+            });
+        }
+        let d = bytes.get_mut().get_uint(3) as u32;
+        if bytes.get().remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: bytes.get().remaining(),
+            });
+        }
+        let chunk = bytes.get_mut().get_u16();
+        let e = (chunk & 0xfff);
+        let f = ((chunk >> 12) & 0xf) as u8;
+        Ok(Self { a, b, c, d, e, f })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        if self.a > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a as u64,
+                maximum_value: 0x7,
+            });
+        }
+        if self.c > 0x1f {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "c",
+                value: self.c as u64,
+                maximum_value: 0x1f,
+            });
+        }
+        let value = (self.a as u16) | ((self.b as u16) << 3) | ((self.c as u16) << 11);
+        buffer.put_u16(value);
+        if self.d > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "d",
+                value: self.d as u64,
+                maximum_value: 0xff_ffff,
+            });
+        }
+        buffer.put_uint(self.d as u64, 3);
+        if self.e > 0xfff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "e",
+                value: self.e as u64,
+                maximum_value: 0xfff,
+            });
+        }
+        if self.f > 0xf {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "f",
+                value: self.f as u64,
+                maximum_value: 0xf,
+            });
+        }
+        let value = self.e | ((self.f as u16) << 12);
+        buffer.put_u16(value);
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        7
+    }
+}
diff --git a/tests/generated/rust_legacy/struct_decl_complex_scalars_little_endian.rs b/tests/generated/rust_legacy/struct_decl_complex_scalars_little_endian.rs
new file mode 100644
index 0000000..a8c3f7a
--- /dev/null
+++ b/tests/generated/rust_legacy/struct_decl_complex_scalars_little_endian.rs
@@ -0,0 +1,131 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u8,
+    pub b: u8,
+    pub c: u8,
+    pub d: u32,
+    pub e: u16,
+    pub f: u8,
+}
+impl Foo {
+    fn conforms(bytes: &[u8]) -> bool {
+        bytes.len() >= 7
+    }
+    pub fn parse(bytes: &[u8]) -> Result<Self, DecodeError> {
+        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, DecodeError> {
+        if bytes.get().remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: bytes.get().remaining(),
+            });
+        }
+        let chunk = bytes.get_mut().get_u16_le();
+        let a = (chunk & 0x7) as u8;
+        let b = (chunk >> 3) as u8;
+        let c = ((chunk >> 11) & 0x1f) as u8;
+        if bytes.get().remaining() < 3 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 3,
+                got: bytes.get().remaining(),
+            });
+        }
+        let d = bytes.get_mut().get_uint_le(3) as u32;
+        if bytes.get().remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: bytes.get().remaining(),
+            });
+        }
+        let chunk = bytes.get_mut().get_u16_le();
+        let e = (chunk & 0xfff);
+        let f = ((chunk >> 12) & 0xf) as u8;
+        Ok(Self { a, b, c, d, e, f })
+    }
+    fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
+        if self.a > 0x7 {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "a",
+                value: self.a as u64,
+                maximum_value: 0x7,
+            });
+        }
+        if self.c > 0x1f {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "c",
+                value: self.c as u64,
+                maximum_value: 0x1f,
+            });
+        }
+        let value = (self.a as u16) | ((self.b as u16) << 3) | ((self.c as u16) << 11);
+        buffer.put_u16_le(value);
+        if self.d > 0xff_ffff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "d",
+                value: self.d as u64,
+                maximum_value: 0xff_ffff,
+            });
+        }
+        buffer.put_uint_le(self.d as u64, 3);
+        if self.e > 0xfff {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "e",
+                value: self.e as u64,
+                maximum_value: 0xfff,
+            });
+        }
+        if self.f > 0xf {
+            return Err(EncodeError::InvalidScalarValue {
+                packet: "Foo",
+                field: "f",
+                value: self.f as u64,
+                maximum_value: 0xf,
+            });
+        }
+        let value = self.e | ((self.f as u16) << 12);
+        buffer.put_u16_le(value);
+        Ok(())
+    }
+    fn get_total_size(&self) -> usize {
+        self.get_size()
+    }
+    fn get_size(&self) -> usize {
+        7
+    }
+}
diff --git a/tests/generated/struct_decl_child_structs_big_endian.rs b/tests/generated/struct_decl_child_structs_big_endian.rs
new file mode 100644
index 0000000..2fda403
--- /dev/null
+++ b/tests/generated/struct_decl_child_structs_big_endian.rs
@@ -0,0 +1,369 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))]
+pub enum Enum16 {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u16> for Enum16 {
+    type Error = u16;
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Enum16::A),
+            0x2 => Ok(Enum16::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum16> for u16 {
+    fn from(value: &Enum16) -> Self {
+        match value {
+            Enum16::A => 0x1,
+            Enum16::B => 0x2,
+        }
+    }
+}
+impl From<Enum16> for u16 {
+    fn from(value: Enum16) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum16> for i32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for i64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u8,
+    pub b: Enum16,
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: &Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<&Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: &Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum FooChild {
+    Bar(Bar),
+    Baz(Baz),
+    None,
+}
+impl Foo {
+    pub fn specialize(&self) -> Result<FooChild, DecodeError> {
+        Ok(
+            match (self.a, self.b) {
+                (100, _) => FooChild::Bar(self.try_into()?),
+                (_, Enum16::B) => FooChild::Baz(self.try_into()?),
+                _ => FooChild::None,
+            },
+        )
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> Enum16 {
+        self.b
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        4 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        buf.put_u16(u16::from(self.b()));
+        if self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(self.payload.len() as u8);
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let a = buf.get_u8();
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let b = Enum16::try_from(buf.get_u16())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Foo",
+                field: "b",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let payload_size = buf.get_u8() as usize;
+        if buf.remaining() < payload_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: payload_size,
+                got: buf.remaining(),
+            });
+        }
+        let payload = buf[..payload_size].to_vec();
+        buf.advance(payload_size);
+        let payload = Vec::from(payload);
+        Ok((Self { payload, a, b }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: u8,
+    pub b: Enum16,
+}
+impl TryFrom<&Foo> for Bar {
+    type Error = DecodeError;
+    fn try_from(parent: &Foo) -> Result<Bar, Self::Error> {
+        Bar::decode_partial(&parent)
+    }
+}
+impl TryFrom<&Bar> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: &Bar) -> Result<Foo, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Foo {
+            a: 100,
+            b: packet.b,
+            payload,
+        })
+    }
+}
+impl TryFrom<&Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: &Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<&Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: &Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Bar {
+    fn decode_partial(parent: &Foo) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf.get_u8();
+        if buf.is_empty() {
+            Ok(Self { x, b: parent.b })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.x());
+        Ok(())
+    }
+    pub fn x(&self) -> u8 {
+        self.x
+    }
+    pub fn b(&self) -> Enum16 {
+        self.b
+    }
+    pub fn a(&self) -> u8 {
+        100
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        5
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        buf.put_u16(u16::from(self.b()));
+        if 1 > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: 1,
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(1 as u8);
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Foo::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Baz {
+    pub y: u16,
+    pub a: u8,
+}
+impl TryFrom<&Foo> for Baz {
+    type Error = DecodeError;
+    fn try_from(parent: &Foo) -> Result<Baz, Self::Error> {
+        Baz::decode_partial(&parent)
+    }
+}
+impl TryFrom<&Baz> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: &Baz) -> Result<Foo, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Foo {
+            a: packet.a,
+            b: Enum16::B,
+            payload,
+        })
+    }
+}
+impl TryFrom<&Baz> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: &Baz) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<&Baz> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: &Baz) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Baz {
+    fn decode_partial(parent: &Foo) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Baz",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let y = buf.get_u16();
+        if buf.is_empty() {
+            Ok(Self { y, a: parent.a })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16(self.y());
+        Ok(())
+    }
+    pub fn y(&self) -> u16 {
+        self.y
+    }
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> Enum16 {
+        Enum16::B
+    }
+}
+impl Packet for Baz {
+    fn encoded_len(&self) -> usize {
+        6
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        buf.put_u16(u16::from(self.b()));
+        if 2 > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: 2,
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 as u8);
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Foo::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
diff --git a/tests/generated/struct_decl_child_structs_little_endian.rs b/tests/generated/struct_decl_child_structs_little_endian.rs
new file mode 100644
index 0000000..09bf722
--- /dev/null
+++ b/tests/generated/struct_decl_child_structs_little_endian.rs
@@ -0,0 +1,369 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))]
+pub enum Enum16 {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u16> for Enum16 {
+    type Error = u16;
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Enum16::A),
+            0x2 => Ok(Enum16::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum16> for u16 {
+    fn from(value: &Enum16) -> Self {
+        match value {
+            Enum16::A => 0x1,
+            Enum16::B => 0x2,
+        }
+    }
+}
+impl From<Enum16> for u16 {
+    fn from(value: Enum16) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum16> for i32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for i64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+    pub a: u8,
+    pub b: Enum16,
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&Foo> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: &Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<&Foo> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: &Foo) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum FooChild {
+    Bar(Bar),
+    Baz(Baz),
+    None,
+}
+impl Foo {
+    pub fn specialize(&self) -> Result<FooChild, DecodeError> {
+        Ok(
+            match (self.a, self.b) {
+                (100, _) => FooChild::Bar(self.try_into()?),
+                (_, Enum16::B) => FooChild::Baz(self.try_into()?),
+                _ => FooChild::None,
+            },
+        )
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> Enum16 {
+        self.b
+    }
+}
+impl Packet for Foo {
+    fn encoded_len(&self) -> usize {
+        4 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        buf.put_u16_le(u16::from(self.b()));
+        if self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(self.payload.len() as u8);
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let a = buf.get_u8();
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let b = Enum16::try_from(buf.get_u16_le())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Foo",
+                field: "b",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let payload_size = buf.get_u8() as usize;
+        if buf.remaining() < payload_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Foo",
+                wanted: payload_size,
+                got: buf.remaining(),
+            });
+        }
+        let payload = buf[..payload_size].to_vec();
+        buf.advance(payload_size);
+        let payload = Vec::from(payload);
+        Ok((Self { payload, a, b }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Bar {
+    pub x: u8,
+    pub b: Enum16,
+}
+impl TryFrom<&Foo> for Bar {
+    type Error = DecodeError;
+    fn try_from(parent: &Foo) -> Result<Bar, Self::Error> {
+        Bar::decode_partial(&parent)
+    }
+}
+impl TryFrom<&Bar> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: &Bar) -> Result<Foo, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Foo {
+            a: 100,
+            b: packet.b,
+            payload,
+        })
+    }
+}
+impl TryFrom<&Bar> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: &Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<&Bar> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: &Bar) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Bar {
+    fn decode_partial(parent: &Foo) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Bar",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let x = buf.get_u8();
+        if buf.is_empty() {
+            Ok(Self { x, b: parent.b })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.x());
+        Ok(())
+    }
+    pub fn x(&self) -> u8 {
+        self.x
+    }
+    pub fn b(&self) -> Enum16 {
+        self.b
+    }
+    pub fn a(&self) -> u8 {
+        100
+    }
+}
+impl Packet for Bar {
+    fn encoded_len(&self) -> usize {
+        5
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        buf.put_u16_le(u16::from(self.b()));
+        if 1 > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: 1,
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(1 as u8);
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Foo::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Baz {
+    pub y: u16,
+    pub a: u8,
+}
+impl TryFrom<&Foo> for Baz {
+    type Error = DecodeError;
+    fn try_from(parent: &Foo) -> Result<Baz, Self::Error> {
+        Baz::decode_partial(&parent)
+    }
+}
+impl TryFrom<&Baz> for Foo {
+    type Error = EncodeError;
+    fn try_from(packet: &Baz) -> Result<Foo, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Foo {
+            a: packet.a,
+            b: Enum16::B,
+            payload,
+        })
+    }
+}
+impl TryFrom<&Baz> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: &Baz) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<&Baz> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: &Baz) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl Baz {
+    fn decode_partial(parent: &Foo) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Baz",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let y = buf.get_u16_le();
+        if buf.is_empty() {
+            Ok(Self { y, a: parent.a })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16_le(self.y());
+        Ok(())
+    }
+    pub fn y(&self) -> u16 {
+        self.y
+    }
+    pub fn a(&self) -> u8 {
+        self.a
+    }
+    pub fn b(&self) -> Enum16 {
+        Enum16::B
+    }
+}
+impl Packet for Baz {
+    fn encoded_len(&self) -> usize {
+        6
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u8(self.a());
+        buf.put_u16_le(u16::from(self.b()));
+        if 2 > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Foo",
+                field: "_payload_",
+                size: 2,
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 as u8);
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Foo::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
diff --git a/tests/generated/struct_decl_complex_scalars_big_endian.rs b/tests/generated/struct_decl_complex_scalars_big_endian.rs
deleted file mode 100644
index 5fa18cd..0000000
--- a/tests/generated/struct_decl_complex_scalars_big_endian.rs
+++ /dev/null
@@ -1,100 +0,0 @@
-#![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 struct Foo {
-    pub a: u8,
-    pub b: u8,
-    pub c: u8,
-    pub d: u32,
-    pub e: u16,
-    pub f: u8,
-}
-impl Foo {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 7
-    }
-    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> {
-        if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 2,
-                got: bytes.get().remaining(),
-            });
-        }
-        let chunk = bytes.get_mut().get_u16();
-        let a = (chunk & 0x7) as u8;
-        let b = (chunk >> 3) as u8;
-        let c = ((chunk >> 11) & 0x1f) as u8;
-        if bytes.get().remaining() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 3,
-                got: bytes.get().remaining(),
-            });
-        }
-        let d = bytes.get_mut().get_uint(3) as u32;
-        if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 2,
-                got: bytes.get().remaining(),
-            });
-        }
-        let chunk = bytes.get_mut().get_u16();
-        let e = (chunk & 0xfff);
-        let f = ((chunk >> 12) & 0xf) as u8;
-        Ok(Self { a, b, c, d, e, f })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        if self.a > 0x7 {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0x7);
-        }
-        if self.c > 0x1f {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "c", self.c, 0x1f);
-        }
-        let value = (self.a as u16) | ((self.b as u16) << 3) | ((self.c as u16) << 11);
-        buffer.put_u16(value);
-        if self.d > 0xff_ffff {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "d", self.d, 0xff_ffff);
-        }
-        buffer.put_uint(self.d as u64, 3);
-        if self.e > 0xfff {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "e", self.e, 0xfff);
-        }
-        if self.f > 0xf {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "f", self.f, 0xf);
-        }
-        let value = self.e | ((self.f as u16) << 12);
-        buffer.put_u16(value);
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        7
-    }
-}
diff --git a/tests/generated/struct_decl_complex_scalars_little_endian.rs b/tests/generated/struct_decl_complex_scalars_little_endian.rs
deleted file mode 100644
index dbd7b69..0000000
--- a/tests/generated/struct_decl_complex_scalars_little_endian.rs
+++ /dev/null
@@ -1,100 +0,0 @@
-#![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 struct Foo {
-    pub a: u8,
-    pub b: u8,
-    pub c: u8,
-    pub d: u32,
-    pub e: u16,
-    pub f: u8,
-}
-impl Foo {
-    fn conforms(bytes: &[u8]) -> bool {
-        bytes.len() >= 7
-    }
-    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> {
-        if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 2,
-                got: bytes.get().remaining(),
-            });
-        }
-        let chunk = bytes.get_mut().get_u16_le();
-        let a = (chunk & 0x7) as u8;
-        let b = (chunk >> 3) as u8;
-        let c = ((chunk >> 11) & 0x1f) as u8;
-        if bytes.get().remaining() < 3 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 3,
-                got: bytes.get().remaining(),
-            });
-        }
-        let d = bytes.get_mut().get_uint_le(3) as u32;
-        if bytes.get().remaining() < 2 {
-            return Err(Error::InvalidLengthError {
-                obj: "Foo".to_string(),
-                wanted: 2,
-                got: bytes.get().remaining(),
-            });
-        }
-        let chunk = bytes.get_mut().get_u16_le();
-        let e = (chunk & 0xfff);
-        let f = ((chunk >> 12) & 0xf) as u8;
-        Ok(Self { a, b, c, d, e, f })
-    }
-    fn write_to(&self, buffer: &mut BytesMut) {
-        if self.a > 0x7 {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "a", self.a, 0x7);
-        }
-        if self.c > 0x1f {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "c", self.c, 0x1f);
-        }
-        let value = (self.a as u16) | ((self.b as u16) << 3) | ((self.c as u16) << 11);
-        buffer.put_u16_le(value);
-        if self.d > 0xff_ffff {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "d", self.d, 0xff_ffff);
-        }
-        buffer.put_uint_le(self.d as u64, 3);
-        if self.e > 0xfff {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "e", self.e, 0xfff);
-        }
-        if self.f > 0xf {
-            panic!("Invalid value for {}::{}: {} > {}", "Foo", "f", self.f, 0xf);
-        }
-        let value = self.e | ((self.f as u16) << 12);
-        buffer.put_u16_le(value);
-    }
-    fn get_total_size(&self) -> usize {
-        self.get_size()
-    }
-    fn get_size(&self) -> usize {
-        7
-    }
-}
diff --git a/tests/generated/struct_decl_grand_children_big_endian.rs b/tests/generated/struct_decl_grand_children_big_endian.rs
new file mode 100644
index 0000000..0650d32
--- /dev/null
+++ b/tests/generated/struct_decl_grand_children_big_endian.rs
@@ -0,0 +1,560 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))]
+pub enum Enum16 {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u16> for Enum16 {
+    type Error = u16;
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Enum16::A),
+            0x2 => Ok(Enum16::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum16> for u16 {
+    fn from(value: &Enum16) -> Self {
+        match value {
+            Enum16::A => 0x1,
+            Enum16::B => 0x2,
+        }
+    }
+}
+impl From<Enum16> for u16 {
+    fn from(value: Enum16) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum16> for i32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for i64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Parent {
+    pub foo: Enum16,
+    pub bar: Enum16,
+    pub baz: Enum16,
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&Parent> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: &Parent) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<&Parent> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: &Parent) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum ParentChild {
+    Child(Child),
+    None,
+}
+impl Parent {
+    pub fn specialize(&self) -> Result<ParentChild, DecodeError> {
+        Ok(
+            match (self.foo,) {
+                (Enum16::A,) => ParentChild::Child(self.try_into()?),
+                _ => ParentChild::None,
+            },
+        )
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn foo(&self) -> Enum16 {
+        self.foo
+    }
+    pub fn bar(&self) -> Enum16 {
+        self.bar
+    }
+    pub fn baz(&self) -> Enum16 {
+        self.baz
+    }
+}
+impl Packet for Parent {
+    fn encoded_len(&self) -> usize {
+        7 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16(u16::from(self.foo()));
+        buf.put_u16(u16::from(self.bar()));
+        buf.put_u16(u16::from(self.baz()));
+        if self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(self.payload.len() as u8);
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let foo = Enum16::try_from(buf.get_u16())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "foo",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let bar = Enum16::try_from(buf.get_u16())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "bar",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let baz = Enum16::try_from(buf.get_u16())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "baz",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let payload_size = buf.get_u8() as usize;
+        if buf.remaining() < payload_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: payload_size,
+                got: buf.remaining(),
+            });
+        }
+        let payload = buf[..payload_size].to_vec();
+        buf.advance(payload_size);
+        let payload = Vec::from(payload);
+        Ok((Self { payload, foo, bar, baz }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Child {
+    pub quux: Enum16,
+    pub bar: Enum16,
+    pub baz: Enum16,
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&Parent> for Child {
+    type Error = DecodeError;
+    fn try_from(parent: &Parent) -> Result<Child, Self::Error> {
+        Child::decode_partial(&parent)
+    }
+}
+impl TryFrom<&Child> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &Child) -> Result<Parent, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Parent {
+            foo: Enum16::A,
+            bar: packet.bar,
+            baz: packet.baz,
+            payload,
+        })
+    }
+}
+impl TryFrom<&Child> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: &Child) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<&Child> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: &Child) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum ChildChild {
+    GrandChild(GrandChild),
+    None,
+}
+impl Child {
+    pub fn specialize(&self) -> Result<ChildChild, DecodeError> {
+        Ok(
+            match (self.bar, self.quux) {
+                (Enum16::A, Enum16::A) => ChildChild::GrandChild(self.try_into()?),
+                _ => ChildChild::None,
+            },
+        )
+    }
+    fn decode_partial(parent: &Parent) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Child",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let quux = Enum16::try_from(buf.get_u16())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Child",
+                field: "quux",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        let payload = Vec::from(payload);
+        if buf.is_empty() {
+            Ok(Self {
+                payload,
+                quux,
+                bar: parent.bar,
+                baz: parent.baz,
+            })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16(u16::from(self.quux()));
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn quux(&self) -> Enum16 {
+        self.quux
+    }
+    pub fn bar(&self) -> Enum16 {
+        self.bar
+    }
+    pub fn baz(&self) -> Enum16 {
+        self.baz
+    }
+    pub fn foo(&self) -> Enum16 {
+        Enum16::A
+    }
+}
+impl Packet for Child {
+    fn encoded_len(&self) -> usize {
+        9 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16(u16::from(self.foo()));
+        buf.put_u16(u16::from(self.bar()));
+        buf.put_u16(u16::from(self.baz()));
+        if 2 + self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: 2 + self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 + self.payload.len() as u8);
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Parent::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct GrandChild {
+    pub baz: Enum16,
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&Child> for GrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: &Child) -> Result<GrandChild, Self::Error> {
+        GrandChild::decode_partial(&parent)
+    }
+}
+impl TryFrom<&GrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandChild) -> Result<Child, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Child {
+            quux: Enum16::A,
+            bar: Enum16::A,
+            baz: packet.baz,
+            payload,
+        })
+    }
+}
+impl TryFrom<&GrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandChild) -> Result<Parent, Self::Error> {
+        (&Child::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<&GrandChild> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandChild) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<&GrandChild> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandChild) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum GrandChildChild {
+    GrandGrandChild(GrandGrandChild),
+    None,
+}
+impl GrandChild {
+    pub fn specialize(&self) -> Result<GrandChildChild, DecodeError> {
+        Ok(
+            match (self.baz,) {
+                (Enum16::A,) => GrandChildChild::GrandGrandChild(self.try_into()?),
+                _ => GrandChildChild::None,
+            },
+        )
+    }
+    fn decode_partial(parent: &Child) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        let payload = Vec::from(payload);
+        if buf.is_empty() {
+            Ok(Self { payload, baz: parent.baz })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn baz(&self) -> Enum16 {
+        self.baz
+    }
+    pub fn quux(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn foo(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn bar(&self) -> Enum16 {
+        Enum16::A
+    }
+}
+impl Packet for GrandChild {
+    fn encoded_len(&self) -> usize {
+        9 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16(u16::from(self.foo()));
+        buf.put_u16(u16::from(self.bar()));
+        buf.put_u16(u16::from(self.baz()));
+        if 2 + self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: 2 + self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 + self.payload.len() as u8);
+        buf.put_u16(u16::from(self.quux()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Child::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct GrandGrandChild {
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&GrandChild> for GrandGrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: &GrandChild) -> Result<GrandGrandChild, Self::Error> {
+        GrandGrandChild::decode_partial(&parent)
+    }
+}
+impl TryFrom<&GrandGrandChild> for GrandChild {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<GrandChild, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(GrandChild {
+            baz: Enum16::A,
+            payload,
+        })
+    }
+}
+impl TryFrom<&GrandGrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<Child, Self::Error> {
+        (&GrandChild::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<&GrandGrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<Parent, Self::Error> {
+        (&GrandChild::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<&GrandGrandChild> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<&GrandGrandChild> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl GrandGrandChild {
+    fn decode_partial(parent: &GrandChild) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        let payload = Vec::from(payload);
+        if buf.is_empty() {
+            Ok(Self { payload })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn quux(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn foo(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn bar(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn baz(&self) -> Enum16 {
+        Enum16::A
+    }
+}
+impl Packet for GrandGrandChild {
+    fn encoded_len(&self) -> usize {
+        9 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16(u16::from(self.foo()));
+        buf.put_u16(u16::from(self.bar()));
+        buf.put_u16(u16::from(self.baz()));
+        if 2 + self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: 2 + self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 + self.payload.len() as u8);
+        buf.put_u16(u16::from(self.quux()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = GrandChild::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
diff --git a/tests/generated/struct_decl_grand_children_little_endian.rs b/tests/generated/struct_decl_grand_children_little_endian.rs
new file mode 100644
index 0000000..eca914a
--- /dev/null
+++ b/tests/generated/struct_decl_grand_children_little_endian.rs
@@ -0,0 +1,560 @@
+#![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 std::result::Result;
+use pdl_runtime::{DecodeError, EncodeError, Packet};
+/// 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(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
+    }
+}
+impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        T::fmt(&self.0, f)
+    }
+}
+#[repr(u64)]
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[cfg_attr(feature = "serde", serde(try_from = "u16", into = "u16"))]
+pub enum Enum16 {
+    A = 0x1,
+    B = 0x2,
+}
+impl TryFrom<u16> for Enum16 {
+    type Error = u16;
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
+        match value {
+            0x1 => Ok(Enum16::A),
+            0x2 => Ok(Enum16::B),
+            _ => Err(value),
+        }
+    }
+}
+impl From<&Enum16> for u16 {
+    fn from(value: &Enum16) -> Self {
+        match value {
+            Enum16::A => 0x1,
+            Enum16::B => 0x2,
+        }
+    }
+}
+impl From<Enum16> for u16 {
+    fn from(value: Enum16) -> Self {
+        (&value).into()
+    }
+}
+impl From<Enum16> for i32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for i64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u32 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+impl From<Enum16> for u64 {
+    fn from(value: Enum16) -> Self {
+        u16::from(value) as Self
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Parent {
+    pub foo: Enum16,
+    pub bar: Enum16,
+    pub baz: Enum16,
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&Parent> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: &Parent) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<&Parent> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: &Parent) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum ParentChild {
+    Child(Child),
+    None,
+}
+impl Parent {
+    pub fn specialize(&self) -> Result<ParentChild, DecodeError> {
+        Ok(
+            match (self.foo,) {
+                (Enum16::A,) => ParentChild::Child(self.try_into()?),
+                _ => ParentChild::None,
+            },
+        )
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn foo(&self) -> Enum16 {
+        self.foo
+    }
+    pub fn bar(&self) -> Enum16 {
+        self.bar
+    }
+    pub fn baz(&self) -> Enum16 {
+        self.baz
+    }
+}
+impl Packet for Parent {
+    fn encoded_len(&self) -> usize {
+        7 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16_le(u16::from(self.foo()));
+        buf.put_u16_le(u16::from(self.bar()));
+        buf.put_u16_le(u16::from(self.baz()));
+        if self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(self.payload.len() as u8);
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let foo = Enum16::try_from(buf.get_u16_le())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "foo",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let bar = Enum16::try_from(buf.get_u16_le())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "bar",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let baz = Enum16::try_from(buf.get_u16_le())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Parent",
+                field: "baz",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        if buf.remaining() < 1 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: 1,
+                got: buf.remaining(),
+            });
+        }
+        let payload_size = buf.get_u8() as usize;
+        if buf.remaining() < payload_size {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Parent",
+                wanted: payload_size,
+                got: buf.remaining(),
+            });
+        }
+        let payload = buf[..payload_size].to_vec();
+        buf.advance(payload_size);
+        let payload = Vec::from(payload);
+        Ok((Self { payload, foo, bar, baz }, buf))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Child {
+    pub quux: Enum16,
+    pub bar: Enum16,
+    pub baz: Enum16,
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&Parent> for Child {
+    type Error = DecodeError;
+    fn try_from(parent: &Parent) -> Result<Child, Self::Error> {
+        Child::decode_partial(&parent)
+    }
+}
+impl TryFrom<&Child> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &Child) -> Result<Parent, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Parent {
+            foo: Enum16::A,
+            bar: packet.bar,
+            baz: packet.baz,
+            payload,
+        })
+    }
+}
+impl TryFrom<&Child> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: &Child) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<&Child> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: &Child) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum ChildChild {
+    GrandChild(GrandChild),
+    None,
+}
+impl Child {
+    pub fn specialize(&self) -> Result<ChildChild, DecodeError> {
+        Ok(
+            match (self.bar, self.quux) {
+                (Enum16::A, Enum16::A) => ChildChild::GrandChild(self.try_into()?),
+                _ => ChildChild::None,
+            },
+        )
+    }
+    fn decode_partial(parent: &Parent) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        if buf.remaining() < 2 {
+            return Err(DecodeError::InvalidLengthError {
+                obj: "Child",
+                wanted: 2,
+                got: buf.remaining(),
+            });
+        }
+        let quux = Enum16::try_from(buf.get_u16_le())
+            .map_err(|unknown_val| DecodeError::InvalidEnumValueError {
+                obj: "Child",
+                field: "quux",
+                value: unknown_val as u64,
+                type_: "Enum16",
+            })?;
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        let payload = Vec::from(payload);
+        if buf.is_empty() {
+            Ok(Self {
+                payload,
+                quux,
+                bar: parent.bar,
+                baz: parent.baz,
+            })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16_le(u16::from(self.quux()));
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn quux(&self) -> Enum16 {
+        self.quux
+    }
+    pub fn bar(&self) -> Enum16 {
+        self.bar
+    }
+    pub fn baz(&self) -> Enum16 {
+        self.baz
+    }
+    pub fn foo(&self) -> Enum16 {
+        Enum16::A
+    }
+}
+impl Packet for Child {
+    fn encoded_len(&self) -> usize {
+        9 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16_le(u16::from(self.foo()));
+        buf.put_u16_le(u16::from(self.bar()));
+        buf.put_u16_le(u16::from(self.baz()));
+        if 2 + self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: 2 + self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 + self.payload.len() as u8);
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Parent::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct GrandChild {
+    pub baz: Enum16,
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&Child> for GrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: &Child) -> Result<GrandChild, Self::Error> {
+        GrandChild::decode_partial(&parent)
+    }
+}
+impl TryFrom<&GrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandChild) -> Result<Child, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(Child {
+            quux: Enum16::A,
+            bar: Enum16::A,
+            baz: packet.baz,
+            payload,
+        })
+    }
+}
+impl TryFrom<&GrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandChild) -> Result<Parent, Self::Error> {
+        (&Child::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<&GrandChild> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandChild) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<&GrandChild> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandChild) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub enum GrandChildChild {
+    GrandGrandChild(GrandGrandChild),
+    None,
+}
+impl GrandChild {
+    pub fn specialize(&self) -> Result<GrandChildChild, DecodeError> {
+        Ok(
+            match (self.baz,) {
+                (Enum16::A,) => GrandChildChild::GrandGrandChild(self.try_into()?),
+                _ => GrandChildChild::None,
+            },
+        )
+    }
+    fn decode_partial(parent: &Child) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        let payload = Vec::from(payload);
+        if buf.is_empty() {
+            Ok(Self { payload, baz: parent.baz })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn baz(&self) -> Enum16 {
+        self.baz
+    }
+    pub fn quux(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn foo(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn bar(&self) -> Enum16 {
+        Enum16::A
+    }
+}
+impl Packet for GrandChild {
+    fn encoded_len(&self) -> usize {
+        9 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16_le(u16::from(self.foo()));
+        buf.put_u16_le(u16::from(self.bar()));
+        buf.put_u16_le(u16::from(self.baz()));
+        if 2 + self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: 2 + self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 + self.payload.len() as u8);
+        buf.put_u16_le(u16::from(self.quux()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = Child::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct GrandGrandChild {
+    pub payload: Vec<u8>,
+}
+impl TryFrom<&GrandChild> for GrandGrandChild {
+    type Error = DecodeError;
+    fn try_from(parent: &GrandChild) -> Result<GrandGrandChild, Self::Error> {
+        GrandGrandChild::decode_partial(&parent)
+    }
+}
+impl TryFrom<&GrandGrandChild> for GrandChild {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<GrandChild, Self::Error> {
+        let mut payload = Vec::new();
+        packet.encode_partial(&mut payload)?;
+        Ok(GrandChild {
+            baz: Enum16::A,
+            payload,
+        })
+    }
+}
+impl TryFrom<&GrandGrandChild> for Child {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<Child, Self::Error> {
+        (&GrandChild::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<&GrandGrandChild> for Parent {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<Parent, Self::Error> {
+        (&GrandChild::try_from(packet)?).try_into()
+    }
+}
+impl TryFrom<&GrandGrandChild> for Bytes {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<Self, Self::Error> {
+        packet.encode_to_bytes()
+    }
+}
+impl TryFrom<&GrandGrandChild> for Vec<u8> {
+    type Error = EncodeError;
+    fn try_from(packet: &GrandGrandChild) -> Result<Self, Self::Error> {
+        packet.encode_to_vec()
+    }
+}
+impl GrandGrandChild {
+    fn decode_partial(parent: &GrandChild) -> Result<Self, DecodeError> {
+        let mut buf: &[u8] = &parent.payload;
+        let payload = buf.to_vec();
+        buf.advance(payload.len());
+        let payload = Vec::from(payload);
+        if buf.is_empty() {
+            Ok(Self { payload })
+        } else {
+            Err(DecodeError::TrailingBytes)
+        }
+    }
+    pub fn encode_partial(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_slice(&self.payload);
+        Ok(())
+    }
+    pub fn payload(&self) -> &[u8] {
+        &self.payload
+    }
+    pub fn quux(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn foo(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn bar(&self) -> Enum16 {
+        Enum16::A
+    }
+    pub fn baz(&self) -> Enum16 {
+        Enum16::A
+    }
+}
+impl Packet for GrandGrandChild {
+    fn encoded_len(&self) -> usize {
+        9 + self.payload.len()
+    }
+    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
+        buf.put_u16_le(u16::from(self.foo()));
+        buf.put_u16_le(u16::from(self.bar()));
+        buf.put_u16_le(u16::from(self.baz()));
+        if 2 + self.payload.len() > 0xff {
+            return Err(EncodeError::SizeOverflow {
+                packet: "Parent",
+                field: "_payload_",
+                size: 2 + self.payload.len(),
+                maximum_size: 0xff,
+            });
+        }
+        buf.put_u8(2 + self.payload.len() as u8);
+        buf.put_u16_le(u16::from(self.quux()));
+        self.encode_partial(buf)?;
+        Ok(())
+    }
+    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+        let (parent, trailing_bytes) = GrandChild::decode(buf)?;
+        let packet = Self::decode_partial(&parent)?;
+        Ok((packet, trailing_bytes))
+    }
+}
diff --git a/tests/python_generator_test.py b/tests/python_generator_test.py
index a126c8d..1d3ab75 100644
--- a/tests/python_generator_test.py
+++ b/tests/python_generator_test.py
@@ -21,7 +21,6 @@
 import enum
 import json
 import typing
-import typing_extensions
 import unittest
 from importlib import resources
 
@@ -33,6 +32,14 @@
 import be_backend
 
 
+SKIPPED_TESTS = [
+    "Packet_Array_Field_VariableElementSize_ConstantSize",
+    "Packet_Array_Field_VariableElementSize_VariableSize",
+    "Packet_Array_Field_VariableElementSize_VariableCount",
+    "Packet_Array_Field_VariableElementSize_UnknownSize",
+]
+
+
 def match_object(self, left, right):
     """Recursively match a python class object against a reference
     json object."""
@@ -57,19 +64,20 @@
             field_type = field_types[f]
             values[f] = create_object(field_type, v)
         return typ(**values)
-    elif typing_extensions.get_origin(typ) is list:
-        typ = typing_extensions.get_args(typ)[0]
+    elif typing.get_origin(typ) is list:
+        typ = typing.get_args(typ)[0]
         return [create_object(typ, v) for v in value]
-    elif typing_extensions.get_origin(typ) is typing.Union:
+    elif typing.get_origin(typ) is typing.Union:
         # typing.Optional[int] expands to typing.Union[int, None]
-        typ = typing_extensions.get_args(typ)[0]
+        typ = typing.get_args(typ)[0]
         return create_object(typ, value) if value is not None else None
     elif typ is bytes:
         return bytes(value)
     elif typ is bytearray:
         return bytearray(value)
     elif issubclass(typ, enum.Enum):
-        return typ(value)
+        from_int = getattr(typ, 'from_int')
+        return from_int(value)
     elif typ is int:
         return value
     else:
@@ -90,6 +98,10 @@
             # selected packet.
             packet = item['packet']
             tests = item['tests']
+
+            if packet in SKIPPED_TESTS:
+                continue
+
             with self.subTest(packet=packet):
                 # Retrieve the class object from the generated
                 # module, in order to invoke the proper parse
@@ -109,6 +121,10 @@
             # selected packet.
             packet = item['packet']
             tests = item['tests']
+
+            if packet in SKIPPED_TESTS:
+                continue
+
             with self.subTest(packet=packet):
                 # Retrieve the class object from the generated
                 # module, in order to invoke the proper constructor
@@ -133,6 +149,10 @@
             # selected packet.
             packet = item['packet']
             tests = item['tests']
+
+            if packet in SKIPPED_TESTS:
+                continue
+
             with self.subTest(packet=packet):
                 # Retrieve the class object from the generated
                 # module, in order to invoke the proper constructor
@@ -153,6 +173,10 @@
             # selected packet.
             packet = item['packet']
             tests = item['tests']
+
+            if packet in SKIPPED_TESTS:
+                continue
+
             with self.subTest(packet=packet):
                 # Retrieve the class object from the generated
                 # module, in order to invoke the proper parse
diff --git a/tests/run_cxx_generator_tests.sh b/tests/run_cxx_generator_tests.sh
index fa90323..862bd0a 100755
--- a/tests/run_cxx_generator_tests.sh
+++ b/tests/run_cxx_generator_tests.sh
@@ -18,10 +18,54 @@
 python3 scripts/generate_cxx_backend.py \
     --input "$OUT_DIR"/le_test_file.json \
     --output "$OUT_DIR"/le_backend.h \
+    --exclude-declaration Packet_Custom_Field_ConstantSize \
+    --exclude-declaration Packet_Custom_Field_VariableSize \
+    --exclude-declaration Packet_Checksum_Field_FromStart \
+    --exclude-declaration Packet_Checksum_Field_FromEnd \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_ConstantSize \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_VariableSize \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_VariableCount \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_UnknownSize \
+    --exclude-declaration Struct_Custom_Field_ConstantSize \
+    --exclude-declaration Struct_Custom_Field_VariableSize \
+    --exclude-declaration Struct_Checksum_Field_FromStart \
+    --exclude-declaration Struct_Checksum_Field_FromEnd \
+    --exclude-declaration Struct_Custom_Field_ConstantSize_ \
+    --exclude-declaration Struct_Custom_Field_VariableSize_ \
+    --exclude-declaration Struct_Checksum_Field_FromStart_ \
+    --exclude-declaration Struct_Checksum_Field_FromEnd_ \
+    --exclude-declaration PartialParent5 \
+    --exclude-declaration PartialChild5_A \
+    --exclude-declaration PartialChild5_B \
+    --exclude-declaration PartialParent12 \
+    --exclude-declaration PartialChild12_A \
+    --exclude-declaration PartialChild12_B \
     --namespace le_backend
 python3 scripts/generate_cxx_backend.py \
     --input "$OUT_DIR"/be_test_file.json \
     --output "$OUT_DIR"/be_backend.h \
+    --exclude-declaration Packet_Custom_Field_ConstantSize \
+    --exclude-declaration Packet_Custom_Field_VariableSize \
+    --exclude-declaration Packet_Checksum_Field_FromStart \
+    --exclude-declaration Packet_Checksum_Field_FromEnd \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_ConstantSize \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_VariableSize \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_VariableCount \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_UnknownSize \
+    --exclude-declaration Struct_Custom_Field_ConstantSize \
+    --exclude-declaration Struct_Custom_Field_VariableSize \
+    --exclude-declaration Struct_Checksum_Field_FromStart \
+    --exclude-declaration Struct_Checksum_Field_FromEnd \
+    --exclude-declaration Struct_Custom_Field_ConstantSize_ \
+    --exclude-declaration Struct_Custom_Field_VariableSize_ \
+    --exclude-declaration Struct_Checksum_Field_FromStart_ \
+    --exclude-declaration Struct_Checksum_Field_FromEnd_ \
+    --exclude-declaration PartialParent5 \
+    --exclude-declaration PartialChild5_A \
+    --exclude-declaration PartialChild5_B \
+    --exclude-declaration PartialParent12 \
+    --exclude-declaration PartialChild12_A \
+    --exclude-declaration PartialChild12_B \
     --namespace be_backend
 
 python3 scripts/generate_cxx_backend_tests.py \
diff --git a/tests/run_python_generator_tests.sh b/tests/run_python_generator_tests.sh
index e11b8f5..3b90a92 100755
--- a/tests/run_python_generator_tests.sh
+++ b/tests/run_python_generator_tests.sh
@@ -18,10 +18,18 @@
 python3 scripts/generate_python_backend.py \
     --input "$OUT_DIR"/le_test_file.json \
     --output "$OUT_DIR"/le_backend.py \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_ConstantSize \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_VariableSize \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_VariableCount \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_UnknownSize \
     --custom-type-location tests.custom_types
 python3 scripts/generate_python_backend.py \
     --input "$OUT_DIR"/be_test_file.json \
     --output "$OUT_DIR"/be_backend.py \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_ConstantSize \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_VariableSize \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_VariableCount \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_UnknownSize \
     --custom-type-location tests.custom_types
 
 export PYTHONPATH="$OUT_DIR:.:${PYTHONPATH:-}"
diff --git a/tests/run_rust_generator_tests.sh b/tests/run_rust_generator_tests.sh
index 92e6f05..8d0eb67 100755
--- a/tests/run_rust_generator_tests.sh
+++ b/tests/run_rust_generator_tests.sh
@@ -37,8 +37,15 @@
     --exclude-declaration Packet_Array_Field_UnsizedElement_SizeModifier \
     --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier_ \
     --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier \
+    --exclude-declaration Packet_Array_ElementSize_UnsizedCustomField \
+    --exclude-declaration Packet_Array_ElementSize_SizedCustomField \
     > "$OUT_DIR/canonical_test/src/le_backend.rs"
 cargo run --bin pdlc -- \
+    tests/canonical/le_test_vectors.json \
+    --output-format rust \
+    --tests \
+    >> "$OUT_DIR/canonical_test/src/le_backend.rs"
+cargo run --bin pdlc -- \
     "$OUT_DIR/be_test_file.pdl" \
     --output-format rust \
     --exclude-declaration UnsizedCustomField \
@@ -55,20 +62,18 @@
     --exclude-declaration Packet_Array_Field_UnsizedElement_SizeModifier \
     --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier_ \
     --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier \
+    --exclude-declaration Packet_Array_ElementSize_UnsizedCustomField \
+    --exclude-declaration Packet_Array_ElementSize_SizedCustomField \
     > "$OUT_DIR/canonical_test/src/be_backend.rs"
-cargo run --bin generate-canonical-tests -- \
-    tests/canonical/le_test_vectors.json "crate::le_backend" \
-    > "$OUT_DIR/canonical_test/src/le_backend_tests.rs"
-cargo run --bin generate-canonical-tests -- \
-    tests/canonical/be_test_vectors.json "crate::be_backend" \
-    > "$OUT_DIR/canonical_test/src/be_backend_tests.rs"
-
+cargo run --bin pdlc -- \
+    tests/canonical/be_test_vectors.json \
+    --output-format rust \
+    --tests \
+    >> "$OUT_DIR/canonical_test/src/be_backend.rs"
 
 cat <<EOT > "$OUT_DIR/canonical_test/src/lib.rs"
 mod le_backend;
-mod le_backend_tests;
 mod be_backend;
-mod be_backend_tests;
 EOT
 
 cat <<EOT > "$OUT_DIR/canonical_test/Cargo.toml"
diff --git a/tests/run_rust_legacy_generator_tests.sh b/tests/run_rust_legacy_generator_tests.sh
new file mode 100755
index 0000000..53d49e7
--- /dev/null
+++ b/tests/run_rust_legacy_generator_tests.sh
@@ -0,0 +1,110 @@
+#!/usr/bin/env bash
+
+set -euxo pipefail
+
+mkdir -p out/
+OUT_DIR="$(pwd)/out"
+
+# move to `pdl-compiler` directory
+cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." &> /dev/null
+
+sed -e 's/little_endian_packets/big_endian_packets/' \
+    -e '/Start: little_endian_only/,/End: little_endian_only/d' \
+    < tests/canonical/le_test_file.pdl > "$OUT_DIR/be_test_file.pdl"
+
+mkdir -p "$OUT_DIR/canonical_test/src"
+
+cargo run --bin pdlc -- \
+    tests/canonical/le_test_file.pdl \
+    --output-format rust_legacy \
+    --exclude-declaration UnsizedCustomField \
+    --exclude-declaration Packet_Custom_Field_VariableSize \
+    --exclude-declaration Struct_Custom_Field_VariableSize_ \
+    --exclude-declaration Struct_Custom_Field_VariableSize \
+    --exclude-declaration Checksum \
+    --exclude-declaration Packet_Checksum_Field_FromStart \
+    --exclude-declaration Packet_Checksum_Field_FromEnd \
+    --exclude-declaration Struct_Checksum_Field_FromStart_ \
+    --exclude-declaration Struct_Checksum_Field_FromStart \
+    --exclude-declaration Struct_Checksum_Field_FromEnd_ \
+    --exclude-declaration Struct_Checksum_Field_FromEnd \
+    --exclude-declaration PartialParent5 \
+    --exclude-declaration PartialParent12 \
+    --exclude-declaration PartialChild5_A \
+    --exclude-declaration PartialChild5_B \
+    --exclude-declaration PartialChild12_A \
+    --exclude-declaration PartialChild12_B \
+    --exclude-declaration Packet_Array_Field_UnsizedElement_SizeModifier \
+    --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier_ \
+    --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_ConstantSize \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_VariableSize \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_VariableCount \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_UnknownSize \
+    > "$OUT_DIR/canonical_test/src/le_backend.rs"
+cargo run --bin pdlc -- \
+    tests/canonical/le_test_vectors.json \
+    --output-format rust_legacy \
+    --tests \
+    >> "$OUT_DIR/canonical_test/src/le_backend.rs"
+cargo run --bin pdlc -- \
+    "$OUT_DIR/be_test_file.pdl" \
+    --output-format rust_legacy \
+    --exclude-declaration UnsizedCustomField \
+    --exclude-declaration Packet_Custom_Field_VariableSize \
+    --exclude-declaration Struct_Custom_Field_VariableSize_ \
+    --exclude-declaration Struct_Custom_Field_VariableSize \
+    --exclude-declaration Checksum \
+    --exclude-declaration Packet_Checksum_Field_FromStart \
+    --exclude-declaration Packet_Checksum_Field_FromEnd \
+    --exclude-declaration Struct_Checksum_Field_FromStart_ \
+    --exclude-declaration Struct_Checksum_Field_FromStart \
+    --exclude-declaration Struct_Checksum_Field_FromEnd_ \
+    --exclude-declaration Struct_Checksum_Field_FromEnd \
+    --exclude-declaration Packet_Array_Field_UnsizedElement_SizeModifier \
+    --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier_ \
+    --exclude-declaration Struct_Array_Field_UnsizedElement_SizeModifier \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_ConstantSize \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_VariableSize \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_VariableCount \
+    --exclude-declaration Packet_Array_Field_VariableElementSize_UnknownSize \
+    > "$OUT_DIR/canonical_test/src/be_backend.rs"
+cargo run --bin pdlc -- \
+    tests/canonical/be_test_vectors.json \
+    --output-format rust_legacy \
+    --tests \
+    >> "$OUT_DIR/canonical_test/src/be_backend.rs"
+
+cat <<EOT > "$OUT_DIR/canonical_test/src/lib.rs"
+mod le_backend;
+mod be_backend;
+EOT
+
+cat <<EOT > "$OUT_DIR/canonical_test/Cargo.toml"
+[package]
+name = "canonical_test"
+version = "0.0.0"
+publish = false
+edition = "2021"
+
+[features]
+default = ["serde"]
+
+[dependencies]
+bytes = {version = "1.4.0", features = ["serde"]}
+thiserror = "1.0.47"
+serde_json = "1.0.86"
+
+[dependencies.serde]
+version = "1.0.145"
+features = ["default", "derive", "serde_derive", "std", "rc"]
+optional = true
+
+[dependencies.pdl-runtime]
+path = "../../pdl-runtime"
+
+[workspace]
+EOT
+
+cd "$OUT_DIR/canonical_test"
+RUSTFLAGS=-Awarnings cargo test --tests