From a8408600832e6b98b6ee8835f30b43fece5e262e Mon Sep 17 00:00:00 2001 From: Henri Chataing Date: Wed, 7 Jan 2026 17:32:12 +0100 Subject: [PATCH] rust: Support custom fields of width 64 bits Fix #144 --- pdl-compiler/src/backends/rust/mod.rs | 8 ++-- .../packet_decl_custom_field_big_endian.rs | 48 ++++++++++++++++++- .../packet_decl_custom_field_little_endian.rs | 48 ++++++++++++++++++- 3 files changed, 97 insertions(+), 7 deletions(-) diff --git a/pdl-compiler/src/backends/rust/mod.rs b/pdl-compiler/src/backends/rust/mod.rs index d37eca7e..922236db 100644 --- a/pdl-compiler/src/backends/rust/mod.rs +++ b/pdl-compiler/src/backends/rust/mod.rs @@ -1129,7 +1129,6 @@ fn generate_custom_field_decl( let id = id.to_ident(); let backing_type = types::Integer::new(width); let backing_type_str = proc_macro2::Literal::string(&format!("u{}", backing_type.width)); - let max_value = mask_bits(width, &format!("u{}", backing_type.width)); let size = proc_macro2::Literal::usize_unsuffixed(width / 8); let read_value = types::get_uint(endianness, width, &format_ident!("buf")); @@ -1200,6 +1199,7 @@ fn generate_custom_field_decl( } } } else { + let max_value = mask_bits(width, &format!("u{}", backing_type.width)); quote! { #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -1666,12 +1666,14 @@ mod tests { test_pdl!( packet_decl_custom_field, r#" - custom_field Bar1 : 24 "exact" - custom_field Bar2 : 32 "truncated" + custom_field Bar1 : 24 "truncated" + custom_field Bar2 : 32 "exact" + custom_field Bar3 : 64 "maximum width" packet Foo { a: Bar1, b: Bar2, + c: Bar3, } "# ); diff --git a/pdl-compiler/tests/generated/rust/packet_decl_custom_field_big_endian.rs b/pdl-compiler/tests/generated/rust/packet_decl_custom_field_big_endian.rs index 989f61ac..241fabb4 100644 --- a/pdl-compiler/tests/generated/rust/packet_decl_custom_field_big_endian.rs +++ b/pdl-compiler/tests/generated/rust/packet_decl_custom_field_big_endian.rs @@ -100,11 +100,50 @@ impl From for Bar2 { Bar2(value) } } +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(from = "u64", into = "u64"))] +pub struct Bar3(u64); +impl From<&Bar3> for u64 { + fn from(value: &Bar3) -> u64 { + value.0 + } +} +impl From for u64 { + fn from(value: Bar3) -> u64 { + value.0 + } +} +impl Packet for Bar3 { + fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> { + if buf.len() < 8 { + return Err(DecodeError::InvalidLengthError { + obj: "Bar3", + wanted: 8, + got: buf.len(), + }); + } + Ok((buf.get_u64().into(), buf)) + } + fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> { + buf.put_u64(u64::from(self)); + Ok(()) + } + fn encoded_len(&self) -> usize { + 8 + } +} +impl From for Bar3 { + fn from(value: u64) -> Self { + Bar3(value) + } +} #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Foo { pub a: Bar1, pub b: Bar2, + pub c: Bar3, } impl Foo { pub fn a(&self) -> Bar1 { @@ -113,19 +152,24 @@ impl Foo { pub fn b(&self) -> Bar2 { self.b } + pub fn c(&self) -> Bar3 { + self.c + } } impl Packet for Foo { fn encoded_len(&self) -> usize { - 7 + 15 } fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> { buf.put_uint(u32::from(self.a) as u64, 3); buf.put_u32(u32::from(self.b)); + buf.put_u64(u64::from(self.c)); Ok(()) } fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> { let a = (buf.get_uint(3) as u32).try_into().unwrap(); let b = buf.get_u32().into(); - Ok((Self { a, b }, buf)) + let c = buf.get_u64().into(); + Ok((Self { a, b, c }, buf)) } } diff --git a/pdl-compiler/tests/generated/rust/packet_decl_custom_field_little_endian.rs b/pdl-compiler/tests/generated/rust/packet_decl_custom_field_little_endian.rs index 5eda550c..f5a97142 100644 --- a/pdl-compiler/tests/generated/rust/packet_decl_custom_field_little_endian.rs +++ b/pdl-compiler/tests/generated/rust/packet_decl_custom_field_little_endian.rs @@ -100,11 +100,50 @@ impl From for Bar2 { Bar2(value) } } +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(from = "u64", into = "u64"))] +pub struct Bar3(u64); +impl From<&Bar3> for u64 { + fn from(value: &Bar3) -> u64 { + value.0 + } +} +impl From for u64 { + fn from(value: Bar3) -> u64 { + value.0 + } +} +impl Packet for Bar3 { + fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> { + if buf.len() < 8 { + return Err(DecodeError::InvalidLengthError { + obj: "Bar3", + wanted: 8, + got: buf.len(), + }); + } + Ok((buf.get_u64_le().into(), buf)) + } + fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> { + buf.put_u64_le(u64::from(self)); + Ok(()) + } + fn encoded_len(&self) -> usize { + 8 + } +} +impl From for Bar3 { + fn from(value: u64) -> Self { + Bar3(value) + } +} #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Foo { pub a: Bar1, pub b: Bar2, + pub c: Bar3, } impl Foo { pub fn a(&self) -> Bar1 { @@ -113,19 +152,24 @@ impl Foo { pub fn b(&self) -> Bar2 { self.b } + pub fn c(&self) -> Bar3 { + self.c + } } impl Packet for Foo { fn encoded_len(&self) -> usize { - 7 + 15 } fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> { buf.put_uint_le(u32::from(self.a) as u64, 3); buf.put_u32_le(u32::from(self.b)); + buf.put_u64_le(u64::from(self.c)); Ok(()) } fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> { let a = (buf.get_uint_le(3) as u32).try_into().unwrap(); let b = buf.get_u32_le().into(); - Ok((Self { a, b }, buf)) + let c = buf.get_u64_le().into(); + Ok((Self { a, b, c }, buf)) } }