pdl: Add support for reserved fields
Test: atest pdl_tests pdl_rust_generator_tests_{le,be}
Change-Id: Ie09c2fa09694f940e8584d56df3beb5019f91cf3
diff --git a/tools/pdl/Android.bp b/tools/pdl/Android.bp
index 8aff2f2..b31a322 100644
--- a/tools/pdl/Android.bp
+++ b/tools/pdl/Android.bp
@@ -70,6 +70,8 @@
"tests/generated/packet_decl_mask_scalar_value_little_endian.rs",
"tests/generated/packet_decl_mixed_scalars_enums_big_endian.rs",
"tests/generated/packet_decl_mixed_scalars_enums_little_endian.rs",
+ "tests/generated/packet_decl_reserved_field_big_endian.rs",
+ "tests/generated/packet_decl_reserved_field_little_endian.rs",
"tests/generated/packet_decl_simple_scalars_big_endian.rs",
"tests/generated/packet_decl_simple_scalars_little_endian.rs",
"tests/generated/preamble.rs",
diff --git a/tools/pdl/src/backends/rust.rs b/tools/pdl/src/backends/rust.rs
index 9b99ba3..9ed3746 100644
--- a/tools/pdl/src/backends/rust.rs
+++ b/tools/pdl/src/backends/rust.rs
@@ -71,10 +71,10 @@
let id_data = format_ident!("{id}Data");
let id_builder = format_ident!("{id}Builder");
+ let fields_with_ids = fields.iter().filter(|f| f.id().is_some()).collect::<Vec<_>>();
let field_names =
- fields.iter().map(|f| format_ident!("{}", f.id().unwrap())).collect::<Vec<_>>();
- let field_types = fields.iter().map(types::rust_type).collect::<Vec<_>>();
-
+ fields_with_ids.iter().map(|f| format_ident!("{}", f.id().unwrap())).collect::<Vec<_>>();
+ let field_types = fields_with_ids.iter().map(|f| types::rust_type(f)).collect::<Vec<_>>();
let getter_names = field_names.iter().map(|id| format_ident!("get_{id}"));
let packet_size =
@@ -410,4 +410,13 @@
}
"
);
+
+ test_pdl!(
+ packet_decl_reserved_field,
+ "
+ packet Foo {
+ _reserved_: 40,
+ }
+ "
+ );
}
diff --git a/tools/pdl/src/backends/rust/declarations.rs b/tools/pdl/src/backends/rust/declarations.rs
index c24721f..8120c51 100644
--- a/tools/pdl/src/backends/rust/declarations.rs
+++ b/tools/pdl/src/backends/rust/declarations.rs
@@ -27,6 +27,10 @@
#id: #field_type,
}
}
+ ast::Field::Reserved { .. } => {
+ // Nothing to do here.
+ quote! {}
+ }
_ => todo!(),
});
}
diff --git a/tools/pdl/src/backends/rust/parser.rs b/tools/pdl/src/backends/rust/parser.rs
index dbdb392..f9091c0 100644
--- a/tools/pdl/src/backends/rust/parser.rs
+++ b/tools/pdl/src/backends/rust/parser.rs
@@ -130,6 +130,10 @@
let #id = #type_id::#from_u(#v).unwrap();
}
}
+ ast::Field::Reserved { .. } => {
+ // Nothing to do here.
+ quote! {}
+ }
_ => todo!(),
});
}
diff --git a/tools/pdl/src/backends/rust/serializer.rs b/tools/pdl/src/backends/rust/serializer.rs
index d348765..5fd5fb1 100644
--- a/tools/pdl/src/backends/rust/serializer.rs
+++ b/tools/pdl/src/backends/rust/serializer.rs
@@ -77,6 +77,9 @@
shift: self.shift,
});
}
+ ast::Field::Reserved { .. } => {
+ // Nothing to do here.
+ }
_ => todo!(),
}
@@ -110,7 +113,13 @@
.collect::<Vec<_>>();
match values.as_slice() {
- [] => todo!(),
+ [] => {
+ let span = format_ident!("{}", self.span);
+ let count = syn::Index::from(self.shift / 8);
+ self.code.push(quote! {
+ #span.put_bytes(0, #count);
+ });
+ }
[value] => {
let put = types::put_uint(self.endianness, value, self.shift, self.span);
self.code.push(quote! {
diff --git a/tools/pdl/tests/generated/packet_decl_reserved_field_big_endian.rs b/tools/pdl/tests/generated/packet_decl_reserved_field_big_endian.rs
new file mode 100644
index 0000000..f8fd123
--- /dev/null
+++ b/tools/pdl/tests/generated/packet_decl_reserved_field_big_endian.rs
@@ -0,0 +1,108 @@
+// @generated rust packets from test
+
+#![allow(warnings, missing_docs)]
+
+use bytes::{Buf, BufMut, Bytes, BytesMut};
+use num_derive::{FromPrimitive, ToPrimitive};
+use num_traits::{FromPrimitive, ToPrimitive};
+use std::convert::{TryFrom, TryInto};
+use std::fmt;
+use std::sync::Arc;
+use thiserror::Error;
+
+type Result<T> = std::result::Result<T, Error>;
+
+#[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("when parsing {obj} needed length of {wanted} but got {got}")]
+ InvalidLengthError { obj: String, wanted: usize, got: 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 },
+}
+
+#[derive(Debug, Error)]
+#[error("{0}")]
+pub struct TryFromError(&'static str);
+
+pub trait Packet {
+ fn to_bytes(self) -> Bytes;
+ fn to_vec(self) -> Vec<u8>;
+}
+
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+struct FooData {}
+#[derive(Debug, Clone)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+ #[cfg_attr(feature = "serde", serde(flatten))]
+ foo: Arc<FooData>,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {}
+impl FooData {
+ fn conforms(bytes: &[u8]) -> bool {
+ bytes.len() >= 5
+ }
+ fn parse(mut bytes: &[u8]) -> Result<Self> {
+ if bytes.remaining() < 5 {
+ return Err(Error::InvalidLengthError {
+ obj: "Foo".to_string(),
+ wanted: 5,
+ got: bytes.remaining(),
+ });
+ }
+ Ok(Self {})
+ }
+ fn write_to(&self, buffer: &mut BytesMut) {
+ buffer.put_bytes(0, 5);
+ }
+ fn get_total_size(&self) -> usize {
+ self.get_size()
+ }
+ fn get_size(&self) -> usize {
+ 5
+ }
+}
+impl Packet for Foo {
+ fn to_bytes(self) -> Bytes {
+ let mut buffer = BytesMut::with_capacity(self.foo.get_total_size());
+ self.foo.write_to(&mut buffer);
+ buffer.freeze()
+ }
+ fn to_vec(self) -> Vec<u8> {
+ self.to_bytes().to_vec()
+ }
+}
+impl From<Foo> for Bytes {
+ fn from(packet: Foo) -> Self {
+ packet.to_bytes()
+ }
+}
+impl From<Foo> for Vec<u8> {
+ fn from(packet: Foo) -> Self {
+ packet.to_vec()
+ }
+}
+impl Foo {
+ pub fn parse(mut bytes: &[u8]) -> Result<Self> {
+ Ok(Self::new(Arc::new(FooData::parse(bytes)?)).unwrap())
+ }
+ fn new(root: Arc<FooData>) -> std::result::Result<Self, &'static str> {
+ let foo = root;
+ Ok(Self { foo })
+ }
+}
+impl FooBuilder {
+ pub fn build(self) -> Foo {
+ let foo = Arc::new(FooData {});
+ Foo::new(foo).unwrap()
+ }
+}
diff --git a/tools/pdl/tests/generated/packet_decl_reserved_field_little_endian.rs b/tools/pdl/tests/generated/packet_decl_reserved_field_little_endian.rs
new file mode 100644
index 0000000..f8fd123
--- /dev/null
+++ b/tools/pdl/tests/generated/packet_decl_reserved_field_little_endian.rs
@@ -0,0 +1,108 @@
+// @generated rust packets from test
+
+#![allow(warnings, missing_docs)]
+
+use bytes::{Buf, BufMut, Bytes, BytesMut};
+use num_derive::{FromPrimitive, ToPrimitive};
+use num_traits::{FromPrimitive, ToPrimitive};
+use std::convert::{TryFrom, TryInto};
+use std::fmt;
+use std::sync::Arc;
+use thiserror::Error;
+
+type Result<T> = std::result::Result<T, Error>;
+
+#[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("when parsing {obj} needed length of {wanted} but got {got}")]
+ InvalidLengthError { obj: String, wanted: usize, got: 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 },
+}
+
+#[derive(Debug, Error)]
+#[error("{0}")]
+pub struct TryFromError(&'static str);
+
+pub trait Packet {
+ fn to_bytes(self) -> Bytes;
+ fn to_vec(self) -> Vec<u8>;
+}
+
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+struct FooData {}
+#[derive(Debug, Clone)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct Foo {
+ #[cfg_attr(feature = "serde", serde(flatten))]
+ foo: Arc<FooData>,
+}
+#[derive(Debug)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+pub struct FooBuilder {}
+impl FooData {
+ fn conforms(bytes: &[u8]) -> bool {
+ bytes.len() >= 5
+ }
+ fn parse(mut bytes: &[u8]) -> Result<Self> {
+ if bytes.remaining() < 5 {
+ return Err(Error::InvalidLengthError {
+ obj: "Foo".to_string(),
+ wanted: 5,
+ got: bytes.remaining(),
+ });
+ }
+ Ok(Self {})
+ }
+ fn write_to(&self, buffer: &mut BytesMut) {
+ buffer.put_bytes(0, 5);
+ }
+ fn get_total_size(&self) -> usize {
+ self.get_size()
+ }
+ fn get_size(&self) -> usize {
+ 5
+ }
+}
+impl Packet for Foo {
+ fn to_bytes(self) -> Bytes {
+ let mut buffer = BytesMut::with_capacity(self.foo.get_total_size());
+ self.foo.write_to(&mut buffer);
+ buffer.freeze()
+ }
+ fn to_vec(self) -> Vec<u8> {
+ self.to_bytes().to_vec()
+ }
+}
+impl From<Foo> for Bytes {
+ fn from(packet: Foo) -> Self {
+ packet.to_bytes()
+ }
+}
+impl From<Foo> for Vec<u8> {
+ fn from(packet: Foo) -> Self {
+ packet.to_vec()
+ }
+}
+impl Foo {
+ pub fn parse(mut bytes: &[u8]) -> Result<Self> {
+ Ok(Self::new(Arc::new(FooData::parse(bytes)?)).unwrap())
+ }
+ fn new(root: Arc<FooData>) -> std::result::Result<Self, &'static str> {
+ let foo = root;
+ Ok(Self { foo })
+ }
+}
+impl FooBuilder {
+ pub fn build(self) -> Foo {
+ let foo = Arc::new(FooData {});
+ Foo::new(foo).unwrap()
+ }
+}