diff options
author | Weilun Du <wdu@google.com> | 2023-07-14 14:17:19 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-07-14 14:17:19 +0000 |
commit | 35e8e2a601f37842ed8b5dec0b309cbff2687042 (patch) | |
tree | e00e76908c9390c398f7ffc6ca31cf93b9aaa8ea | |
parent | fb0b0cb8e14d488df1b73ba6376e9a875b39c85b (diff) | |
parent | afcefe6794d7b84ca0fabd35fa05517e77be7015 (diff) | |
download | pdl-compiler-35e8e2a601f37842ed8b5dec0b309cbff2687042.tar.gz |
Revert "Update pdl-compiler to 0.1.4" am: afcefe6794
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/pdl-compiler/+/2658075
Change-Id: I11523d5e7d25b735ba7afda76cd087a5385c174e
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
49 files changed, 669 insertions, 1947 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index f776014..24636e7 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "ff041c0f60f985ecc2f8c90bdec618575dcb5060" + "sha1": "6b05a0616ef2a982068e0d5fbe28d2058d49d8e0" }, "path_in_vcs": "" }
\ No newline at end of file @@ -7,7 +7,7 @@ rust_binary_host { name: "generate_canonical_tests", crate_name: "generate_canonical_tests", cargo_env_compat: true, - cargo_pkg_version: "0.1.4", + cargo_pkg_version: "0.1.3", srcs: ["src/bin/generate-canonical-tests.rs"], edition: "2021", features: [ @@ -37,7 +37,7 @@ rust_library_host { name: "libpdl_compiler", crate_name: "pdl_compiler", cargo_env_compat: true, - cargo_pkg_version: "0.1.4", + cargo_pkg_version: "0.1.3", srcs: ["src/lib.rs"], edition: "2021", features: [ @@ -66,7 +66,7 @@ rust_binary_host { name: "pdlc", crate_name: "pdlc", cargo_env_compat: true, - cargo_pkg_version: "0.1.4", + cargo_pkg_version: "0.1.3", srcs: ["src/main.rs"], edition: "2021", features: [ @@ -12,7 +12,7 @@ [package] edition = "2021" name = "pdl-compiler" -version = "0.1.4" +version = "0.1.3" authors = [ "Henri Chataing <henrichataing@google.com>", "David de Jesus Duarte <licorne@google.com>", @@ -32,7 +32,7 @@ keywords = [ "grammar", ] categories = ["parsing"] -license = "Apache-2.0" +license-file = "LICENSE" repository = "https://github.com/google/pdl/" [[bin]] @@ -85,7 +85,7 @@ version = "1.2.1" features = ["serde"] [dev-dependencies.googletest] -version = "0.8.0" +version = "0.7.0" [dev-dependencies.num-derive] version = "0.3.3" diff --git a/Cargo.toml.orig b/Cargo.toml.orig index cf8b0cf..c9fa183 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,10 +1,10 @@ [package] name = "pdl-compiler" -version = "0.1.4" +version = "0.1.3" edition = "2021" description = "Parser and serializer generator for protocol binary packets" repository = "https://github.com/google/pdl/" -license = "Apache-2.0" +license-file = "LICENSE" readme = "README.md" keywords = ["pdl", "parser", "serializer", "grammar"] authors = [ @@ -49,4 +49,4 @@ num-derive = "0.3.3" num-traits = "0.2.15" thiserror = "1.0.37" paste = "1.0.6" -googletest = "0.8.0" +googletest = "0.7.0" @@ -11,13 +11,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/pdl-compiler/pdl-compiler-0.1.4.crate" + value: "https://static.crates.io/crates/pdl-compiler/pdl-compiler-0.1.3.crate" } - version: "0.1.4" + version: "0.1.3" license_type: NOTICE last_upgrade_date { year: 2023 - month: 7 - day: 13 + month: 6 + day: 27 } } diff --git a/doc/cxx-generated-code-guide.rst b/doc/cxx-generated-code-guide.rst index 3a71430..f694e70 100644 --- a/doc/cxx-generated-code-guide.rst +++ b/doc/cxx-generated-code-guide.rst @@ -25,23 +25,3 @@ Example invocation: 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 index de766d4..664d759 100644 --- a/doc/python-generated-code-guide.rst +++ b/doc/python-generated-code-guide.rst @@ -49,13 +49,9 @@ Enum declarations | A = 1, | A = 1 | | B = 2..3, | B_MIN = 2 | | C = 4, | B_MAX = 3 | -| OTHER = .., | C = 4 | -| } | | +| } | C = 4 | +---------------------------------------+---------------------------------------------------------------+ -.. note:: - Python enums are open by construction, default cases in enum declarations are ignored. - Packet declarations ^^^^^^^^^^^^^^^^^^^ diff --git a/doc/reference.md b/doc/reference.md index ce2f0a7..2529c29 100644 --- a/doc/reference.md +++ b/doc/reference.md @@ -161,7 +161,7 @@ A declaration is either: > enum_tag (`,` enum_tag)* `,`? > > enum_tag:\ -> enum_range | enum_value | enum_other +> enum_range | enum_value > > enum_range:\ > [IDENTIFIER](#identifier) `=` [INTEGER](#integer) `..` [INTEGER](#integer)) (`{`\ @@ -173,20 +173,12 @@ A declaration is either: > > enum_value:\ > [IDENTIFIER](#identifier) `=` [INTEGER](#integer) -> -> enum_other:\ -> [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. ``` @@ -207,8 +199,6 @@ enum CoffeeAddition: 5 { }, Custom = 20..29, - - Other = .. } ``` diff --git a/doc/rust-generated-code-guide.rst b/doc/rust-generated-code-guide.rst index 6dfdfd0..df22d92 100644 --- a/doc/rust-generated-code-guide.rst +++ b/doc/rust-generated-code-guide.rst @@ -30,10 +30,6 @@ backend may create it. 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 ^^^^^^^^^^^^^^^^^ @@ -76,23 +72,3 @@ Enum declarations | | 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/scripts/generate_test_vectors.py b/scripts/generate_test_vectors.py deleted file mode 100755 index ef2ea24..0000000 --- a/scripts/generate_test_vectors.py +++ /dev/null @@ -1,685 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import collections -import copy -import json -from pathlib import Path -import pprint -import traceback -from typing import Iterable, List, Optional, Union -import sys - -from pdl import ast, core - -MAX_ARRAY_SIZE = 256 -MAX_ARRAY_COUNT = 32 -DEFAULT_ARRAY_COUNT = 3 -DEFAULT_PAYLOAD_SIZE = 5 - - -class BitSerializer: - def __init__(self, big_endian: bool): - self.stream = [] - self.value = 0 - self.shift = 0 - self.byteorder = "big" if big_endian else "little" - - def append(self, value: int, width: int): - self.value = self.value | (value << self.shift) - self.shift += width - - if (self.shift % 8) == 0: - width = int(self.shift / 8) - self.stream.extend(self.value.to_bytes(width, byteorder=self.byteorder)) - self.shift = 0 - self.value = 0 - - -class Value: - def __init__(self, value: object, width: Optional[int] = None): - self.value = value - if width is not None: - self.width = width - elif isinstance(value, int) or callable(value): - raise Exception("Creating scalar value of unspecified width") - elif isinstance(value, list): - self.width = sum([v.width for v in value]) - elif isinstance(value, Packet): - self.width = value.width - else: - raise Exception(f"Malformed value {value}") - - def finalize(self, parent: "Packet"): - if callable(self.width): - self.width = self.width(parent) - - if callable(self.value): - self.value = self.value(parent) - elif isinstance(self.value, list): - for v in self.value: - v.finalize(parent) - elif isinstance(self.value, Packet): - self.value.finalize() - - def serialize_(self, serializer: BitSerializer): - if isinstance(self.value, int): - serializer.append(self.value, self.width) - elif isinstance(self.value, list): - for v in self.value: - v.serialize_(serializer) - elif isinstance(self.value, Packet): - self.value.serialize_(serializer) - else: - raise Exception(f"Malformed value {self.value}") - - def show(self, indent: int = 0): - space = " " * indent - if isinstance(self.value, int): - print(f"{space}{self.name}: {hex(self.value)}") - elif isinstance(self.value, list): - print(f"{space}{self.name}[{len(self.value)}]:") - for v in self.value: - v.show(indent + 2) - elif isinstance(self.value, Packet): - print(f"{space}{self.name}:") - self.value.show(indent + 2) - - def to_json(self) -> object: - if isinstance(self.value, int): - return self.value - elif isinstance(self.value, list): - return [v.to_json() for v in self.value] - elif isinstance(self.value, Packet): - return self.value.to_json() - - -class Field: - def __init__(self, value: Value, ref: ast.Field): - self.value = value - self.ref = ref - - def finalize(self, parent: "Packet"): - self.value.finalize(parent) - - def serialize_(self, serializer: BitSerializer): - self.value.serialize_(serializer) - - def clone(self): - return Field(copy.copy(self.value), self.ref) - - -class Packet: - def __init__(self, fields: List[Field], ref: ast.Declaration): - self.fields = fields - self.ref = ref - - def finalize(self, parent: Optional["Packet"] = None): - for f in self.fields: - f.finalize(self) - - def serialize_(self, serializer: BitSerializer): - for f in self.fields: - f.serialize_(serializer) - - def serialize(self, big_endian: bool) -> bytes: - serializer = BitSerializer(big_endian) - self.serialize_(serializer) - if serializer.shift != 0: - raise Exception("The packet size is not an integral number of octets") - return bytes(serializer.stream) - - def show(self, indent: int = 0): - for f in self.fields: - f.value.show(indent) - - def to_json(self) -> dict: - result = dict() - for f in self.fields: - if isinstance(f.ref, (ast.PayloadField, ast.BodyField)) and isinstance( - f.value.value, Packet - ): - result.update(f.value.to_json()) - elif isinstance(f.ref, (ast.PayloadField, ast.BodyField)): - result["payload"] = f.value.to_json() - elif hasattr(f.ref, "id"): - result[f.ref.id] = f.value.to_json() - return result - - @property - def width(self) -> int: - self.finalize() - return sum([f.value.width for f in self.fields]) - - -class BitGenerator: - def __init__(self): - self.value = 0 - self.shift = 0 - - def generate(self, width: int) -> Value: - """Generate an integer value of the selected width.""" - value = 0 - remains = width - while remains > 0: - w = min(8 - self.shift, remains) - mask = (1 << w) - 1 - value = (value << w) | ((self.value >> self.shift) & mask) - remains -= w - self.shift += w - if self.shift >= 8: - self.shift = 0 - self.value = (self.value + 1) % 0xFF - return Value(value, width) - - def generate_list(self, width: int, count: int) -> List[Value]: - return [self.generate(width) for n in range(count)] - - -generator = BitGenerator() - - -def generate_size_field_values(field: ast.SizeField) -> List[Value]: - def get_field_size(parent: Packet, field_id: str) -> int: - for f in parent.fields: - if ( - (field_id == "_payload_" and isinstance(f.ref, ast.PayloadField)) - or (field_id == "_body_" and isinstance(f.ref, ast.BodyField)) - or (getattr(f.ref, "id", None) == field_id) - ): - assert f.value.width % 8 == 0 - size_modifier = int(getattr(f.ref, "size_modifier", None) or 0) - return int(f.value.width / 8) + size_modifier - raise Exception( - "Field {} not found in packet {}".format(field_id, parent.ref.id) - ) - - return [Value(lambda p: get_field_size(p, field.field_id), field.width)] - - -def generate_count_field_values(field: ast.CountField) -> List[Value]: - def get_array_count(parent: Packet, field_id: str) -> int: - for f in parent.fields: - if getattr(f.ref, "id", None) == field_id: - assert isinstance(f.value.value, list) - return len(f.value.value) - raise Exception( - "Field {} not found in packet {}".format(field_id, parent.ref.id) - ) - - return [Value(lambda p: get_array_count(p, field.field_id), field.width)] - - -def generate_checksum_field_values(field: ast.TypedefField) -> List[Value]: - field_width = core.get_field_size(field) - - def basic_checksum(input: bytes, width: int): - assert width == 8 - return sum(input) % 256 - - def compute_checksum(parent: Packet, field_id: str) -> int: - serializer = None - for f in parent.fields: - if isinstance(f.ref, ast.ChecksumField) and f.ref.field_id == field_id: - serializer = BitSerializer( - f.ref.parent.file.endianness.value == "big_endian" - ) - elif isinstance(f.ref, ast.TypedefField) and f.ref.id == field_id: - return basic_checksum(serializer.stream, field_width) - elif serializer: - f.value.serialize_(serializer) - raise Exception("malformed checksum") - - return [Value(lambda p: compute_checksum(p, field.id), field_width)] - - -def generate_padding_field_values(field: ast.PaddingField) -> List[Value]: - preceding_field_id = field.padded_field.id - - def get_padding(parent: Packet, field_id: str, width: int) -> List[Value]: - for f in parent.fields: - if ( - (field_id == "_payload_" and isinstance(f.ref, ast.PayloadField)) - or (field_id == "_body_" and isinstance(f.ref, ast.BodyField)) - or (getattr(f.ref, "id", None) == field_id) - ): - assert f.value.width % 8 == 0 - assert f.value.width <= width - return width - f.value.width - raise Exception( - "Field {} not found in packet {}".format(field_id, parent.ref.id) - ) - - return [Value(0, lambda p: get_padding(p, preceding_field_id, 8 * field.size))] - - -def generate_payload_field_values( - field: Union[ast.PayloadField, ast.BodyField] -) -> List[Value]: - payload_size = core.get_payload_field_size(field) - size_modifier = int(getattr(field, "size_modifier", None) or 0) - - # If the paylaod has a size field, generate an empty payload and - # a payload of maximum size. If not generate a payload of the default size. - max_size = (1 << payload_size.width) - 1 if payload_size else DEFAULT_PAYLOAD_SIZE - max_size -= size_modifier - - assert max_size > 0 - return [Value([]), Value(generator.generate_list(8, max_size))] - - -def generate_scalar_array_field_values(field: ast.ArrayField) -> List[Value]: - if field.width % 8 != 0: - if element_width % 8 != 0: - raise Exception("Array element size is not a multiple of 8") - - array_size = core.get_array_field_size(field) - element_width = int(field.width / 8) - - # TODO - # The array might also be bounded if it is included in the sized payload - # of a packet. - - # Apply the size modifiers. - size_modifier = int(getattr(field, "size_modifier", None) or 0) - - # The element width is known, and the array element count is known - # statically. - if isinstance(array_size, int): - return [Value(generator.generate_list(field.width, array_size))] - - # The element width is known, and the array element count is known - # by count field. - elif isinstance(array_size, ast.CountField): - min_count = 0 - max_count = (1 << array_size.width) - 1 - return [Value([]), Value(generator.generate_list(field.width, max_count))] - - # The element width is known, and the array full size is known - # by size field. - elif isinstance(array_size, ast.SizeField): - min_count = 0 - max_size = (1 << array_size.width) - 1 - size_modifier - max_count = int(max_size / element_width) - return [Value([]), Value(generator.generate_list(field.width, max_count))] - - # The element width is known, but the array size is unknown. - # Generate two arrays: one empty and one including some possible element - # values. - else: - return [ - Value([]), - Value(generator.generate_list(field.width, DEFAULT_ARRAY_COUNT)), - ] - - -def generate_typedef_array_field_values(field: ast.ArrayField) -> List[Value]: - array_size = core.get_array_field_size(field) - element_width = core.get_array_element_size(field) - if element_width: - if element_width % 8 != 0: - raise Exception("Array element size is not a multiple of 8") - element_width = int(element_width / 8) - - # Generate element values to use for the generation. - type_decl = field.parent.file.typedef_scope[field.type_id] - - def generate_list(count: Optional[int]) -> List[Value]: - """Generate an array of specified length. - If the count is None all possible array items are returned.""" - element_values = generate_typedef_values(type_decl) - - # Requested a variable count, send everything in one chunk. - if count is None: - return [Value(element_values)] - # Have more items than the requested count. - # Slice the possible array values in multiple slices. - elif len(element_values) > count: - # Add more elements in case of wrap-over. - elements_count = len(element_values) - element_values.extend(generate_typedef_values(type_decl)) - chunk_count = int((len(elements) + count - 1) / count) - return [ - Value(element_values[n * count : (n + 1) * count]) - for n in range(chunk_count) - ] - # Have less items than the requested count. - # Generate additional items to fill the gap. - else: - chunk = element_values - while len(chunk) < count: - chunk.extend(generate_typedef_values(type_decl)) - return [Value(chunk[:count])] - - # TODO - # The array might also be bounded if it is included in the sized payload - # of a packet. - - # Apply the size modifier. - size_modifier = int(getattr(field, "size_modifier", None) or 0) - - min_size = 0 - max_size = MAX_ARRAY_SIZE - min_count = 0 - max_count = MAX_ARRAY_COUNT - - if field.padded_size: - max_size = field.padded_size - - if isinstance(array_size, ast.SizeField): - max_size = (1 << array_size.width) - 1 - size_modifier - min_size = size_modifier - elif isinstance(array_size, ast.CountField): - max_count = (1 << array_size.width) - 1 - elif isinstance(array_size, int): - min_count = array_size - max_count = array_size - - values = [] - chunk = [] - chunk_size = 0 - - while not values: - element_values = generate_typedef_values(type_decl) - for element_value in element_values: - element_size = int(element_value.width / 8) - - if len(chunk) >= max_count or chunk_size + element_size > max_size: - assert len(chunk) >= min_count - values.append(Value(chunk)) - chunk = [] - chunk_size = 0 - - chunk.append(element_value) - chunk_size += element_size - - if min_count == 0: - values.append(Value([])) - - return values - - # The element width is not known, but the array full octet size - # is known by size field. Generate two arrays: of minimal and maximum - # size. All unused element values are packed into arrays of varying size. - if element_width is None and isinstance(array_size, ast.SizeField): - element_values = generate_typedef_values(type_decl) - chunk = [] - chunk_size = 0 - values = [Value([])] - for element_value in element_values: - assert element_value.width % 8 == 0 - element_size = int(element_value.width / 8) - if chunk_size + element_size > max_size: - values.append(Value(chunk)) - chunk = [] - chunk.append(element_value) - chunk_size += element_size - if chunk: - values.append(Value(chunk)) - return values - - # The element width is not known, but the array element count - # is known statically or by count field. Generate two arrays: - # of minimal and maximum length. All unused element values are packed into - # arrays of varying count. - elif element_width is None and isinstance(array_size, ast.CountField): - return [Value([])] + generate_list(max_count) - - # The element width is not known, and the array element count is known - # statically. - elif element_width is None and isinstance(array_size, int): - return generate_list(array_size) - - # Neither the count not size is known, - # generate two arrays: one empty and one including all possible element - # values. - elif element_width is None: - return [Value([])] + generate_list(None) - - # The element width is known, and the array element count is known - # statically. - elif isinstance(array_size, int): - return generate_list(array_size) - - # The element width is known, and the array element count is known - # by count field. - elif isinstance(array_size, ast.CountField): - return [Value([])] + generate_list(max_count) - - # The element width is known, and the array full size is known - # by size field. - elif isinstance(array_size, ast.SizeField): - return [Value([])] + generate_list(max_count) - - # The element width is known, but the array size is unknown. - # Generate two arrays: one empty and one including all possible element - # values. - else: - return [Value([])] + generate_list(None) - - -def generate_array_field_values(field: ast.ArrayField) -> List[Value]: - if field.width is not None: - return generate_scalar_array_field_values(field) - else: - return generate_typedef_array_field_values(field) - - -def generate_typedef_field_values( - field: ast.TypedefField, constraints: List[ast.Constraint] -) -> List[Value]: - type_decl = field.parent.file.typedef_scope[field.type_id] - - # Check for constraint on enum field. - if isinstance(type_decl, ast.EnumDeclaration): - for c in constraints: - if c.id == field.id: - for tag in type_decl.tags: - if tag.id == c.tag_id: - return [Value(tag.value, type_decl.width)] - raise Exception("undefined enum tag") - - # Checksum field needs to known the checksum range. - if isinstance(type_decl, ast.ChecksumDeclaration): - return generate_checksum_field_values(field) - - return generate_typedef_values(type_decl) - - -def generate_field_values( - field: ast.Field, constraints: List[ast.Constraint], payload: Optional[List[Packet]] -) -> List[Value]: - if isinstance(field, ast.ChecksumField): - # Checksum fields are just markers. - return [Value(0, 0)] - - elif isinstance(field, ast.PaddingField): - return generate_padding_field_values(field) - - elif isinstance(field, ast.SizeField): - return generate_size_field_values(field) - - elif isinstance(field, ast.CountField): - return generate_count_field_values(field) - - elif isinstance(field, (ast.BodyField, ast.PayloadField)) and payload: - return [Value(p) for p in payload] - - elif isinstance(field, (ast.BodyField, ast.PayloadField)): - return generate_payload_field_values(field) - - elif isinstance(field, ast.FixedField) and field.enum_id: - enum_decl = field.parent.file.typedef_scope[field.enum_id] - for tag in enum_decl.tags: - if tag.id == field.tag_id: - return [Value(tag.value, enum_decl.width)] - raise Exception("undefined enum tag") - - elif isinstance(field, ast.FixedField) and field.width: - return [Value(field.value, field.width)] - - elif isinstance(field, ast.ReservedField): - return [Value(0, field.width)] - - elif isinstance(field, ast.ArrayField): - return generate_array_field_values(field) - - elif isinstance(field, ast.ScalarField): - for c in constraints: - if c.id == field.id: - return [Value(c.value, field.width)] - mask = (1 << field.width) - 1 - return [ - Value(0, field.width), - Value(-1 & mask, field.width), - generator.generate(field.width), - ] - - elif isinstance(field, ast.TypedefField): - return generate_typedef_field_values(field, constraints) - - else: - raise Exception("unsupported field kind") - - -def generate_fields( - decl: ast.Declaration, - constraints: List[ast.Constraint], - payload: Optional[List[Packet]], -) -> List[List[Field]]: - return [ - [Field(v, f) for v in generate_field_values(f, constraints, payload)] - for f in decl.fields - ] - - -def generate_fields_recursive( - scope: dict, - decl: ast.Declaration, - constraints: List[ast.Constraint] = [], - payload: Optional[List[Packet]] = None, -) -> List[List[Field]]: - fields = generate_fields(decl, constraints, payload) - - if not decl.parent_id: - return fields - - packets = [Packet(fields, decl) for fields in product(fields)] - parent_decl = scope[decl.parent_id] - return generate_fields_recursive( - scope, parent_decl, constraints + decl.constraints, payload=packets - ) - - -def generate_struct_values(decl: ast.StructDeclaration) -> List[Packet]: - fields = generate_fields_recursive(decl.file.typedef_scope, decl) - return [Packet(fields, decl) for fields in product(fields)] - - -def generate_packet_values(decl: ast.PacketDeclaration) -> List[Packet]: - fields = generate_fields_recursive(decl.file.packet_scope, decl) - return [Packet(fields, decl) for fields in product(fields)] - - -def generate_typedef_values(decl: ast.Declaration) -> List[Value]: - if isinstance(decl, ast.EnumDeclaration): - return [Value(t.value, decl.width) for t in decl.tags] - - elif isinstance(decl, ast.ChecksumDeclaration): - raise Exception("ChecksumDeclaration handled in typedef field") - - elif isinstance(decl, ast.CustomFieldDeclaration): - raise Exception("TODO custom field") - - elif isinstance(decl, ast.StructDeclaration): - return [Value(p) for p in generate_struct_values(decl)] - - else: - raise Exception("unsupported typedef declaration type") - - -def product(fields: List[List[Field]]) -> List[List[Field]]: - """Perform a cartesian product of generated options for packet field values.""" - - def aux(vec: List[List[Field]]) -> List[List[Field]]: - if len(vec) == 0: - return [[]] - return [[item.clone()] + items for item in vec[0] for items in aux(vec[1:])] - - count = 1 - max_len = 0 - for f in fields: - count *= len(f) - max_len = max(max_len, len(f)) - - # Limit products to 32 elements to prevent combinatorial - # explosion. - if count <= 32: - return aux(fields) - - # If too many products, select samples which test all fields value - # values at the minimum. - else: - return [[f[idx % len(f)] for f in fields] for idx in range(0, max_len + 1)] - - -def serialize_values(file: ast.File, values: List[Value]) -> List[dict]: - results = [] - for v in values: - v.finalize() - packed = v.serialize(file.endianness.value == "big_endian") - result = { - "packed": "".join([f"{b:02x}" for b in packed]), - "unpacked": v.to_json(), - } - if v.ref.parent_id: - result["packet"] = v.ref.id - results.append(result) - return results - - -def run(input: Path, packet: List[str]): - with open(input) as f: - file = ast.File.from_json(json.load(f)) - core.desugar(file) - - results = dict() - for decl in file.packet_scope.values(): - if core.get_derived_packets(decl) or (packet and decl.id not in packet): - continue - - try: - values = generate_packet_values(decl) - ancestor = core.get_packet_ancestor(decl) - results[ancestor.id] = results.get(ancestor.id, []) + serialize_values( - file, values - ) - except Exception as exn: - print( - f"Skipping packet {decl.id}; cannot generate values: {exn}", - file=sys.stderr, - ) - - results = [{"packet": k, "tests": v} for (k, v) in results.items()] - json.dump(results, sys.stdout, indent=2) - - -def main() -> int: - """Generate test vectors for top-level PDL packets.""" - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--input", type=Path, required=True, help="Input PDL-JSON source" - ) - parser.add_argument( - "--packet", - type=lambda x: x.split(","), - required=False, - action="extend", - default=[], - help="Select PDL packet to test", - ) - return run(**vars(parser.parse_args())) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/src/analyzer.rs b/src/analyzer.rs index c89d3d0..1757e5e 100644 --- a/src/analyzer.rs +++ b/src/analyzer.rs @@ -190,7 +190,6 @@ pub enum ErrorCode { DuplicateTagRange = 41, E42 = 42, E43 = 43, - DuplicateDefaultTag = 44, } impl From<ErrorCode> for String { @@ -206,10 +205,8 @@ pub struct Diagnostics { } /// Gather information about the full AST. -#[derive(Debug)] -pub struct Scope<'d, A: Annotation = ast::Annotation> { - /// Reference to the source file. - pub file: &'d crate::ast::File<A>, +#[derive(Debug, Default)] +pub struct Scope<'d, A: Annotation> { /// Collection of Group, Packet, Enum, Struct, Checksum, and CustomField /// declarations. pub typedef: HashMap<String, &'d crate::ast::Decl<A>>, @@ -248,7 +245,7 @@ impl Diagnostics { impl<'d, A: Annotation + Default> Scope<'d, A> { pub fn new(file: &'d crate::ast::File<A>) -> Result<Scope<'d, A>, Diagnostics> { // Gather top-level declarations. - let mut scope: Scope<A> = Scope { file, typedef: Default::default() }; + let mut scope: Scope<A> = Default::default(); let mut diagnostics: Diagnostics = Default::default(); for decl in &file.declarations { if let Some(id) = decl.id() { @@ -280,14 +277,6 @@ impl<'d, A: Annotation + Default> Scope<'d, A> { } } - /// 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 { - 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>> { @@ -302,15 +291,6 @@ impl<'d, A: Annotation + Default> Scope<'d, A> { std::iter::successors(self.get_parent(decl), |decl| self.get_parent(decl)) } - /// Iterate over the parent declarations of the selected declaration, - /// 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 { - 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, @@ -319,27 +299,11 @@ impl<'d, A: Annotation + Default> Scope<'d, A> { 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 { - std::iter::successors(self.get_parent(decl), |decl| self.get_parent(decl)) - .flat_map(Decl::fields) - } - - /// Iterate over the declaration and its parent's constraints. - pub fn iter_constraints<'s>( - &'s self, - decl: &'d crate::ast::Decl<A>, - ) -> 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( + #[allow(dead_code)] + pub fn get_declaration( &self, - field: &crate::ast::Field<A>, + field: &'d crate::ast::Field<A>, ) -> Option<&'d crate::ast::Decl<A>> { match &field.desc { FieldDesc::Checksum { .. } @@ -359,24 +323,6 @@ impl<'d, A: Annotation + Default> Scope<'d, A> { | FieldDesc::Typedef { type_id, .. } => self.typedef.get(type_id).cloned(), } } - - /// Test if the selected field is a bit-field. - pub fn is_bitfield(&self, field: &crate::ast::Field<A>) -> bool { - match &field.desc { - FieldDesc::Size { .. } - | FieldDesc::Count { .. } - | FieldDesc::ElementSize { .. } - | FieldDesc::FixedScalar { .. } - | FieldDesc::FixedEnum { .. } - | FieldDesc::Reserved { .. } - | FieldDesc::Scalar { .. } => true, - FieldDesc::Typedef { type_id, .. } => { - let field = self.typedef.get(type_id.as_str()); - matches!(field, Some(Decl { desc: DeclDesc::Enum { .. }, .. })) - } - _ => false, - } - } } /// Return the bit-width of a scalar value. @@ -736,39 +682,6 @@ fn check_enum_declarations(file: &parser_ast::File) -> Result<(), Diagnostics> { } } - fn check_tag_other<'a>( - tag: &'a TagOther, - tags_by_id: &mut HashMap<&'a str, SourceRange>, - tag_other: &mut Option<SourceRange>, - diagnostics: &mut Diagnostics, - ) { - if let Some(prev) = tags_by_id.insert(&tag.id, tag.loc) { - diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::DuplicateTagIdentifier) - .with_message(format!("duplicate tag identifier `{}`", tag.id)) - .with_labels(vec![ - tag.loc.primary(), - prev.secondary() - .with_message(format!("`{}` is first declared here", tag.id)), - ]), - ) - } - if let Some(prev) = tag_other { - diagnostics.push( - Diagnostic::error() - .with_code(ErrorCode::DuplicateDefaultTag) - .with_message("duplicate default tag".to_owned()) - .with_labels(vec![ - tag.loc.primary(), - prev.secondary() - .with_message("the default tag is first declared here".to_owned()), - ]), - ) - } - *tag_other = Some(tag.loc) - } - let mut diagnostics: Diagnostics = Default::default(); for decl in &file.declarations { if let DeclDesc::Enum { tags, width, .. } = &decl.desc { @@ -781,7 +694,6 @@ fn check_enum_declarations(file: &parser_ast::File) -> Result<(), Diagnostics> { _ => None, }) .collect::<Vec<_>>(); - let mut tag_other = None; for tag in tags { match tag { @@ -800,9 +712,6 @@ fn check_enum_declarations(file: &parser_ast::File) -> Result<(), Diagnostics> { &mut tags_by_value, &mut diagnostics, ), - Tag::Other(other) => { - check_tag_other(other, &mut tags_by_id, &mut tag_other, &mut diagnostics) - } } } @@ -1933,17 +1842,6 @@ mod test { } "# ); - - raises!( - DuplicateTagIdentifier, - r#" - little_endian_packets - enum A : 8 { - X = 0, - X = .., - } - "# - ); } #[test] @@ -2622,22 +2520,6 @@ mod test { } #[test] - fn test_e44() { - raises!( - DuplicateDefaultTag, - r#" - little_endian_packets - enum A : 8 { - A = 0, - X = .., - B = 1, - Y = .., - } - "# - ); - } - - #[test] fn test_enum_declaration() { valid!( r#" @@ -2672,17 +2554,6 @@ mod test { } "# ); - - valid!( - r#" - little_endian_packets - enum A : 7 { - A = 50..100, - X = 101, - UNKNOWN = .., - } - "# - ); } use analyzer::ast::Size; @@ -86,19 +86,11 @@ pub struct TagRange { pub tags: Vec<TagValue>, } -#[derive(Debug, Clone, Serialize)] -#[serde(tag = "kind", rename = "tag")] -pub struct TagOther { - pub id: String, - pub loc: SourceRange, -} - #[derive(Debug, Serialize, Clone, PartialEq, Eq)] #[serde(untagged)] pub enum Tag { Value(TagValue), Range(TagRange), - Other(TagOther), } #[derive(Debug, Serialize, Clone)] @@ -296,35 +288,23 @@ impl PartialEq for TagRange { } } -impl Eq for TagOther {} -impl PartialEq for TagOther { - fn eq(&self, other: &Self) -> bool { - // Implement structual equality, leave out loc. - self.id == other.id - } -} - impl Tag { pub fn id(&self) -> &str { match self { - Tag::Value(TagValue { id, .. }) - | Tag::Range(TagRange { id, .. }) - | Tag::Other(TagOther { id, .. }) => id, + Tag::Value(TagValue { id, .. }) | Tag::Range(TagRange { id, .. }) => id, } } pub fn loc(&self) -> &SourceRange { match self { - Tag::Value(TagValue { loc, .. }) - | Tag::Range(TagRange { loc, .. }) - | Tag::Other(TagOther { loc, .. }) => loc, + Tag::Value(TagValue { loc, .. }) | Tag::Range(TagRange { loc, .. }) => loc, } } pub fn value(&self) -> Option<usize> { match self { Tag::Value(TagValue { value, .. }) => Some(*value), - Tag::Range(_) | Tag::Other(_) => None, + Tag::Range(_) => None, } } } @@ -471,31 +451,6 @@ impl<A: Annotation> Decl<A> { } } - /// Return the reference to the payload or body field in a declaration, - /// if present. - pub fn payload(&self) -> Option<&Field<A>> { - 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>> { - self.fields().find(|field| match &field.desc { - FieldDesc::Size { field_id, .. } => field_id == "_payload_" || field_id == "_body_", - _ => false, - }) - } - - /// 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>> { - self.fields().find(|field| match &field.desc { - FieldDesc::Size { field_id, .. } | FieldDesc::Count { field_id, .. } => field_id == id, - _ => false, - }) - } - pub fn kind(&self) -> &str { match &self.desc { DeclDesc::Checksum { .. } => "checksum", diff --git a/src/backends/rust.rs b/src/backends/rust.rs index 9dfdf8a..f369179 100644 --- a/src/backends/rust.rs +++ b/src/backends/rust.rs @@ -14,10 +14,9 @@ //! Rust compiler backend. -use crate::{analyzer, ast}; +use crate::{ast, lint}; use quote::{format_ident, quote}; use std::collections::BTreeSet; -use std::collections::HashMap; use std::path::Path; use syn::LitInt; @@ -31,25 +30,25 @@ mod types; use parser::FieldParser; use serializer::FieldSerializer; +#[cfg(not(tm_mainline_prod))] pub use heck::ToUpperCamelCase; -pub trait ToIdent { - /// Generate a sanitized rust identifier. - /// Rust specific keywords are renamed for validity. - fn to_ident(self) -> proc_macro2::Ident; +#[cfg(tm_mainline_prod)] +pub trait ToUpperCamelCase { + fn to_upper_camel_case(&self) -> String; } -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), +#[cfg(tm_mainline_prod)] +impl ToUpperCamelCase for str { + fn to_upper_camel_case(&self) -> String { + use heck::CamelCase; + let camel_case = self.to_camel_case(); + if camel_case.is_empty() { + camel_case + } else { + // PDL identifiers are a-zA-z0-9, so we're dealing with + // simple ASCII text. + format!("{}{}", &camel_case[..1].to_ascii_uppercase(), &camel_case[1..]) } } } @@ -85,7 +84,7 @@ pub fn mask_bits(n: usize, suffix: &str) -> syn::LitInt { } fn generate_packet_size_getter<'a>( - scope: &analyzer::Scope<'a>, + scope: &lint::Scope<'a>, fields: impl Iterator<Item = &'a analyzer_ast::Field>, is_packet: bool, ) -> (usize, proc_macro2::TokenStream) { @@ -98,7 +97,7 @@ fn generate_packet_size_getter<'a>( continue; } - let decl = scope.get_type_declaration(field); + let decl = scope.get_field_declaration(field); dynamic_widths.push(match &field.desc { ast::FieldDesc::Payload { .. } | ast::FieldDesc::Body { .. } => { if is_packet { @@ -112,11 +111,11 @@ fn generate_packet_size_getter<'a>( } } ast::FieldDesc::Typedef { id, .. } => { - let id = id.to_ident(); + let id = format_ident!("{id}"); quote!(self.#id.get_size()) } ast::FieldDesc::Array { id, width, .. } => { - let id = id.to_ident(); + let id = format_ident!("{id}"); match &decl { Some(analyzer_ast::Decl { desc: ast::DeclDesc::Struct { .. } | ast::DeclDesc::CustomField { .. }, @@ -164,10 +163,7 @@ fn generate_packet_size_getter<'a>( ) } -fn top_level_packet<'a>( - scope: &analyzer::Scope<'a>, - packet_name: &'a str, -) -> &'a analyzer_ast::Decl { +fn top_level_packet<'a>(scope: &lint::Scope<'a>, packet_name: &'a str) -> &'a analyzer_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 @@ -177,68 +173,74 @@ fn top_level_packet<'a>( decl } -/// Find parent fields which are constrained in child packets. -/// -/// These fields are the fields which need to be passed in when -/// parsing a `id` packet since their values are needed for one or -/// more child packets. -fn find_constrained_parent_fields<'a>( - scope: &analyzer::Scope<'a>, - id: &str, +/// Find all constrained fields in children of `id`. +fn find_constrained_fields<'a>( + scope: &'a lint::Scope<'a>, + id: &'a str, ) -> Vec<&'a analyzer_ast::Field> { - let all_parent_fields: HashMap<String, &'a analyzer_ast::Field> = HashMap::from_iter( - scope - .iter_parent_fields(scope.typedef[id]) - .filter_map(|f| f.id().map(|id| (id.to_string(), f))), - ); - let mut fields = Vec::new(); let mut field_names = BTreeSet::new(); - let mut children = scope.iter_children(scope.typedef[id]).collect::<Vec<_>>(); + let mut children = scope.iter_children(id).collect::<Vec<_>>(); while let Some(child) = children.pop() { if let ast::DeclDesc::Packet { id, constraints, .. } | ast::DeclDesc::Struct { id, constraints, .. } = &child.desc { + let packet_scope = &scope.scopes[&scope.typedef[id]]; for constraint in constraints { - if field_names.insert(&constraint.id) - && all_parent_fields.contains_key(&constraint.id) - { - fields.push(all_parent_fields[&constraint.id]); + if field_names.insert(&constraint.id) { + fields.push(packet_scope.all_fields[&constraint.id]); } } - children.extend(scope.iter_children(scope.typedef[id]).collect::<Vec<_>>()); + children.extend(scope.iter_children(id).collect::<Vec<_>>()); } } fields } +/// Find parent fields which are constrained in child packets. +/// +/// These fields are the fields which need to be passed in when +/// parsing a `id` packet since their values are needed for one or +/// more child packets. +fn find_constrained_parent_fields<'a>( + scope: &'a lint::Scope<'a>, + id: &'a str, +) -> impl Iterator<Item = &'a analyzer_ast::Field> { + let packet_scope = &scope.scopes[&scope.typedef[id]]; + find_constrained_fields(scope, id).into_iter().filter(|field| { + let id = field.id().unwrap(); + packet_scope.all_fields.contains_key(id) && packet_scope.get_packet_field(id).is_none() + }) +} + /// Generate the declaration and implementation for a data struct. /// /// This struct will hold the data for a packet or a struct. It knows /// how to parse and serialize its own fields. fn generate_data_struct( - scope: &analyzer::Scope<'_>, + scope: &lint::Scope<'_>, endianness: ast::EndiannessValue, id: &str, ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) { let decl = scope.typedef[id]; + let packet_scope = &scope.scopes[&decl]; let is_packet = matches!(&decl.desc, ast::DeclDesc::Packet { .. }); 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); - for field in decl.fields() { + for field in packet_scope.iter_fields() { field_parser.add(field); field_serializer.add(field); } field_parser.done(); let (parse_arg_names, parse_arg_types) = if is_packet { - let fields = find_constrained_parent_fields(scope, id); - let names = fields.iter().map(|f| f.id().unwrap().to_ident()).collect::<Vec<_>>(); + let fields = find_constrained_parent_fields(scope, id).collect::<Vec<_>>(); + let names = fields.iter().map(|f| format_ident!("{}", f.id().unwrap())).collect::<Vec<_>>(); let types = fields.iter().map(|f| types::rust_type(f)).collect::<Vec<_>>(); (names, types) } else { @@ -246,7 +248,7 @@ fn generate_data_struct( }; let (constant_width, packet_size) = - generate_packet_size_getter(scope, decl.fields(), is_packet); + generate_packet_size_getter(scope, packet_scope.iter_fields(), is_packet); let conforms = if constant_width == 0 { quote! { true } } else { @@ -255,13 +257,14 @@ fn generate_data_struct( }; let visibility = if is_packet { quote!() } else { quote!(pub) }; - let has_payload = decl.payload().is_some(); - let has_children = scope.iter_children(decl).next().is_some(); + let has_payload = packet_scope.get_payload_field().is_some(); + let has_children = scope.iter_children(id).next().is_some(); - let struct_name = if is_packet { format_ident!("{id}Data") } else { id.to_ident() }; - let fields_with_ids = decl.fields().filter(|f| f.id().is_some()).collect::<Vec<_>>(); + let struct_name = if is_packet { format_ident!("{id}Data") } else { format_ident!("{id}") }; + let fields_with_ids = + packet_scope.iter_fields().filter(|f| f.id().is_some()).collect::<Vec<_>>(); let mut field_names = - fields_with_ids.iter().map(|f| f.id().unwrap().to_ident()).collect::<Vec<_>>(); + fields_with_ids.iter().map(|f| format_ident!("{}", f.id().unwrap())).collect::<Vec<_>>(); let mut field_types = fields_with_ids.iter().map(|f| types::rust_type(f)).collect::<Vec<_>>(); if has_children || has_payload { if is_packet { @@ -323,10 +326,26 @@ fn generate_data_struct( (data_struct_decl, data_struct_impl) } +/// Find all parents from `id`. +/// +/// This includes the `Decl` for `id` itself. +fn find_parents<'a>(scope: &lint::Scope<'a>, id: &str) -> Vec<&'a analyzer_ast::Decl> { + let mut decl = scope.typedef[id]; + let mut parents = vec![decl]; + while let ast::DeclDesc::Packet { parent_id: Some(parent_id), .. } + | ast::DeclDesc::Struct { parent_id: Some(parent_id), .. } = &decl.desc + { + decl = scope.typedef[parent_id]; + parents.push(decl); + } + parents.reverse(); + parents +} + /// Turn the constraint into a value (such as `10` or /// `SomeEnum::Foo`). pub fn constraint_to_value( - all_fields: &HashMap<String, &'_ analyzer_ast::Field>, + packet_scope: &lint::PacketScope<'_>, constraint: &ast::Constraint, ) -> proc_macro2::TokenStream { match constraint { @@ -337,8 +356,8 @@ pub fn constraint_to_value( // TODO(mgeisler): include type_id in `ast::Constraint` and // drop the packet_scope argument. ast::Constraint { tag_id: Some(tag_id), .. } => { - let type_id = match &all_fields[&constraint.id].desc { - ast::FieldDesc::Typedef { type_id, .. } => type_id.to_ident(), + let type_id = match &packet_scope.all_fields[&constraint.id].desc { + ast::FieldDesc::Typedef { type_id, .. } => format_ident!("{type_id}"), _ => unreachable!("Invalid constraint: {constraint:?}"), }; let tag_id = format_ident!("{}", tag_id.to_upper_camel_case()); @@ -350,99 +369,95 @@ pub fn constraint_to_value( /// Generate code for a `ast::Decl::Packet`. fn generate_packet_decl( - scope: &analyzer::Scope<'_>, + scope: &lint::Scope<'_>, endianness: ast::EndiannessValue, id: &str, ) -> proc_macro2::TokenStream { - let decl = scope.typedef[id]; + let packet_scope = &scope.scopes[&scope.typedef[id]]; + let top_level = top_level_packet(scope, id); let top_level_id = top_level.id().unwrap(); - let top_level_packet = top_level_id.to_ident(); + let top_level_packet = format_ident!("{top_level_id}"); let top_level_data = format_ident!("{top_level_id}Data"); - let top_level_id_lower = top_level_id.to_lowercase().to_ident(); + let top_level_id_lower = format_ident!("{}", top_level_id.to_lowercase()); // TODO(mgeisler): use the convert_case crate to convert between // `FooBar` and `foo_bar` in the code below. let span = format_ident!("bytes"); - let id_lower = id.to_lowercase().to_ident(); - let id_packet = id.to_ident(); + let id_lower = format_ident!("{}", id.to_lowercase()); + let id_packet = format_ident!("{id}"); let id_child = format_ident!("{id}Child"); let id_data_child = format_ident!("{id}DataChild"); let id_builder = format_ident!("{id}Builder"); - let mut parents = scope.iter_parents_and_self(decl).collect::<Vec<_>>(); - parents.reverse(); - + let parents = find_parents(scope, id); let parent_ids = parents.iter().map(|p| p.id().unwrap()).collect::<Vec<_>>(); - let parent_shifted_ids = parent_ids.iter().skip(1).map(|id| id.to_ident()); + let parent_shifted_ids = parent_ids.iter().skip(1).map(|id| format_ident!("{id}")); let parent_lower_ids = - parent_ids.iter().map(|id| id.to_lowercase().to_ident()).collect::<Vec<_>>(); + parent_ids.iter().map(|id| format_ident!("{}", id.to_lowercase())).collect::<Vec<_>>(); let parent_shifted_lower_ids = parent_lower_ids.iter().skip(1).collect::<Vec<_>>(); - let parent_packet = parent_ids.iter().map(|id| id.to_ident()); + let parent_packet = parent_ids.iter().map(|id| format_ident!("{id}")); let parent_data = parent_ids.iter().map(|id| format_ident!("{id}Data")); let parent_data_child = parent_ids.iter().map(|id| format_ident!("{id}DataChild")); let all_fields = { - let mut fields = scope.iter_fields(decl).filter(|d| d.id().is_some()).collect::<Vec<_>>(); + let mut fields = packet_scope.all_fields.values().collect::<Vec<_>>(); fields.sort_by_key(|f| f.id()); fields }; - let all_named_fields = - HashMap::from_iter(all_fields.iter().map(|f| (f.id().unwrap().to_string(), *f))); - - let all_field_names = all_fields.iter().map(|f| f.id().unwrap().to_ident()).collect::<Vec<_>>(); + let all_field_names = + all_fields.iter().map(|f| format_ident!("{}", f.id().unwrap())).collect::<Vec<_>>(); let all_field_types = all_fields.iter().map(|f| types::rust_type(f)).collect::<Vec<_>>(); let all_field_borrows = all_fields.iter().map(|f| types::rust_borrow(f, scope)).collect::<Vec<_>>(); - let all_field_getter_names = - all_fields.iter().map(|f| format_ident!("get_{}", f.id().unwrap())); + let all_field_getter_names = all_field_names.iter().map(|id| format_ident!("get_{id}")); let all_field_self_field = all_fields.iter().map(|f| { for (parent, parent_id) in parents.iter().zip(parent_lower_ids.iter()) { - if parent.fields().any(|ff| ff.id() == f.id()) { + if scope.scopes[parent].iter_fields().any(|ff| ff.id() == f.id()) { return quote!(self.#parent_id); } } unreachable!("Could not find {f:?} in parent chain"); }); - let all_constraints = HashMap::<String, _>::from_iter( - scope.iter_constraints(decl).map(|c| (c.id.to_string(), c)), - ); - let unconstrained_fields = all_fields .iter() - .filter(|f| !all_constraints.contains_key(f.id().unwrap())) + .filter(|f| !packet_scope.all_constraints.contains_key(f.id().unwrap())) + .collect::<Vec<_>>(); + let unconstrained_field_names = unconstrained_fields + .iter() + .map(|f| format_ident!("{}", f.id().unwrap())) .collect::<Vec<_>>(); - let unconstrained_field_names = - unconstrained_fields.iter().map(|f| f.id().unwrap().to_ident()).collect::<Vec<_>>(); let unconstrained_field_types = unconstrained_fields.iter().map(|f| types::rust_type(f)); let rev_parents = parents.iter().rev().collect::<Vec<_>>(); let builder_assignments = rev_parents.iter().enumerate().map(|(idx, parent)| { let parent_id = parent.id().unwrap(); - let parent_id_lower = parent_id.to_lowercase().to_ident(); + let parent_id_lower = format_ident!("{}", parent_id.to_lowercase()); let parent_data = format_ident!("{parent_id}Data"); let parent_data_child = format_ident!("{parent_id}DataChild"); + let parent_packet_scope = &scope.scopes[&scope.typedef[parent_id]]; let named_fields = { - let mut names = parent.fields().filter_map(ast::Field::id).collect::<Vec<_>>(); + let mut names = + parent_packet_scope.iter_fields().filter_map(ast::Field::id).collect::<Vec<_>>(); names.sort_unstable(); names }; - let mut field = named_fields.iter().map(|id| id.to_ident()).collect::<Vec<_>>(); + let mut field = named_fields.iter().map(|id| format_ident!("{id}")).collect::<Vec<_>>(); let mut value = named_fields .iter() - .map(|&id| match all_constraints.get(id) { - Some(constraint) => constraint_to_value(&all_named_fields, constraint), + .map(|&id| match packet_scope.all_constraints.get(id) { + Some(constraint) => constraint_to_value(packet_scope, constraint), None => { - let id = id.to_ident(); + let id = format_ident!("{id}"); quote!(self.#id) } }) .collect::<Vec<_>>(); - if parent.payload().is_some() { + if parent_packet_scope.get_payload_field().is_some() { field.push(format_ident!("child")); if idx == 0 { // Top-most parent, the child is simply created from @@ -456,13 +471,13 @@ fn generate_packet_decl( } else { // Child is created from the previous parent. let prev_parent_id = rev_parents[idx - 1].id().unwrap(); - let prev_parent_id_lower = prev_parent_id.to_lowercase().to_ident(); - let prev_parent_id = prev_parent_id.to_ident(); + let prev_parent_id_lower = format_ident!("{}", prev_parent_id.to_lowercase()); + let prev_parent_id = format_ident!("{prev_parent_id}"); value.push(quote! { #parent_data_child::#prev_parent_id(#prev_parent_id_lower) }); } - } else if scope.iter_children(parent).next().is_some() { + } else if scope.iter_children(parent_id).next().is_some() { field.push(format_ident!("child")); value.push(quote! { #parent_data_child::None }); } @@ -474,10 +489,11 @@ fn generate_packet_decl( } }); - let children = scope.iter_children(decl).collect::<Vec<_>>(); - let has_payload = decl.payload().is_some(); + let children = scope.iter_children(id).collect::<Vec<_>>(); + let has_payload = packet_scope.get_payload_field().is_some(); let has_children_or_payload = !children.is_empty() || has_payload; - let child = children.iter().map(|child| child.id().unwrap().to_ident()).collect::<Vec<_>>(); + let child = + children.iter().map(|child| format_ident!("{}", child.id().unwrap())).collect::<Vec<_>>(); let child_data = child.iter().map(|child| format_ident!("{child}Data")).collect::<Vec<_>>(); let get_payload = (children.is_empty() && has_payload).then(|| { quote! { @@ -539,7 +555,8 @@ fn generate_packet_decl( } }); - let ancestor_packets = parent_ids[..parent_ids.len() - 1].iter().map(|id| id.to_ident()); + let ancestor_packets = + parent_ids[..parent_ids.len() - 1].iter().map(|id| format_ident!("{id}")); let impl_from_and_try_from = (top_level_id != id).then(|| { quote! { #( @@ -672,7 +689,7 @@ fn generate_packet_decl( /// Generate code for a `ast::Decl::Struct`. fn generate_struct_decl( - scope: &analyzer::Scope<'_>, + scope: &lint::Scope<'_>, endianness: ast::EndiannessValue, id: &str, ) -> proc_macro2::TokenStream { @@ -693,26 +710,20 @@ fn generate_struct_decl( /// an additional Unknown case for unmatched valued. Complete /// enums (where the full range of values is covered) are /// automatically closed. -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() - } - +fn generate_enum_decl( + id: &str, + tags: &[ast::Tag], + width: usize, + open: bool, +) -> proc_macro2::TokenStream { // 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, + .map(|tag| match tag { + ast::Tag::Value(tag) => (tag.value, tag.value), + ast::Tag::Range(tag) => tag.range.clone().into_inner(), }) .collect::<Vec<_>>(); ranges.sort_unstable(); @@ -727,7 +738,8 @@ fn generate_enum_decl(id: &str, tags: &[ast::Tag], width: usize) -> proc_macro2: }) } - // Determine if the enum is primitive, i.e. does not contain any tag range. + // 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(_))) } @@ -756,15 +768,13 @@ fn generate_enum_decl(id: &str, tags: &[ast::Tag], width: usize) -> proc_macro2: 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(); + let name = format_ident!("{id}"); // 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 use_variant_values = is_primitive && (is_complete || !open); let repr_u64 = use_variant_values.then(|| quote! { #[repr(u64)] }); let mut variants = vec![]; for tag in tags.iter() { @@ -780,7 +790,6 @@ fn generate_enum_decl(id: &str, tags: &[ast::Tag], width: usize) -> proc_macro2: let id = format_tag_ident(&tag.id); variants.push(quote! { #id(Private<#backing_type>) }) } - ast::Tag::Other(_) => (), } } @@ -804,7 +813,6 @@ fn generate_enum_decl(id: &str, tags: &[ast::Tag], width: usize) -> proc_macro2: let end = format_value(*tag.range.end()); from_cases.push(quote! { #start ..= #end => Ok(#name::#id(Private(value))) }) } - ast::Tag::Other(_) => (), } } @@ -826,22 +834,19 @@ fn generate_enum_decl(id: &str, tags: &[ast::Tag], width: usize) -> proc_macro2: 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 }); + if !is_complete && open { + variants.push(quote! { Unknown(Private<#backing_type>) }); + from_cases.push(quote! { 0..#range_max => Ok(#name::Unknown(Private(value))) }); + into_cases.push(quote! { #name::Unknown(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) { + if backing_type.width != width || (!is_complete && !open) { from_cases.push(quote! { _ => Err(value) }); } @@ -902,7 +907,7 @@ fn generate_enum_decl(id: &str, tags: &[ast::Tag], width: usize) -> proc_macro2: /// * `id` - Enum identifier. /// * `width` - Width of the backing type of the enum, in bits. fn generate_custom_field_decl(id: &str, width: usize) -> proc_macro2::TokenStream { - let id = id.to_ident(); + let id = format_ident!("{}", id); 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)); @@ -959,7 +964,7 @@ fn generate_custom_field_decl(id: &str, width: usize) -> proc_macro2::TokenStrea } fn generate_decl( - scope: &analyzer::Scope<'_>, + scope: &lint::Scope<'_>, file: &analyzer_ast::File, decl: &analyzer_ast::Decl, ) -> proc_macro2::TokenStream { @@ -973,7 +978,7 @@ fn generate_decl( // implement the recursive (de)serialization. generate_struct_decl(scope, file.endianness.value, id) } - ast::DeclDesc::Enum { id, tags, width } => generate_enum_decl(id, tags, *width), + ast::DeclDesc::Enum { id, tags, width } => generate_enum_decl(id, tags, *width, false), ast::DeclDesc::CustomField { id, width: Some(width), .. } => { generate_custom_field_decl(id, *width) } @@ -989,7 +994,7 @@ pub fn generate(sources: &ast::SourceDatabase, file: &analyzer_ast::File) -> Str 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 scope = lint::Scope::new(file); let decls = file.declarations.iter().map(|decl| generate_decl(&scope, file, decl)); let code = quote! { #preamble @@ -1045,10 +1050,9 @@ mod tests { } "; let file = parse_str(code); - let scope = analyzer::Scope::new(&file).unwrap(); + let scope = lint::Scope::new(&file); let find_fields = |id| { find_constrained_parent_fields(&scope, id) - .iter() .map(|field| field.id().unwrap()) .collect::<Vec<_>>() }; @@ -1116,18 +1120,14 @@ mod tests { test_pdl!( enum_declaration, r#" - enum IncompleteTruncatedClosed : 3 { - A = 0, - B = 1, - } - - enum IncompleteTruncatedOpen : 3 { + // Should generate unknown case. + enum IncompleteTruncated : 3 { A = 0, B = 1, - UNKNOWN = .. } - enum IncompleteTruncatedClosedWithRange : 3 { + // Should generate unknown case. + enum IncompleteTruncatedWithRange : 3 { A = 0, B = 1..6 { X = 1, @@ -1135,15 +1135,7 @@ mod tests { } } - enum IncompleteTruncatedOpenWithRange : 3 { - A = 0, - B = 1..6 { - X = 1, - Y = 2, - }, - UNKNOWN = .. - } - + // Should generate unreachable case. enum CompleteTruncated : 3 { A = 0, B = 1, @@ -1155,6 +1147,7 @@ mod tests { H = 7, } + // Should generate unreachable case. enum CompleteTruncatedWithRange : 3 { A = 0, B = 1..7 { @@ -1163,6 +1156,7 @@ mod tests { } } + // Should generate no unknown or unreachable case. enum CompleteWithRange : 8 { A = 0, B = 1, @@ -1528,15 +1522,6 @@ mod tests { " ); - test_pdl!( - reserved_identifier, - " - packet Test { - type: 8, - } - " - ); - // TODO(mgeisler): enable this test when we have an approach to // struct fields with parents. // diff --git a/src/backends/rust/parser.rs b/src/backends/rust/parser.rs index f837082..203a19b 100644 --- a/src/backends/rust/parser.rs +++ b/src/backends/rust/parser.rs @@ -14,12 +14,11 @@ use crate::analyzer::ast as analyzer_ast; use crate::backends::rust::{ - constraint_to_value, find_constrained_parent_fields, mask_bits, types, ToIdent, - ToUpperCamelCase, + constraint_to_value, find_constrained_parent_fields, mask_bits, types, ToUpperCamelCase, }; -use crate::{analyzer, ast}; +use crate::{ast, lint}; use quote::{format_ident, quote}; -use std::collections::{BTreeSet, HashMap}; +use std::collections::BTreeSet; fn size_field_ident(id: &str) -> proc_macro2::Ident { format_ident!("{}_size", id.trim_matches('_')) @@ -32,9 +31,8 @@ struct BitField<'a> { } pub struct FieldParser<'a> { - scope: &'a analyzer::Scope<'a>, + scope: &'a lint::Scope<'a>, endianness: ast::EndiannessValue, - decl: &'a analyzer_ast::Decl, packet_name: &'a str, span: &'a proc_macro2::Ident, chunk: Vec<BitField<'a>>, @@ -45,7 +43,7 @@ pub struct FieldParser<'a> { impl<'a> FieldParser<'a> { pub fn new( - scope: &'a analyzer::Scope<'a>, + scope: &'a lint::Scope<'a>, endianness: ast::EndiannessValue, packet_name: &'a str, span: &'a proc_macro2::Ident, @@ -53,7 +51,6 @@ impl<'a> FieldParser<'a> { FieldParser { scope, endianness, - decl: scope.typedef[packet_name], packet_name, span, chunk: Vec::new(), @@ -73,7 +70,7 @@ impl<'a> FieldParser<'a> { type_id.as_deref(), *size, field.annot.padded_size, - self.scope.get_type_declaration(field), + self.scope.get_field_declaration(field), ), ast::FieldDesc::Typedef { id, type_id } => self.add_typedef_field(id, type_id), ast::FieldDesc::Payload { size_modifier, .. } => { @@ -142,20 +139,19 @@ impl<'a> FieldParser<'a> { self.code.push(match &field.desc { ast::FieldDesc::Scalar { id, .. } => { - let id = id.to_ident(); + let id = format_ident!("{id}"); 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(); + let enum_id = format_ident!("{enum_id}"); + let tag_id = format_ident!("{}", tag_id.to_upper_camel_case()); quote! { - let fixed_value = #v; - if fixed_value != #value_type::from(#enum_id::#tag_id) { + if #v != #value_type::from(#enum_id::#tag_id) { return Err(Error::InvalidFixedValue { expected: #value_type::from(#enum_id::#tag_id) as u64, - actual: fixed_value as u64, + actual: #v as u64, }); } } @@ -163,11 +159,10 @@ impl<'a> FieldParser<'a> { ast::FieldDesc::FixedScalar { value, .. } => { let value = proc_macro2::Literal::usize_unsuffixed(*value); quote! { - let fixed_value = #v; if #v != #value { return Err(Error::InvalidFixedValue { expected: #value, - actual: fixed_value as u64, + actual: #v as u64, }); } } @@ -176,13 +171,13 @@ impl<'a> FieldParser<'a> { 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(); + let id = format_ident!("{id}"); + let type_id = format_ident!("{type_id}"); quote! { - let #id = #type_id::try_from(#v).map_err(|unknown_val| Error::InvalidEnumValueError { + let #id = #type_id::try_from(#v).map_err(|_| Error::InvalidEnumValueError { obj: #packet_name.to_string(), field: #field_name.to_string(), - value: unknown_val as u64, + value: #v as u64, type_: #type_name.to_string(), })?; } @@ -221,23 +216,27 @@ impl<'a> FieldParser<'a> { self.shift = 0; } + fn packet_scope(&self) -> Option<&lint::PacketScope> { + self.scope.scopes.get(self.scope.typedef.get(self.packet_name)?) + } + fn find_count_field(&self, id: &str) -> Option<proc_macro2::Ident> { - match self.decl.array_size(id)?.desc { + match self.packet_scope()?.get_array_size_field(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 { + match self.packet_scope()?.get_array_size_field(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(); + let packet_scope = self.packet_scope().unwrap(); + let mut fields = packet_scope.iter_fields(); fields.find(|f| { matches!(f.desc, ast::FieldDesc::Body { .. } | ast::FieldDesc::Payload { .. }) })?; @@ -328,7 +327,7 @@ impl<'a> FieldParser<'a> { None => self.span.clone(), }; - let id = id.to_ident(); + let id = format_ident!("{id}"); let parse_element = self.parse_array_element(&span, width, type_id, decl); match (element_width, &array_shape) { @@ -469,8 +468,8 @@ impl<'a> FieldParser<'a> { } let span = self.span; - let id = id.to_ident(); - let type_id = type_id.to_ident(); + let id = format_ident!("{id}"); + let type_id = format_ident!("{type_id}"); self.code.push(match decl.annot.size { analyzer_ast::Size::Unknown | analyzer_ast::Size::Dynamic => quote! { @@ -511,7 +510,8 @@ impl<'a> FieldParser<'a> { /// 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 packet_scope = self.packet_scope().unwrap(); + let payload_size_field = packet_scope.get_payload_size_field(); let offset_from_end = self.payload_field_offset_from_end(); if size_modifier.is_some() { @@ -597,19 +597,19 @@ impl<'a> FieldParser<'a> { 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 type_id = format_ident!("{id}"); let packet_name = &self.packet_name; return quote! { - #type_id::try_from(#get_uint).map_err(|unknown_val| Error::InvalidEnumValueError { + #type_id::try_from(#get_uint).map_err(|_| Error::InvalidEnumValueError { obj: #packet_name.to_string(), field: String::new(), // TODO(mgeisler): fill out or remove - value: unknown_val as u64, + value: 0, type_: #id.to_string(), }) }; } - let type_id = type_id.unwrap().to_ident(); + let type_id = format_ident!("{}", type_id.unwrap()); quote! { #type_id::parse_inner(#span) } @@ -621,15 +621,12 @@ impl<'a> FieldParser<'a> { 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() { + let packet_scope = &self.scope.scopes[&decl]; + let children = self.scope.iter_children(self.packet_name).collect::<Vec<_>>(); + if children.is_empty() && packet_scope.get_payload_field().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. @@ -642,11 +639,10 @@ impl<'a> FieldParser<'a> { 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)) + constraints.find(|c| c.id == id).map(|c| constraint_to_value(packet_scope, c)) }; for child in children.iter() { @@ -677,17 +673,16 @@ impl<'a> FieldParser<'a> { .collect::<Vec<_>>(); let fields = find_constrained_parent_fields(self.scope, child.id().unwrap()) - .iter() - .map(|field| field.id().unwrap().to_ident()) - .collect::<Vec<_>>(); + .map(|field| format_ident!("{}", field.id().unwrap())); 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()); + child_ids.push(format_ident!("{}", child.id().unwrap())); } - let constrained_field_idents = constrained_fields.iter().map(|field| field.to_ident()); + let constrained_field_idents = + constrained_fields.iter().map(|field| format_ident!("{field}")); let packet_data_child = format_ident!("{}DataChild", self.packet_name); // Parsing of packet children requires having a payload field; @@ -755,7 +750,7 @@ mod tests { } "; let file = parse_str(code); - let scope = analyzer::Scope::new(&file).unwrap(); + let scope = lint::Scope::new(&file); let span = format_ident!("bytes"); let parser = FieldParser::new(&scope, file.endianness.value, "P", &span); assert_eq!(parser.find_size_field("a"), None); @@ -772,7 +767,7 @@ mod tests { } "; let file = parse_str(code); - let scope = analyzer::Scope::new(&file).unwrap(); + let scope = lint::Scope::new(&file); let span = format_ident!("bytes"); let parser = FieldParser::new(&scope, file.endianness.value, "P", &span); assert_eq!(parser.find_size_field("b"), None); @@ -789,7 +784,7 @@ mod tests { } "; let file = parse_str(code); - let scope = analyzer::Scope::new(&file).unwrap(); + let scope = lint::Scope::new(&file); let span = format_ident!("bytes"); let parser = FieldParser::new(&scope, file.endianness.value, "P", &span); assert_eq!(parser.find_size_field("c"), Some(format_ident!("c_size"))); diff --git a/src/backends/rust/serializer.rs b/src/backends/rust/serializer.rs index 345e98a..497936c 100644 --- a/src/backends/rust/serializer.rs +++ b/src/backends/rust/serializer.rs @@ -13,8 +13,8 @@ // 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 crate::backends::rust::{mask_bits, types, ToUpperCamelCase}; +use crate::{ast, lint}; use quote::{format_ident, quote}; /// A single bit-field value. @@ -25,7 +25,7 @@ struct BitField { } pub struct FieldSerializer<'a> { - scope: &'a analyzer::Scope<'a>, + scope: &'a lint::Scope<'a>, endianness: ast::EndiannessValue, packet_name: &'a str, span: &'a proc_macro2::Ident, @@ -36,7 +36,7 @@ pub struct FieldSerializer<'a> { impl<'a> FieldSerializer<'a> { pub fn new( - scope: &'a analyzer::Scope<'a>, + scope: &'a lint::Scope<'a>, endianness: ast::EndiannessValue, packet_name: &'a str, span: &'a proc_macro2::Ident, @@ -59,7 +59,7 @@ impl<'a> FieldSerializer<'a> { id, *width, field.annot.padded_size, - self.scope.get_type_declaration(field), + self.scope.get_field_declaration(field), ), ast::FieldDesc::Typedef { id, type_id } => { self.add_typedef_field(id, type_id); @@ -79,7 +79,7 @@ impl<'a> FieldSerializer<'a> { match &field.desc { ast::FieldDesc::Scalar { id, width } => { - let field_name = id.to_ident(); + let field_name = format_ident!("{id}"); let field_type = types::Integer::new(*width); if field_type.width > *width { let packet_name = &self.packet_name; @@ -97,7 +97,7 @@ impl<'a> FieldSerializer<'a> { } ast::FieldDesc::FixedEnum { enum_id, tag_id, .. } => { let field_type = types::Integer::new(width); - let enum_id = enum_id.to_ident(); + let enum_id = format_ident!("{enum_id}"); let tag_id = format_ident!("{}", tag_id.to_upper_camel_case()); self.chunk.push(BitField { value: quote!(#field_type::from(#enum_id::#tag_id)), @@ -111,7 +111,7 @@ impl<'a> FieldSerializer<'a> { self.chunk.push(BitField { value: quote!(#value), field_type, shift }); } ast::FieldDesc::Typedef { id, .. } => { - let field_name = id.to_ident(); + let field_name = format_ident!("{id}"); let field_type = types::Integer::new(width); self.chunk.push(BitField { value: quote!(#field_type::from(self.#field_name)), @@ -127,21 +127,14 @@ impl<'a> FieldSerializer<'a> { 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 scope = self.scope.scopes.get(decl).unwrap(); + let value_field = scope.get_packet_field(field_id).unwrap(); - let field_name = field_id.to_ident(); + let field_name = format_ident!("{field_id}"); let field_type = types::Integer::new(*width); // TODO: size modifier - let value_field_decl = self.scope.get_type_declaration(value_field); + let value_field_decl = self.scope.get_field_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)) @@ -190,7 +183,7 @@ impl<'a> FieldSerializer<'a> { }); } ast::FieldDesc::Count { field_id, width, .. } => { - let field_name = field_id.to_ident(); + let field_name = format_ident!("{field_id}"); let field_type = types::Integer::new(*width); if field_type.width > *width { let packet_name = &self.packet_name; @@ -296,7 +289,7 @@ impl<'a> FieldSerializer<'a> { } }; - let id = id.to_ident(); + let id = format_ident!("{id}"); self.code.push(match padding_size { Some(padding_size) => @@ -327,7 +320,7 @@ impl<'a> FieldSerializer<'a> { panic!("Derived struct used in typedef field"); } - let id = id.to_ident(); + let id = format_ident!("{id}"); let span = format_ident!("{}", self.span); self.code.push(match &decl.desc { @@ -361,8 +354,8 @@ impl<'a> FieldSerializer<'a> { let child_ids = self .scope - .iter_children(decl) - .map(|child| child.id().unwrap().to_ident()) + .iter_children(self.packet_name) + .map(|child| format_ident!("{}", child.id().unwrap())) .collect::<Vec<_>>(); let span = format_ident!("{}", self.span); diff --git a/src/backends/rust/types.rs b/src/backends/rust/types.rs index b5f2b91..5b1767d 100644 --- a/src/backends/rust/types.rs +++ b/src/backends/rust/types.rs @@ -15,8 +15,7 @@ //! Utility functions for dealing with Rust integer types. use crate::analyzer::ast as analyzer_ast; -use crate::backends::rust::ToIdent; -use crate::{analyzer, ast}; +use crate::{ast, lint}; use quote::{format_ident, quote}; /// A Rust integer type such as `u8`. @@ -56,7 +55,7 @@ pub fn rust_type(field: &analyzer_ast::Field) -> proc_macro2::TokenStream { quote!(#field_type) } ast::FieldDesc::Typedef { type_id, .. } => { - let field_type = type_id.to_ident(); + let field_type = format_ident!("{type_id}"); quote!(#field_type) } ast::FieldDesc::Array { width: Some(width), size: Some(size), .. } => { @@ -69,12 +68,12 @@ pub fn rust_type(field: &analyzer_ast::Field) -> proc_macro2::TokenStream { quote!(Vec<#field_type>) } ast::FieldDesc::Array { type_id: Some(type_id), size: Some(size), .. } => { - let field_type = type_id.to_ident(); + let field_type = format_ident!("{type_id}"); 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(); + let field_type = format_ident!("{type_id}"); quote!(Vec<#field_type>) } //ast::Field::Size { .. } | ast::Field::Count { .. } => quote!(), @@ -84,7 +83,7 @@ pub fn rust_type(field: &analyzer_ast::Field) -> proc_macro2::TokenStream { pub fn rust_borrow( field: &analyzer_ast::Field, - scope: &analyzer::Scope<'_>, + scope: &lint::Scope<'_>, ) -> proc_macro2::TokenStream { match &field.desc { ast::FieldDesc::Scalar { .. } => quote!(), @@ -17,6 +17,7 @@ pub mod analyzer; pub mod ast; pub mod backends; +pub mod lint; pub mod parser; #[cfg(test)] pub mod test_utils; diff --git a/src/lint.rs b/src/lint.rs new file mode 100644 index 0000000..421f364 --- /dev/null +++ b/src/lint.rs @@ -0,0 +1,259 @@ +// 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 std::collections::HashMap; + +use crate::analyzer::ast as analyzer_ast; +use crate::ast::*; + +/// Gather information about the full AST. +#[derive(Debug)] +pub struct Scope<'d> { + // Original file. + pub file: &'d analyzer_ast::File, + + // Collection of Group, Packet, Enum, Struct, Checksum, and CustomField declarations. + pub typedef: HashMap<String, &'d analyzer_ast::Decl>, + + // Collection of Packet, Struct, and Group scope declarations. + pub scopes: HashMap<&'d analyzer_ast::Decl, PacketScope<'d>>, +} + +/// Gather information about a Packet, Struct, or Group declaration. +#[derive(Debug)] +pub struct PacketScope<'d> { + // Original decl. + decl: &'d analyzer_ast::Decl, + + // Local and inherited field declarations. Only named fields are preserved. + // Saved here for reference for parent constraint resolving. + pub all_fields: HashMap<String, &'d analyzer_ast::Field>, + + // Local and inherited constraint declarations. + // Saved here for constraint conflict checks. + pub all_constraints: HashMap<String, &'d Constraint>, +} + +impl<'d> std::hash::Hash for &'d analyzer_ast::Decl { + fn hash<H: std::hash::Hasher>(&self, state: &mut H) { + std::ptr::hash(*self, state); + } +} + +impl<'d> PacketScope<'d> { + /// Add parent fields and constraints to the scope. + /// Only named fields are imported. + fn inherit( + &mut self, + parent: &PacketScope<'d>, + constraints: impl Iterator<Item = &'d Constraint>, + ) { + // Check constraints. + assert!(self.all_constraints.is_empty()); + self.all_constraints = parent.all_constraints.clone(); + for constraint in constraints { + let id = constraint.id.clone(); + self.all_constraints.insert(id, constraint); + } + + // Save parent fields. + self.all_fields = parent.all_fields.clone(); + } + + /// Iterate over the packet's fields. + pub fn iter_fields(&self) -> impl Iterator<Item = &'d analyzer_ast::Field> { + self.decl.fields() + } + + /// Lookup a field by name. This will also find the special + /// `_payload_` and `_body_` fields. + pub fn get_packet_field(&self, id: &str) -> Option<&analyzer_ast::Field> { + self.decl.fields().find(|field| match &field.desc { + FieldDesc::Payload { .. } => id == "_payload_", + FieldDesc::Body { .. } => id == "_body_", + _ => field.id() == Some(id), + }) + } + + /// Find the payload or body field, if any. + pub fn get_payload_field(&self) -> Option<&analyzer_ast::Field> { + self.decl + .fields() + .find(|field| matches!(&field.desc, FieldDesc::Payload { .. } | FieldDesc::Body { .. })) + } + + /// Lookup the size field for an array field. + pub fn get_array_size_field(&self, id: &str) -> Option<&analyzer_ast::Field> { + self.decl.fields().find(|field| match &field.desc { + FieldDesc::Size { field_id, .. } | FieldDesc::Count { field_id, .. } => field_id == id, + _ => false, + }) + } + + /// Find the size field corresponding to the payload or body + /// field of this packet. + pub fn get_payload_size_field(&self) -> Option<&analyzer_ast::Field> { + self.decl.fields().find(|field| match &field.desc { + FieldDesc::Size { field_id, .. } => field_id == "_payload_" || field_id == "_body_", + _ => false, + }) + } + + /// Cleanup scope after processing all fields. + fn finalize(&mut self) { + // Check field shadowing. + for f in self.decl.fields() { + if let Some(id) = f.id() { + self.all_fields.insert(id.to_string(), f); + } + } + } +} + +impl<'d> Scope<'d> { + pub fn new(file: &analyzer_ast::File) -> Scope<'_> { + let mut scope = Scope { file, typedef: HashMap::new(), scopes: HashMap::new() }; + + // Gather top-level declarations. + // Validate the top-level scopes (Group, Packet, Typedef). + // + // TODO: switch to try_insert when stable + for decl in &file.declarations { + if let Some(id) = decl.id() { + scope.typedef.insert(id.to_string(), decl); + } + } + + scope.finalize(); + scope + } + + // Sort Packet, Struct, and Group declarations by reverse topological + // order. + fn finalize(&mut self) -> Vec<&'d analyzer_ast::Decl> { + // Auxiliary function implementing BFS on Packet tree. + enum Mark { + Temporary, + Permanent, + } + struct Context<'d> { + list: Vec<&'d analyzer_ast::Decl>, + visited: HashMap<&'d analyzer_ast::Decl, Mark>, + scopes: HashMap<&'d analyzer_ast::Decl, PacketScope<'d>>, + } + + fn bfs<'s, 'd>( + decl: &'d analyzer_ast::Decl, + context: &'s mut Context<'d>, + scope: &Scope<'d>, + ) -> Option<&'s PacketScope<'d>> { + match context.visited.get(&decl) { + Some(Mark::Permanent) => return context.scopes.get(&decl), + Some(Mark::Temporary) => { + return None; + } + _ => (), + } + + let (parent_id, fields) = match &decl.desc { + DeclDesc::Packet { parent_id, fields, .. } + | DeclDesc::Struct { parent_id, fields, .. } => (parent_id.as_ref(), fields), + DeclDesc::Group { fields, .. } => (None, fields), + _ => return None, + }; + + context.visited.insert(decl, Mark::Temporary); + let mut lscope = + PacketScope { decl, all_fields: HashMap::new(), all_constraints: HashMap::new() }; + + // Iterate over Struct and Group fields. + for f in fields { + match &f.desc { + FieldDesc::Group { .. } => unreachable!(), + FieldDesc::Typedef { type_id, .. } => match scope.typedef.get(type_id) { + Some(struct_decl @ Decl { desc: DeclDesc::Struct { .. }, .. }) => { + bfs(struct_decl, context, scope); + } + None | Some(_) => (), + }, + _ => (), + } + } + + // Iterate over parent declaration. + let parent = parent_id.and_then(|id| scope.typedef.get(id)); + if let Some(parent_decl) = parent { + if let Some(rscope) = bfs(parent_decl, context, scope) { + // Import the parent fields and constraints into the current scope. + lscope.inherit(rscope, decl.constraints()) + } + } + + lscope.finalize(); + context.list.push(decl); + context.visited.insert(decl, Mark::Permanent); + context.scopes.insert(decl, lscope); + context.scopes.get(&decl) + } + + let mut context = + Context::<'d> { list: vec![], visited: HashMap::new(), scopes: HashMap::new() }; + + for decl in self.typedef.values() { + bfs(decl, &mut context, self); + } + + self.scopes = context.scopes; + context.list + } + + pub fn iter_children<'a>( + &'a self, + id: &'a str, + ) -> impl Iterator<Item = &'d analyzer_ast::Decl> + 'a { + self.file.iter_children(self.typedef.get(id).unwrap()) + } + + /// Return the declaration of the typedef type backing the + /// selected field. + pub fn get_field_declaration( + &self, + field: &analyzer_ast::Field, + ) -> Option<&'d analyzer_ast::Decl> { + match &field.desc { + FieldDesc::FixedEnum { enum_id, .. } => self.typedef.get(enum_id).copied(), + FieldDesc::Array { type_id: Some(type_id), .. } => self.typedef.get(type_id).copied(), + FieldDesc::Typedef { type_id, .. } => self.typedef.get(type_id.as_str()).copied(), + _ => None, + } + } + + /// Test if the selected field is a bitfield. + pub fn is_bitfield(&self, field: &analyzer_ast::Field) -> bool { + match &field.desc { + FieldDesc::Size { .. } + | FieldDesc::Count { .. } + | FieldDesc::ElementSize { .. } + | FieldDesc::FixedScalar { .. } + | FieldDesc::FixedEnum { .. } + | FieldDesc::Reserved { .. } + | FieldDesc::Scalar { .. } => true, + FieldDesc::Typedef { type_id, .. } => { + let field = self.typedef.get(type_id.as_str()); + matches!(field, Some(Decl { desc: DeclDesc::Enum { .. }, .. })) + } + _ => false, + } + } +} diff --git a/src/parser.rs b/src/parser.rs index f9d2ffa..6d19648 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -69,8 +69,7 @@ enum_range = { enum_value_list ~ "}")? } -enum_other = { identifier ~ "=" ~ ".." } -enum_tag = { enum_range | enum_value | enum_other } +enum_tag = { enum_range | enum_value } enum_tag_list = { enum_tag ~ ("," ~ enum_tag)* ~ ","? } enum_declaration = { "enum" ~ identifier ~ ":" ~ integer ~ "{" ~ @@ -351,17 +350,6 @@ fn parse_enum_range(node: Node<'_>, context: &Context) -> Result<crate::ast::Tag } } -fn parse_enum_other(node: Node<'_>, context: &Context) -> Result<crate::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 }) - } -} - fn parse_enum_tag(node: Node<'_>, context: &Context) -> Result<crate::ast::Tag, String> { if node.as_rule() != Rule::enum_tag { err_unexpected_rule(Rule::enum_tag, node.as_rule()) @@ -373,9 +361,6 @@ fn parse_enum_tag(node: Node<'_>, context: &Context) -> Result<crate::ast::Tag, Some(node) if node.as_rule() == Rule::enum_range => { Ok(crate::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)?)) - } Some(node) => Err(format!( "expected rule {:?} or {:?}, got {:?}", Rule::enum_value, diff --git a/tests/generated/enum_declaration_big_endian.rs b/tests/generated/enum_declaration_big_endian.rs index ffc4725..badb3f0 100644 --- a/tests/generated/enum_declaration_big_endian.rs +++ b/tests/generated/enum_declaration_big_endian.rs @@ -47,278 +47,136 @@ pub trait Packet { #[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 { +pub enum IncompleteTruncated { A = 0x0, B = 0x1, } -impl TryFrom<u8> for IncompleteTruncatedClosed { +impl TryFrom<u8> for IncompleteTruncated { type Error = u8; fn try_from(value: u8) -> std::result::Result<Self, Self::Error> { match value { - 0x0 => Ok(IncompleteTruncatedClosed::A), - 0x1 => Ok(IncompleteTruncatedClosed::B), + 0x0 => Ok(IncompleteTruncated::A), + 0x1 => Ok(IncompleteTruncated::B), _ => Err(value), } } } -impl From<&IncompleteTruncatedClosed> for u8 { - fn from(value: &IncompleteTruncatedClosed) -> Self { +impl From<&IncompleteTruncated> for u8 { + fn from(value: &IncompleteTruncated) -> Self { match value { - IncompleteTruncatedClosed::A => 0x0, - IncompleteTruncatedClosed::B => 0x1, + IncompleteTruncated::A => 0x0, + IncompleteTruncated::B => 0x1, } } } -impl From<IncompleteTruncatedClosed> for u8 { - fn from(value: IncompleteTruncatedClosed) -> Self { +impl From<IncompleteTruncated> for u8 { + fn from(value: IncompleteTruncated) -> Self { (&value).into() } } -impl From<IncompleteTruncatedClosed> for i8 { - fn from(value: IncompleteTruncatedClosed) -> Self { +impl From<IncompleteTruncated> for i8 { + fn from(value: IncompleteTruncated) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedClosed> for i16 { - fn from(value: IncompleteTruncatedClosed) -> Self { +impl From<IncompleteTruncated> for i16 { + fn from(value: IncompleteTruncated) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedClosed> for i32 { - fn from(value: IncompleteTruncatedClosed) -> Self { +impl From<IncompleteTruncated> for i32 { + fn from(value: IncompleteTruncated) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedClosed> for i64 { - fn from(value: IncompleteTruncatedClosed) -> Self { +impl From<IncompleteTruncated> for i64 { + fn from(value: IncompleteTruncated) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedClosed> for u16 { - fn from(value: IncompleteTruncatedClosed) -> Self { +impl From<IncompleteTruncated> for u16 { + fn from(value: IncompleteTruncated) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedClosed> for u32 { - fn from(value: IncompleteTruncatedClosed) -> Self { +impl From<IncompleteTruncated> for u32 { + fn from(value: IncompleteTruncated) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedClosed> for u64 { - fn from(value: IncompleteTruncatedClosed) -> Self { +impl From<IncompleteTruncated> for u64 { + fn from(value: IncompleteTruncated) -> 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 { +pub enum IncompleteTruncatedWithRange { A, X, Y, B(Private<u8>), - Unknown(Private<u8>), } -impl TryFrom<u8> for IncompleteTruncatedOpenWithRange { +impl TryFrom<u8> for IncompleteTruncatedWithRange { 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))), + 0x0 => Ok(IncompleteTruncatedWithRange::A), + 0x1 => Ok(IncompleteTruncatedWithRange::X), + 0x2 => Ok(IncompleteTruncatedWithRange::Y), + 0x1..=0x6 => Ok(IncompleteTruncatedWithRange::B(Private(value))), _ => Err(value), } } } -impl From<&IncompleteTruncatedOpenWithRange> for u8 { - fn from(value: &IncompleteTruncatedOpenWithRange) -> Self { +impl From<&IncompleteTruncatedWithRange> for u8 { + fn from(value: &IncompleteTruncatedWithRange) -> Self { match value { - IncompleteTruncatedOpenWithRange::A => 0x0, - IncompleteTruncatedOpenWithRange::X => 0x1, - IncompleteTruncatedOpenWithRange::Y => 0x2, - IncompleteTruncatedOpenWithRange::B(Private(value)) => *value, - IncompleteTruncatedOpenWithRange::Unknown(Private(value)) => *value, + IncompleteTruncatedWithRange::A => 0x0, + IncompleteTruncatedWithRange::X => 0x1, + IncompleteTruncatedWithRange::Y => 0x2, + IncompleteTruncatedWithRange::B(Private(value)) => *value, } } } -impl From<IncompleteTruncatedOpenWithRange> for u8 { - fn from(value: IncompleteTruncatedOpenWithRange) -> Self { +impl From<IncompleteTruncatedWithRange> for u8 { + fn from(value: IncompleteTruncatedWithRange) -> Self { (&value).into() } } -impl From<IncompleteTruncatedOpenWithRange> for i8 { - fn from(value: IncompleteTruncatedOpenWithRange) -> Self { +impl From<IncompleteTruncatedWithRange> for i8 { + fn from(value: IncompleteTruncatedWithRange) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedOpenWithRange> for i16 { - fn from(value: IncompleteTruncatedOpenWithRange) -> Self { +impl From<IncompleteTruncatedWithRange> for i16 { + fn from(value: IncompleteTruncatedWithRange) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedOpenWithRange> for i32 { - fn from(value: IncompleteTruncatedOpenWithRange) -> Self { +impl From<IncompleteTruncatedWithRange> for i32 { + fn from(value: IncompleteTruncatedWithRange) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedOpenWithRange> for i64 { - fn from(value: IncompleteTruncatedOpenWithRange) -> Self { +impl From<IncompleteTruncatedWithRange> for i64 { + fn from(value: IncompleteTruncatedWithRange) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedOpenWithRange> for u16 { - fn from(value: IncompleteTruncatedOpenWithRange) -> Self { +impl From<IncompleteTruncatedWithRange> for u16 { + fn from(value: IncompleteTruncatedWithRange) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedOpenWithRange> for u32 { - fn from(value: IncompleteTruncatedOpenWithRange) -> Self { +impl From<IncompleteTruncatedWithRange> for u32 { + fn from(value: IncompleteTruncatedWithRange) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedOpenWithRange> for u64 { - fn from(value: IncompleteTruncatedOpenWithRange) -> Self { +impl From<IncompleteTruncatedWithRange> for u64 { + fn from(value: IncompleteTruncatedWithRange) -> Self { u8::from(value) as Self } } diff --git a/tests/generated/enum_declaration_little_endian.rs b/tests/generated/enum_declaration_little_endian.rs index ffc4725..badb3f0 100644 --- a/tests/generated/enum_declaration_little_endian.rs +++ b/tests/generated/enum_declaration_little_endian.rs @@ -47,278 +47,136 @@ pub trait Packet { #[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 { +pub enum IncompleteTruncated { A = 0x0, B = 0x1, } -impl TryFrom<u8> for IncompleteTruncatedClosed { +impl TryFrom<u8> for IncompleteTruncated { type Error = u8; fn try_from(value: u8) -> std::result::Result<Self, Self::Error> { match value { - 0x0 => Ok(IncompleteTruncatedClosed::A), - 0x1 => Ok(IncompleteTruncatedClosed::B), + 0x0 => Ok(IncompleteTruncated::A), + 0x1 => Ok(IncompleteTruncated::B), _ => Err(value), } } } -impl From<&IncompleteTruncatedClosed> for u8 { - fn from(value: &IncompleteTruncatedClosed) -> Self { +impl From<&IncompleteTruncated> for u8 { + fn from(value: &IncompleteTruncated) -> Self { match value { - IncompleteTruncatedClosed::A => 0x0, - IncompleteTruncatedClosed::B => 0x1, + IncompleteTruncated::A => 0x0, + IncompleteTruncated::B => 0x1, } } } -impl From<IncompleteTruncatedClosed> for u8 { - fn from(value: IncompleteTruncatedClosed) -> Self { +impl From<IncompleteTruncated> for u8 { + fn from(value: IncompleteTruncated) -> Self { (&value).into() } } -impl From<IncompleteTruncatedClosed> for i8 { - fn from(value: IncompleteTruncatedClosed) -> Self { +impl From<IncompleteTruncated> for i8 { + fn from(value: IncompleteTruncated) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedClosed> for i16 { - fn from(value: IncompleteTruncatedClosed) -> Self { +impl From<IncompleteTruncated> for i16 { + fn from(value: IncompleteTruncated) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedClosed> for i32 { - fn from(value: IncompleteTruncatedClosed) -> Self { +impl From<IncompleteTruncated> for i32 { + fn from(value: IncompleteTruncated) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedClosed> for i64 { - fn from(value: IncompleteTruncatedClosed) -> Self { +impl From<IncompleteTruncated> for i64 { + fn from(value: IncompleteTruncated) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedClosed> for u16 { - fn from(value: IncompleteTruncatedClosed) -> Self { +impl From<IncompleteTruncated> for u16 { + fn from(value: IncompleteTruncated) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedClosed> for u32 { - fn from(value: IncompleteTruncatedClosed) -> Self { +impl From<IncompleteTruncated> for u32 { + fn from(value: IncompleteTruncated) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedClosed> for u64 { - fn from(value: IncompleteTruncatedClosed) -> Self { +impl From<IncompleteTruncated> for u64 { + fn from(value: IncompleteTruncated) -> 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 { +pub enum IncompleteTruncatedWithRange { A, X, Y, B(Private<u8>), - Unknown(Private<u8>), } -impl TryFrom<u8> for IncompleteTruncatedOpenWithRange { +impl TryFrom<u8> for IncompleteTruncatedWithRange { 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))), + 0x0 => Ok(IncompleteTruncatedWithRange::A), + 0x1 => Ok(IncompleteTruncatedWithRange::X), + 0x2 => Ok(IncompleteTruncatedWithRange::Y), + 0x1..=0x6 => Ok(IncompleteTruncatedWithRange::B(Private(value))), _ => Err(value), } } } -impl From<&IncompleteTruncatedOpenWithRange> for u8 { - fn from(value: &IncompleteTruncatedOpenWithRange) -> Self { +impl From<&IncompleteTruncatedWithRange> for u8 { + fn from(value: &IncompleteTruncatedWithRange) -> Self { match value { - IncompleteTruncatedOpenWithRange::A => 0x0, - IncompleteTruncatedOpenWithRange::X => 0x1, - IncompleteTruncatedOpenWithRange::Y => 0x2, - IncompleteTruncatedOpenWithRange::B(Private(value)) => *value, - IncompleteTruncatedOpenWithRange::Unknown(Private(value)) => *value, + IncompleteTruncatedWithRange::A => 0x0, + IncompleteTruncatedWithRange::X => 0x1, + IncompleteTruncatedWithRange::Y => 0x2, + IncompleteTruncatedWithRange::B(Private(value)) => *value, } } } -impl From<IncompleteTruncatedOpenWithRange> for u8 { - fn from(value: IncompleteTruncatedOpenWithRange) -> Self { +impl From<IncompleteTruncatedWithRange> for u8 { + fn from(value: IncompleteTruncatedWithRange) -> Self { (&value).into() } } -impl From<IncompleteTruncatedOpenWithRange> for i8 { - fn from(value: IncompleteTruncatedOpenWithRange) -> Self { +impl From<IncompleteTruncatedWithRange> for i8 { + fn from(value: IncompleteTruncatedWithRange) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedOpenWithRange> for i16 { - fn from(value: IncompleteTruncatedOpenWithRange) -> Self { +impl From<IncompleteTruncatedWithRange> for i16 { + fn from(value: IncompleteTruncatedWithRange) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedOpenWithRange> for i32 { - fn from(value: IncompleteTruncatedOpenWithRange) -> Self { +impl From<IncompleteTruncatedWithRange> for i32 { + fn from(value: IncompleteTruncatedWithRange) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedOpenWithRange> for i64 { - fn from(value: IncompleteTruncatedOpenWithRange) -> Self { +impl From<IncompleteTruncatedWithRange> for i64 { + fn from(value: IncompleteTruncatedWithRange) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedOpenWithRange> for u16 { - fn from(value: IncompleteTruncatedOpenWithRange) -> Self { +impl From<IncompleteTruncatedWithRange> for u16 { + fn from(value: IncompleteTruncatedWithRange) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedOpenWithRange> for u32 { - fn from(value: IncompleteTruncatedOpenWithRange) -> Self { +impl From<IncompleteTruncatedWithRange> for u32 { + fn from(value: IncompleteTruncatedWithRange) -> Self { u8::from(value) as Self } } -impl From<IncompleteTruncatedOpenWithRange> for u64 { - fn from(value: IncompleteTruncatedOpenWithRange) -> Self { +impl From<IncompleteTruncatedWithRange> for u64 { + fn from(value: IncompleteTruncatedWithRange) -> Self { u8::from(value) as Self } } diff --git a/tests/generated/packet_decl_24bit_enum_array_big_endian.rs b/tests/generated/packet_decl_24bit_enum_array_big_endian.rs index 7717d7a..47b45dc 100644 --- a/tests/generated/packet_decl_24bit_enum_array_big_endian.rs +++ b/tests/generated/packet_decl_24bit_enum_array_big_endian.rs @@ -125,10 +125,10 @@ impl BarData { let x = (0..5) .map(|_| { Foo::try_from(bytes.get_mut().get_uint(3) as u32) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Bar".to_string(), field: String::new(), - value: unknown_val as u64, + value: 0, type_: "Foo".to_string(), }) }) diff --git a/tests/generated/packet_decl_24bit_enum_array_little_endian.rs b/tests/generated/packet_decl_24bit_enum_array_little_endian.rs index 2fb9a9c..a413ce1 100644 --- a/tests/generated/packet_decl_24bit_enum_array_little_endian.rs +++ b/tests/generated/packet_decl_24bit_enum_array_little_endian.rs @@ -125,10 +125,10 @@ impl BarData { let x = (0..5) .map(|_| { Foo::try_from(bytes.get_mut().get_uint_le(3) as u32) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Bar".to_string(), field: String::new(), - value: unknown_val as u64, + value: 0, type_: "Foo".to_string(), }) }) diff --git a/tests/generated/packet_decl_24bit_enum_big_endian.rs b/tests/generated/packet_decl_24bit_enum_big_endian.rs index 272e52d..c63b562 100644 --- a/tests/generated/packet_decl_24bit_enum_big_endian.rs +++ b/tests/generated/packet_decl_24bit_enum_big_endian.rs @@ -123,10 +123,10 @@ impl BarData { }); } let x = Foo::try_from(bytes.get_mut().get_uint(3) as u32) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Bar".to_string(), field: "x".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_uint(3) as u32 as u64, type_: "Foo".to_string(), })?; Ok(Self { x }) diff --git a/tests/generated/packet_decl_24bit_enum_little_endian.rs b/tests/generated/packet_decl_24bit_enum_little_endian.rs index 278336c..2e58a9e 100644 --- a/tests/generated/packet_decl_24bit_enum_little_endian.rs +++ b/tests/generated/packet_decl_24bit_enum_little_endian.rs @@ -123,10 +123,10 @@ impl BarData { }); } let x = Foo::try_from(bytes.get_mut().get_uint_le(3) as u32) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Bar".to_string(), field: "x".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_uint_le(3) as u32 as u64, type_: "Foo".to_string(), })?; Ok(Self { x }) diff --git a/tests/generated/packet_decl_64bit_enum_array_big_endian.rs b/tests/generated/packet_decl_64bit_enum_array_big_endian.rs index caeba78..dd28666 100644 --- a/tests/generated/packet_decl_64bit_enum_array_big_endian.rs +++ b/tests/generated/packet_decl_64bit_enum_array_big_endian.rs @@ -110,10 +110,10 @@ impl BarData { let x = (0..7) .map(|_| { Foo::try_from(bytes.get_mut().get_u64()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Bar".to_string(), field: String::new(), - value: unknown_val as u64, + value: 0, type_: "Foo".to_string(), }) }) diff --git a/tests/generated/packet_decl_64bit_enum_array_little_endian.rs b/tests/generated/packet_decl_64bit_enum_array_little_endian.rs index 2a698b8..371c1eb 100644 --- a/tests/generated/packet_decl_64bit_enum_array_little_endian.rs +++ b/tests/generated/packet_decl_64bit_enum_array_little_endian.rs @@ -110,10 +110,10 @@ impl BarData { let x = (0..7) .map(|_| { Foo::try_from(bytes.get_mut().get_u64_le()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Bar".to_string(), field: String::new(), - value: unknown_val as u64, + value: 0, type_: "Foo".to_string(), }) }) diff --git a/tests/generated/packet_decl_64bit_enum_big_endian.rs b/tests/generated/packet_decl_64bit_enum_big_endian.rs index f29c654..bd46742 100644 --- a/tests/generated/packet_decl_64bit_enum_big_endian.rs +++ b/tests/generated/packet_decl_64bit_enum_big_endian.rs @@ -108,10 +108,10 @@ impl BarData { }); } let x = Foo::try_from(bytes.get_mut().get_u64()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Bar".to_string(), field: "x".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_u64() as u64, type_: "Foo".to_string(), })?; Ok(Self { x }) diff --git a/tests/generated/packet_decl_64bit_enum_little_endian.rs b/tests/generated/packet_decl_64bit_enum_little_endian.rs index 0bc5a12..75a43b6 100644 --- a/tests/generated/packet_decl_64bit_enum_little_endian.rs +++ b/tests/generated/packet_decl_64bit_enum_little_endian.rs @@ -108,10 +108,10 @@ impl BarData { }); } let x = Foo::try_from(bytes.get_mut().get_u64_le()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Bar".to_string(), field: "x".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_u64_le() as u64, type_: "Foo".to_string(), })?; Ok(Self { x }) diff --git a/tests/generated/packet_decl_8bit_enum_array_big_endian.rs b/tests/generated/packet_decl_8bit_enum_array_big_endian.rs index f36f1ba..4c16ddf 100644 --- a/tests/generated/packet_decl_8bit_enum_array_big_endian.rs +++ b/tests/generated/packet_decl_8bit_enum_array_big_endian.rs @@ -140,10 +140,10 @@ impl BarData { let x = (0..3) .map(|_| { Foo::try_from(bytes.get_mut().get_u8()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Bar".to_string(), field: String::new(), - value: unknown_val as u64, + value: 0, type_: "Foo".to_string(), }) }) diff --git a/tests/generated/packet_decl_8bit_enum_array_little_endian.rs b/tests/generated/packet_decl_8bit_enum_array_little_endian.rs index f36f1ba..4c16ddf 100644 --- a/tests/generated/packet_decl_8bit_enum_array_little_endian.rs +++ b/tests/generated/packet_decl_8bit_enum_array_little_endian.rs @@ -140,10 +140,10 @@ impl BarData { let x = (0..3) .map(|_| { Foo::try_from(bytes.get_mut().get_u8()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Bar".to_string(), field: String::new(), - value: unknown_val as u64, + value: 0, type_: "Foo".to_string(), }) }) diff --git a/tests/generated/packet_decl_8bit_enum_big_endian.rs b/tests/generated/packet_decl_8bit_enum_big_endian.rs index bccdaeb..8ceb132 100644 --- a/tests/generated/packet_decl_8bit_enum_big_endian.rs +++ b/tests/generated/packet_decl_8bit_enum_big_endian.rs @@ -138,10 +138,10 @@ impl BarData { }); } let x = Foo::try_from(bytes.get_mut().get_u8()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Bar".to_string(), field: "x".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_u8() as u64, type_: "Foo".to_string(), })?; Ok(Self { x }) diff --git a/tests/generated/packet_decl_8bit_enum_little_endian.rs b/tests/generated/packet_decl_8bit_enum_little_endian.rs index bccdaeb..8ceb132 100644 --- a/tests/generated/packet_decl_8bit_enum_little_endian.rs +++ b/tests/generated/packet_decl_8bit_enum_little_endian.rs @@ -138,10 +138,10 @@ impl BarData { }); } let x = Foo::try_from(bytes.get_mut().get_u8()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Bar".to_string(), field: "x".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_u8() as u64, type_: "Foo".to_string(), })?; Ok(Self { x }) diff --git a/tests/generated/packet_decl_child_packets_big_endian.rs b/tests/generated/packet_decl_child_packets_big_endian.rs index 8b3e05d..7a000c7 100644 --- a/tests/generated/packet_decl_child_packets_big_endian.rs +++ b/tests/generated/packet_decl_child_packets_big_endian.rs @@ -166,10 +166,10 @@ impl FooData { }); } let b = Enum16::try_from(bytes.get_mut().get_u16()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Foo".to_string(), field: "b".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_u16() as u64, type_: "Enum16".to_string(), })?; if bytes.get().remaining() < 1 { diff --git a/tests/generated/packet_decl_child_packets_little_endian.rs b/tests/generated/packet_decl_child_packets_little_endian.rs index 8a464b2..7fe9783 100644 --- a/tests/generated/packet_decl_child_packets_little_endian.rs +++ b/tests/generated/packet_decl_child_packets_little_endian.rs @@ -166,10 +166,10 @@ impl FooData { }); } let b = Enum16::try_from(bytes.get_mut().get_u16_le()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Foo".to_string(), field: "b".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_u16_le() as u64, type_: "Enum16".to_string(), })?; if bytes.get().remaining() < 1 { diff --git a/tests/generated/packet_decl_fixed_enum_field_big_endian.rs b/tests/generated/packet_decl_fixed_enum_field_big_endian.rs index 5c780ad..2ec6b58 100644 --- a/tests/generated/packet_decl_fixed_enum_field_big_endian.rs +++ b/tests/generated/packet_decl_fixed_enum_field_big_endian.rs @@ -143,11 +143,10 @@ impl FooData { }); } let chunk = bytes.get_mut().get_u64(); - let fixed_value = (chunk & 0x7f) as u8; - if fixed_value != u8::from(Enum7::A) { + if (chunk & 0x7f) as u8 != u8::from(Enum7::A) { return Err(Error::InvalidFixedValue { expected: u8::from(Enum7::A) as u64, - actual: fixed_value as u64, + actual: (chunk & 0x7f) as u8 as u64, }); } let b = ((chunk >> 7) & 0x1ff_ffff_ffff_ffff_u64); diff --git a/tests/generated/packet_decl_fixed_enum_field_little_endian.rs b/tests/generated/packet_decl_fixed_enum_field_little_endian.rs index 45486c5..13aecd9 100644 --- a/tests/generated/packet_decl_fixed_enum_field_little_endian.rs +++ b/tests/generated/packet_decl_fixed_enum_field_little_endian.rs @@ -143,11 +143,10 @@ impl FooData { }); } let chunk = bytes.get_mut().get_u64_le(); - let fixed_value = (chunk & 0x7f) as u8; - if fixed_value != u8::from(Enum7::A) { + if (chunk & 0x7f) as u8 != u8::from(Enum7::A) { return Err(Error::InvalidFixedValue { expected: u8::from(Enum7::A) as u64, - actual: fixed_value as u64, + actual: (chunk & 0x7f) as u8 as u64, }); } let b = ((chunk >> 7) & 0x1ff_ffff_ffff_ffff_u64); diff --git a/tests/generated/packet_decl_fixed_scalar_field_big_endian.rs b/tests/generated/packet_decl_fixed_scalar_field_big_endian.rs index 349b183..e047669 100644 --- a/tests/generated/packet_decl_fixed_scalar_field_big_endian.rs +++ b/tests/generated/packet_decl_fixed_scalar_field_big_endian.rs @@ -77,11 +77,10 @@ impl FooData { }); } let chunk = bytes.get_mut().get_u64(); - let fixed_value = (chunk & 0x7f) as u8; if (chunk & 0x7f) as u8 != 7 { return Err(Error::InvalidFixedValue { expected: 7, - actual: fixed_value as u64, + actual: (chunk & 0x7f) as u8 as u64, }); } let b = ((chunk >> 7) & 0x1ff_ffff_ffff_ffff_u64); diff --git a/tests/generated/packet_decl_fixed_scalar_field_little_endian.rs b/tests/generated/packet_decl_fixed_scalar_field_little_endian.rs index 96b9064..39922ca 100644 --- a/tests/generated/packet_decl_fixed_scalar_field_little_endian.rs +++ b/tests/generated/packet_decl_fixed_scalar_field_little_endian.rs @@ -77,11 +77,10 @@ impl FooData { }); } let chunk = bytes.get_mut().get_u64_le(); - let fixed_value = (chunk & 0x7f) as u8; if (chunk & 0x7f) as u8 != 7 { return Err(Error::InvalidFixedValue { expected: 7, - actual: fixed_value as u64, + actual: (chunk & 0x7f) as u8 as u64, }); } let b = ((chunk >> 7) & 0x1ff_ffff_ffff_ffff_u64); diff --git a/tests/generated/packet_decl_grand_children_big_endian.rs b/tests/generated/packet_decl_grand_children_big_endian.rs index f1a2cac..896a46f 100644 --- a/tests/generated/packet_decl_grand_children_big_endian.rs +++ b/tests/generated/packet_decl_grand_children_big_endian.rs @@ -157,10 +157,10 @@ impl ParentData { }); } let foo = Enum16::try_from(bytes.get_mut().get_u16()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Parent".to_string(), field: "foo".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_u16() as u64, type_: "Enum16".to_string(), })?; if bytes.get().remaining() < 2 { @@ -171,10 +171,10 @@ impl ParentData { }); } let bar = Enum16::try_from(bytes.get_mut().get_u16()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Parent".to_string(), field: "bar".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_u16() as u64, type_: "Enum16".to_string(), })?; if bytes.get().remaining() < 2 { @@ -185,10 +185,10 @@ impl ParentData { }); } let baz = Enum16::try_from(bytes.get_mut().get_u16()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Parent".to_string(), field: "baz".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_u16() as u64, type_: "Enum16".to_string(), })?; if bytes.get().remaining() < 1 { @@ -389,10 +389,10 @@ impl ChildData { }); } let quux = Enum16::try_from(bytes.get_mut().get_u16()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Child".to_string(), field: "quux".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_u16() as u64, type_: "Enum16".to_string(), })?; let payload = bytes.get(); diff --git a/tests/generated/packet_decl_grand_children_little_endian.rs b/tests/generated/packet_decl_grand_children_little_endian.rs index 66fa76a..4a672a6 100644 --- a/tests/generated/packet_decl_grand_children_little_endian.rs +++ b/tests/generated/packet_decl_grand_children_little_endian.rs @@ -157,10 +157,10 @@ impl ParentData { }); } let foo = Enum16::try_from(bytes.get_mut().get_u16_le()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Parent".to_string(), field: "foo".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_u16_le() as u64, type_: "Enum16".to_string(), })?; if bytes.get().remaining() < 2 { @@ -171,10 +171,10 @@ impl ParentData { }); } let bar = Enum16::try_from(bytes.get_mut().get_u16_le()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Parent".to_string(), field: "bar".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_u16_le() as u64, type_: "Enum16".to_string(), })?; if bytes.get().remaining() < 2 { @@ -185,10 +185,10 @@ impl ParentData { }); } let baz = Enum16::try_from(bytes.get_mut().get_u16_le()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Parent".to_string(), field: "baz".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_u16_le() as u64, type_: "Enum16".to_string(), })?; if bytes.get().remaining() < 1 { @@ -389,10 +389,10 @@ impl ChildData { }); } let quux = Enum16::try_from(bytes.get_mut().get_u16_le()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Child".to_string(), field: "quux".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_u16_le() as u64, type_: "Enum16".to_string(), })?; let payload = bytes.get(); diff --git a/tests/generated/packet_decl_mixed_scalars_enums_big_endian.rs b/tests/generated/packet_decl_mixed_scalars_enums_big_endian.rs index 7dcf2e6..122b202 100644 --- a/tests/generated/packet_decl_mixed_scalars_enums_big_endian.rs +++ b/tests/generated/packet_decl_mixed_scalars_enums_big_endian.rs @@ -206,18 +206,18 @@ impl FooData { } 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 { + .map_err(|_| Error::InvalidEnumValueError { obj: "Foo".to_string(), field: "x".to_string(), - value: unknown_val as u64, + value: (chunk & 0x7f) as u8 as u64, type_: "Enum7".to_string(), })?; let y = ((chunk >> 7) & 0x1f) as u8; let z = Enum9::try_from(((chunk >> 12) & 0x1ff) as u16) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Foo".to_string(), field: "z".to_string(), - value: unknown_val as u64, + value: ((chunk >> 12) & 0x1ff) as u16 as u64, type_: "Enum9".to_string(), })?; let w = ((chunk >> 21) & 0x7) as u8; diff --git a/tests/generated/packet_decl_mixed_scalars_enums_little_endian.rs b/tests/generated/packet_decl_mixed_scalars_enums_little_endian.rs index 667dab3..0cc3d92 100644 --- a/tests/generated/packet_decl_mixed_scalars_enums_little_endian.rs +++ b/tests/generated/packet_decl_mixed_scalars_enums_little_endian.rs @@ -206,18 +206,18 @@ impl FooData { } 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 { + .map_err(|_| Error::InvalidEnumValueError { obj: "Foo".to_string(), field: "x".to_string(), - value: unknown_val as u64, + value: (chunk & 0x7f) as u8 as u64, type_: "Enum7".to_string(), })?; let y = ((chunk >> 7) & 0x1f) as u8; let z = Enum9::try_from(((chunk >> 12) & 0x1ff) as u16) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Foo".to_string(), field: "z".to_string(), - value: unknown_val as u64, + value: ((chunk >> 12) & 0x1ff) as u16 as u64, type_: "Enum9".to_string(), })?; let w = ((chunk >> 21) & 0x7) as u8; diff --git a/tests/generated/packet_decl_parent_with_alias_child_big_endian.rs b/tests/generated/packet_decl_parent_with_alias_child_big_endian.rs index 785c0ee..8c9232d 100644 --- a/tests/generated/packet_decl_parent_with_alias_child_big_endian.rs +++ b/tests/generated/packet_decl_parent_with_alias_child_big_endian.rs @@ -169,10 +169,10 @@ impl ParentData { }); } let v = Enum8::try_from(bytes.get_mut().get_u8()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Parent".to_string(), field: "v".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_u8() as u64, type_: "Enum8".to_string(), })?; let payload = bytes.get(); 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 index 785c0ee..8c9232d 100644 --- a/tests/generated/packet_decl_parent_with_alias_child_little_endian.rs +++ b/tests/generated/packet_decl_parent_with_alias_child_little_endian.rs @@ -169,10 +169,10 @@ impl ParentData { }); } let v = Enum8::try_from(bytes.get_mut().get_u8()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Parent".to_string(), field: "v".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_u8() as u64, type_: "Enum8".to_string(), })?; let payload = bytes.get(); diff --git a/tests/generated/packet_decl_parent_with_no_payload_big_endian.rs b/tests/generated/packet_decl_parent_with_no_payload_big_endian.rs index 82c45c5..4f58e26 100644 --- a/tests/generated/packet_decl_parent_with_no_payload_big_endian.rs +++ b/tests/generated/packet_decl_parent_with_no_payload_big_endian.rs @@ -160,10 +160,10 @@ impl ParentData { }); } let v = Enum8::try_from(bytes.get_mut().get_u8()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Parent".to_string(), field: "v".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_u8() as u64, type_: "Enum8".to_string(), })?; let payload: &[u8] = &[]; 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 index 82c45c5..4f58e26 100644 --- a/tests/generated/packet_decl_parent_with_no_payload_little_endian.rs +++ b/tests/generated/packet_decl_parent_with_no_payload_little_endian.rs @@ -160,10 +160,10 @@ impl ParentData { }); } let v = Enum8::try_from(bytes.get_mut().get_u8()) - .map_err(|unknown_val| Error::InvalidEnumValueError { + .map_err(|_| Error::InvalidEnumValueError { obj: "Parent".to_string(), field: "v".to_string(), - value: unknown_val as u64, + value: bytes.get_mut().get_u8() as u64, type_: "Enum8".to_string(), })?; let payload: &[u8] = &[]; diff --git a/tests/generated/reserved_identifier_big_endian.rs b/tests/generated/reserved_identifier_big_endian.rs deleted file mode 100644 index 1f13532..0000000 --- a/tests/generated/reserved_identifier_big_endian.rs +++ /dev/null @@ -1,145 +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 thiserror::Error; -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, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error( - "array size ({array} bytes) is not a multiple of the element size ({element} bytes)" - )] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec<u8>; -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct TestData { - r#type: u8, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Test { - #[cfg_attr(feature = "serde", serde(flatten))] - test: TestData, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct TestBuilder { - pub r#type: u8, -} -impl TestData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 1 - } - fn parse(bytes: &[u8]) -> Result<Self> { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self> { - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Test".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let r#type = bytes.get_mut().get_u8(); - Ok(Self { r#type }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u8(self.r#type); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 1 - } -} -impl Packet for Test { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.test.get_size()); - self.test.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec<u8> { - self.to_bytes().to_vec() - } -} -impl From<Test> for Bytes { - fn from(packet: Test) -> Self { - packet.to_bytes() - } -} -impl From<Test> for Vec<u8> { - fn from(packet: Test) -> Self { - packet.to_vec() - } -} -impl Test { - pub fn parse(bytes: &[u8]) -> Result<Self> { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self> { - let data = TestData::parse_inner(&mut bytes)?; - Self::new(data) - } - fn new(test: TestData) -> Result<Self> { - Ok(Self { test }) - } - pub fn get_type(&self) -> u8 { - self.test.r#type - } - fn write_to(&self, buffer: &mut BytesMut) { - self.test.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.test.get_size() - } -} -impl TestBuilder { - pub fn build(self) -> Test { - let test = TestData { r#type: self.r#type }; - Test::new(test).unwrap() - } -} -impl From<TestBuilder> for Test { - fn from(builder: TestBuilder) -> Test { - builder.build().into() - } -} diff --git a/tests/generated/reserved_identifier_little_endian.rs b/tests/generated/reserved_identifier_little_endian.rs deleted file mode 100644 index 1f13532..0000000 --- a/tests/generated/reserved_identifier_little_endian.rs +++ /dev/null @@ -1,145 +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 thiserror::Error; -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, Error)] -pub enum Error { - #[error("Packet parsing failed")] - InvalidPacketError, - #[error("{field} was {value:x}, which is not known")] - ConstraintOutOfBounds { field: String, value: u64 }, - #[error("Got {actual:x}, expected {expected:x}")] - InvalidFixedValue { expected: u64, actual: u64 }, - #[error("when parsing {obj} needed length of {wanted} but got {got}")] - InvalidLengthError { obj: String, wanted: usize, got: usize }, - #[error( - "array size ({array} bytes) is not a multiple of the element size ({element} bytes)" - )] - InvalidArraySize { array: usize, element: usize }, - #[error("Due to size restrictions a struct could not be parsed.")] - ImpossibleStructError, - #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")] - InvalidEnumValueError { obj: String, field: String, value: u64, type_: String }, - #[error("expected child {expected}, got {actual}")] - InvalidChildError { expected: &'static str, actual: String }, -} -pub trait Packet { - fn to_bytes(self) -> Bytes; - fn to_vec(self) -> Vec<u8>; -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct TestData { - r#type: u8, -} -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Test { - #[cfg_attr(feature = "serde", serde(flatten))] - test: TestData, -} -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct TestBuilder { - pub r#type: u8, -} -impl TestData { - fn conforms(bytes: &[u8]) -> bool { - bytes.len() >= 1 - } - fn parse(bytes: &[u8]) -> Result<Self> { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self> { - if bytes.get().remaining() < 1 { - return Err(Error::InvalidLengthError { - obj: "Test".to_string(), - wanted: 1, - got: bytes.get().remaining(), - }); - } - let r#type = bytes.get_mut().get_u8(); - Ok(Self { r#type }) - } - fn write_to(&self, buffer: &mut BytesMut) { - buffer.put_u8(self.r#type); - } - fn get_total_size(&self) -> usize { - self.get_size() - } - fn get_size(&self) -> usize { - 1 - } -} -impl Packet for Test { - fn to_bytes(self) -> Bytes { - let mut buffer = BytesMut::with_capacity(self.test.get_size()); - self.test.write_to(&mut buffer); - buffer.freeze() - } - fn to_vec(self) -> Vec<u8> { - self.to_bytes().to_vec() - } -} -impl From<Test> for Bytes { - fn from(packet: Test) -> Self { - packet.to_bytes() - } -} -impl From<Test> for Vec<u8> { - fn from(packet: Test) -> Self { - packet.to_vec() - } -} -impl Test { - pub fn parse(bytes: &[u8]) -> Result<Self> { - let mut cell = Cell::new(bytes); - let packet = Self::parse_inner(&mut cell)?; - Ok(packet) - } - fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self> { - let data = TestData::parse_inner(&mut bytes)?; - Self::new(data) - } - fn new(test: TestData) -> Result<Self> { - Ok(Self { test }) - } - pub fn get_type(&self) -> u8 { - self.test.r#type - } - fn write_to(&self, buffer: &mut BytesMut) { - self.test.write_to(buffer) - } - pub fn get_size(&self) -> usize { - self.test.get_size() - } -} -impl TestBuilder { - pub fn build(self) -> Test { - let test = TestData { r#type: self.r#type }; - Test::new(test).unwrap() - } -} -impl From<TestBuilder> for Test { - fn from(builder: TestBuilder) -> Test { - builder.build().into() - } -} |