Skip to content

Commit

Permalink
Implement Packet trait for custom fields of constant size
Browse files Browse the repository at this point in the history
The PDL source
```
custom_field Test : 32 "test"
```

will now generate impl Packet
```
pub struct Test(u32);
impl Packet for Test {
}
```
  • Loading branch information
hchataing committed May 14, 2024
1 parent 9508a36 commit a275027
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 2 deletions.
49 changes: 47 additions & 2 deletions pdl-compiler/src/backends/rust/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -885,11 +885,33 @@ 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 {
fn generate_custom_field_decl(
endianness: ast::EndiannessValue,
id: &str,
width: usize,
) -> proc_macro2::TokenStream {
let name = id;
let id = id.to_ident();
let backing_type = types::Integer::new(width);
let backing_type_str = proc_macro2::Literal::string(&format!("u{}", backing_type.width));
let max_value = mask_bits(width, &format!("u{}", backing_type.width));
let size = proc_macro2::Literal::usize_unsuffixed(width / 8);

let read_value = types::get_uint(endianness, width, &format_ident!("buf"));
let read_value = if [8, 16, 32, 64].contains(&width) {
quote! { #read_value.into() }
} else {
// The value is masked when read, and the conversion must succeed.
quote! { (#read_value).try_into().unwrap() }
};

let write_value = types::put_uint(
endianness,
&quote! { #backing_type::from(self) },
width,
&format_ident!("buf"),
);

let common = quote! {
impl From<&#id> for #backing_type {
fn from(value: &#id) -> #backing_type {
Expand All @@ -902,6 +924,29 @@ fn generate_custom_field_decl(id: &str, width: usize) -> proc_macro2::TokenStrea
value.0
}
}

impl Packet for #id {
fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
if buf.len() < #size {
return Err(DecodeError::InvalidLengthError {
obj: #name,
wanted: #size,
got: buf.len(),
})
}

Ok((#read_value, buf))
}

fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
#write_value;
Ok(())
}

fn encoded_len(&self) -> usize {
#size
}
}
};

if backing_type.width == width {
Expand Down Expand Up @@ -957,7 +1002,7 @@ fn generate_decl(
}
ast::DeclDesc::Enum { id, tags, width } => generate_enum_decl(id, tags, *width),
ast::DeclDesc::CustomField { id, width: Some(width), .. } => {
generate_custom_field_decl(id, *width)
generate_custom_field_decl(file.endianness.value, id, *width)
}
_ => todo!("unsupported Decl::{:?}", decl),
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,25 @@ impl From<ExactSize> for u32 {
value.0
}
}
impl Packet for ExactSize {
fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
if buf.len() < 4 {
return Err(DecodeError::InvalidLengthError {
obj: "ExactSize",
wanted: 4,
got: buf.len(),
});
}
Ok((buf.get_u32().into(), buf))
}
fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
buf.put_u32(u32::from(self));
Ok(())
}
fn encoded_len(&self) -> usize {
4
}
}
impl From<u32> for ExactSize {
fn from(value: u32) -> Self {
ExactSize(value)
Expand All @@ -56,6 +75,25 @@ impl From<TruncatedSize> for u32 {
value.0
}
}
impl Packet for TruncatedSize {
fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
if buf.len() < 3 {
return Err(DecodeError::InvalidLengthError {
obj: "TruncatedSize",
wanted: 3,
got: buf.len(),
});
}
Ok(((buf.get_uint(3) as u32).try_into().unwrap(), buf))
}
fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
buf.put_uint(u32::from(self) as u64, 3);
Ok(())
}
fn encoded_len(&self) -> usize {
3
}
}
impl TryFrom<u32> for TruncatedSize {
type Error = u32;
fn try_from(value: u32) -> Result<Self, Self::Error> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,25 @@ impl From<ExactSize> for u32 {
value.0
}
}
impl Packet for ExactSize {
fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
if buf.len() < 4 {
return Err(DecodeError::InvalidLengthError {
obj: "ExactSize",
wanted: 4,
got: buf.len(),
});
}
Ok((buf.get_u32_le().into(), buf))
}
fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
buf.put_u32_le(u32::from(self));
Ok(())
}
fn encoded_len(&self) -> usize {
4
}
}
impl From<u32> for ExactSize {
fn from(value: u32) -> Self {
ExactSize(value)
Expand All @@ -56,6 +75,25 @@ impl From<TruncatedSize> for u32 {
value.0
}
}
impl Packet for TruncatedSize {
fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
if buf.len() < 3 {
return Err(DecodeError::InvalidLengthError {
obj: "TruncatedSize",
wanted: 3,
got: buf.len(),
});
}
Ok(((buf.get_uint_le(3) as u32).try_into().unwrap(), buf))
}
fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
buf.put_uint_le(u32::from(self) as u64, 3);
Ok(())
}
fn encoded_len(&self) -> usize {
3
}
}
impl TryFrom<u32> for TruncatedSize {
type Error = u32;
fn try_from(value: u32) -> Result<Self, Self::Error> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,25 @@ impl From<Bar1> for u32 {
value.0
}
}
impl Packet for Bar1 {
fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
if buf.len() < 3 {
return Err(DecodeError::InvalidLengthError {
obj: "Bar1",
wanted: 3,
got: buf.len(),
});
}
Ok(((buf.get_uint(3) as u32).try_into().unwrap(), buf))
}
fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
buf.put_uint(u32::from(self) as u64, 3);
Ok(())
}
fn encoded_len(&self) -> usize {
3
}
}
impl TryFrom<u32> for Bar1 {
type Error = u32;
fn try_from(value: u32) -> Result<Self, Self::Error> {
Expand All @@ -57,6 +76,25 @@ impl From<Bar2> for u32 {
value.0
}
}
impl Packet for Bar2 {
fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
if buf.len() < 4 {
return Err(DecodeError::InvalidLengthError {
obj: "Bar2",
wanted: 4,
got: buf.len(),
});
}
Ok((buf.get_u32().into(), buf))
}
fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
buf.put_u32(u32::from(self));
Ok(())
}
fn encoded_len(&self) -> usize {
4
}
}
impl From<u32> for Bar2 {
fn from(value: u32) -> Self {
Bar2(value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,25 @@ impl From<Bar1> for u32 {
value.0
}
}
impl Packet for Bar1 {
fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
if buf.len() < 3 {
return Err(DecodeError::InvalidLengthError {
obj: "Bar1",
wanted: 3,
got: buf.len(),
});
}
Ok(((buf.get_uint_le(3) as u32).try_into().unwrap(), buf))
}
fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
buf.put_uint_le(u32::from(self) as u64, 3);
Ok(())
}
fn encoded_len(&self) -> usize {
3
}
}
impl TryFrom<u32> for Bar1 {
type Error = u32;
fn try_from(value: u32) -> Result<Self, Self::Error> {
Expand All @@ -57,6 +76,25 @@ impl From<Bar2> for u32 {
value.0
}
}
impl Packet for Bar2 {
fn decode(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
if buf.len() < 4 {
return Err(DecodeError::InvalidLengthError {
obj: "Bar2",
wanted: 4,
got: buf.len(),
});
}
Ok((buf.get_u32_le().into(), buf))
}
fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
buf.put_u32_le(u32::from(self));
Ok(())
}
fn encoded_len(&self) -> usize {
4
}
}
impl From<u32> for Bar2 {
fn from(value: u32) -> Self {
Bar2(value)
Expand Down

0 comments on commit a275027

Please sign in to comment.