1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 14:26:04 +00:00

implement #[limit(i)] attribute for AzBuf derive macro

This commit is contained in:
mat 2024-11-27 05:11:42 +00:00
parent f8cd7ed1de
commit d0472484fd
5 changed files with 62 additions and 4 deletions

View file

@ -19,7 +19,7 @@ pub fn derive_azaleawrite(input: TokenStream) -> TokenStream {
write::create_impl_azaleawrite(&ident, &data).into()
}
#[proc_macro_derive(AzBuf, attributes(var))]
#[proc_macro_derive(AzBuf, attributes(var, limit))]
pub fn derive_azbuf(input: TokenStream) -> TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input);

View file

@ -9,14 +9,35 @@ fn read_named_fields(
.map(|f| {
let field_name = &f.ident;
let field_type = &f.ty;
let is_variable_length = f.attrs.iter().any(|a| a.path().is_ident("var"));
let limit = f
.attrs
.iter()
.find(|a| a.path().is_ident("limit"))
.map(|a| {
a.parse_args::<syn::LitInt>()
.unwrap()
.base10_parse::<usize>()
.unwrap()
});
if is_variable_length && limit.is_some() {
panic!("Fields cannot have both var and limit attributes");
}
// do a different buf.write_* for each field depending on the type
// if it's a string, use buf.write_string
match field_type {
syn::Type::Path(_) | syn::Type::Array(_) => {
if f.attrs.iter().any(|a| a.path().is_ident("var")) {
if is_variable_length {
quote! {
let #field_name = azalea_buf::AzaleaReadVar::azalea_read_var(buf)?;
}
} else if let Some(limit) = limit {
quote! {
let #field_name = azalea_buf::AzaleaReadLimited::azalea_read_limited(buf, #limit)?;
}
} else {
quote! {
let #field_name = azalea_buf::AzaleaRead::azalea_read(buf)?;
@ -108,10 +129,31 @@ pub fn create_impl_azalearead(ident: &Ident, data: &Data) -> proc_macro2::TokenS
syn::Fields::Unnamed(fields) => {
let mut reader_code = quote! {};
for f in &fields.unnamed {
if f.attrs.iter().any(|attr| attr.path().is_ident("var")) {
let is_variable_length =
f.attrs.iter().any(|a| a.path().is_ident("var"));
let limit =
f.attrs
.iter()
.find(|a| a.path().is_ident("limit"))
.map(|a| {
a.parse_args::<syn::LitInt>()
.unwrap()
.base10_parse::<usize>()
.unwrap()
});
if is_variable_length && limit.is_some() {
panic!("Fields cannot have both var and limit attributes");
}
if is_variable_length {
reader_code.extend(quote! {
Self::#variant_name(azalea_buf::AzaleaReadVar::azalea_read_var(buf)?),
});
} else if let Some(limit) = limit {
reader_code.extend(quote! {
Self::#variant_name(azalea_buf::AzaleaReadLimited::azalea_read_limited(buf, #limit)?),
});
} else {
reader_code.extend(quote! {
Self::#variant_name(azalea_buf::AzaleaRead::azalea_read(buf)?),

View file

@ -10,7 +10,7 @@ mod write;
pub use azalea_buf_macros::*;
pub use definitions::*;
pub use read::{AzaleaRead, AzaleaReadVar, BufReadError};
pub use read::{AzaleaRead, AzaleaReadLimited, AzaleaReadVar, BufReadError};
pub use serializable_uuid::*;
pub use write::{AzaleaWrite, AzaleaWriteVar};

View file

@ -119,6 +119,16 @@ where
fn azalea_read_var(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError>;
}
// note that there's no Write equivalent for this trait since we don't really
// care if we're writing over the limit (and maybe we already know that the
// server implementation accepts it)
pub trait AzaleaReadLimited
where
Self: Sized,
{
fn azalea_read_limited(buf: &mut Cursor<&[u8]>, limit: usize) -> Result<Self, BufReadError>;
}
impl AzaleaRead for i32 {
fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
Ok(buf.read_i32::<BE>()?)
@ -219,6 +229,11 @@ impl AzaleaRead for String {
read_utf_with_len(buf, MAX_STRING_LENGTH.into())
}
}
impl AzaleaReadLimited for String {
fn azalea_read_limited(buf: &mut Cursor<&[u8]>, limit: usize) -> Result<Self, BufReadError> {
read_utf_with_len(buf, limit as u32)
}
}
impl AzaleaRead for u32 {
fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {

View file

@ -4,6 +4,7 @@ use uuid::Uuid;
#[derive(Clone, Debug, PartialEq, Eq, AzBuf, ServerboundLoginPacket)]
pub struct ServerboundHello {
#[limit(16)]
pub name: String,
pub profile_id: Uuid,
}