Improve Encodable/Decodable impls

This commit is contained in:
topjohnwu
2025-09-17 20:21:56 -07:00
parent cf483ad4d2
commit dd743f6f7e
2 changed files with 17 additions and 60 deletions

View File

@@ -20,16 +20,12 @@ pub(crate) fn derive_decodable(input: proc_macro::TokenStream) -> proc_macro::To
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let sum = gen_size_sum(&input.data);
let encode = gen_encode(&input.data);
let decode = gen_decode(&input.data);
let expanded = quote! {
// The generated impl.
impl #impl_generics crate::socket::Encodable for #name #ty_generics #where_clause {
fn encoded_len(&self) -> usize {
#sum
}
fn encode(&self, w: &mut impl std::io::Write) -> std::io::Result<()> {
#encode
Ok(())
@@ -45,32 +41,6 @@ pub(crate) fn derive_decodable(input: proc_macro::TokenStream) -> proc_macro::To
proc_macro::TokenStream::from(expanded)
}
// Generate an expression to sum up the size of each field.
fn gen_size_sum(data: &Data) -> TokenStream {
match *data {
Data::Struct(ref data) => {
match data.fields {
Fields::Named(ref fields) => {
// Expands to an expression like
//
// 0 + self.x.encoded_len() + self.y.encoded_len() + self.z.encoded_len()
let recurse = fields.named.iter().map(|f| {
let name = &f.ident;
quote_spanned! { f.span() =>
crate::socket::Encodable::encoded_len(&self.#name)
}
});
quote! {
0 #(+ #recurse)*
}
}
_ => unimplemented!(),
}
}
Data::Enum(_) | Data::Union(_) => unimplemented!(),
}
}
// Generate an expression to encode each field.
fn gen_encode(data: &Data) -> TokenStream {
match *data {

View File

@@ -7,8 +7,6 @@ use std::os::fd::{FromRawFd, IntoRawFd, OwnedFd, RawFd};
use std::os::unix::net::{AncillaryData, SocketAncillary, UnixStream};
pub trait Encodable {
#[allow(dead_code)]
fn encoded_len(&self) -> usize;
fn encode(&self, w: &mut impl Write) -> io::Result<()>;
}
@@ -19,11 +17,6 @@ pub trait Decodable: Sized + Encodable {
macro_rules! impl_pod_encodable {
($($t:ty)*) => ($(
impl Encodable for $t {
#[inline(always)]
fn encoded_len(&self) -> usize {
size_of::<Self>()
}
#[inline(always)]
fn encode(&self, w: &mut impl Write) -> io::Result<()> {
w.write_pod(self)
@@ -43,11 +36,6 @@ macro_rules! impl_pod_encodable {
impl_pod_encodable! { u8 u32 i32 usize }
impl Encodable for bool {
#[inline(always)]
fn encoded_len(&self) -> usize {
size_of::<u8>()
}
#[inline(always)]
fn encode(&self, w: &mut impl Write) -> io::Result<()> {
match *self {
@@ -64,11 +52,24 @@ impl Decodable for bool {
}
}
impl<T: Decodable> Encodable for Vec<T> {
fn encoded_len(&self) -> usize {
size_of::<i32>() + size_of::<T>() * self.len()
}
// impl<E: Encodable, T: AsRef<E>> Encodable for T
macro_rules! impl_encodable_as_ref {
($( ($t:ty, $e:ty, $($g:tt)*) )*) => ($(
impl<$($g)*> Encodable for $t {
#[inline(always)]
fn encode(&self, w: &mut impl Write) -> io::Result<()> {
AsRef::<$e>::as_ref(self).encode(w)
}
}
)*)
}
impl_encodable_as_ref! {
(String, str,)
(Vec<T>, [T], T: Encodable)
}
impl<T: Encodable> Encodable for [T] {
fn encode(&self, w: &mut impl Write) -> io::Result<()> {
(self.len() as i32).encode(w)?;
self.iter().try_for_each(|e| e.encode(w))
@@ -87,26 +88,12 @@ impl<T: Decodable> Decodable for Vec<T> {
}
impl Encodable for str {
fn encoded_len(&self) -> usize {
size_of::<i32>() + self.len()
}
fn encode(&self, w: &mut impl Write) -> io::Result<()> {
(self.len() as i32).encode(w)?;
w.write_all(self.as_bytes())
}
}
impl Encodable for String {
fn encoded_len(&self) -> usize {
self.as_str().encoded_len()
}
fn encode(&self, w: &mut impl Write) -> io::Result<()> {
self.as_str().encode(w)
}
}
impl Decodable for String {
fn decode(r: &mut impl Read) -> io::Result<String> {
let len = i32::decode(r)?;