use macro_rules_attribute::derive; use mini_macro_magic::export; // Assume the following is in a different crate we don't control. // But the author has used export to export the definition. #[derive(export!)] #[custom(export(person$))] pub struct Person { name: String, age: u8, } #[derive(export!)] #[custom(export(other_person$))] pub struct OtherPerson { age: u8, // We swapped the order of the fields. name: String, } // Assume the following is code we can control. // We want to implement our trait Serialize for Person but we don't // want to have to repeat the definition of Person. // We can use the exported definition that export made. // Implement Serialize for Person based on it's definition. person!(impl_serialize!(Person)); other_person!(impl_serialize!(OtherPerson)); #[test] fn check_serialization() { let bob = Person { name: "bob".into(), age: 29, }; let mut bytes = Vec::new(); bob.serialize(&mut bytes); assert_eq!(bytes, [3, 0, 0, 0, 0, 0, 0, 0, 98, 111, 98, 29]); } #[test] fn check_other_serialization() { let bob = OtherPerson { name: "bob".into(), age: 29, }; let mut bytes = Vec::new(); bob.serialize(&mut bytes); // 29 is first now because we swapped the order of the fields in the definition of // OtherPerson. assert_eq!(bytes, [29, 3, 0, 0, 0, 0, 0, 0, 0, 98, 111, 98]); } // Implement serialize based on the definition of a struct. macro_rules! impl_serialize { {{ $(#[$($attr:tt)*])* $vis:vis struct $name:ident { $($field:ident: $ty:ty),*$(,)? } } $path:path} => { impl Serialize for $path { fn serialize(&self, buffer: &mut Vec) { $(self.$field.serialize(buffer);)* } } }; } use impl_serialize; // Example serialize trait. trait Serialize { fn serialize(&self, buffer: &mut Vec); } impl Serialize for u8 { fn serialize(&self, buffer: &mut Vec) { buffer.push(*self); } } impl Serialize for usize { fn serialize(&self, buffer: &mut Vec) { buffer.extend((*self as u64).to_le_bytes()); } } impl Serialize for String { fn serialize(&self, buffer: &mut Vec) { self.len().serialize(buffer); buffer.extend(self.as_bytes()); } }