* Hi folks, I usually use an HMI touchscreen in my projects and for the last few years, I tend to use this kinda-cheap kinda-simple HMI family that communicates via UART. I decided to write an opinionated no\_std lib crate for it with the intention on publishing the crate someday. In the HMI UI designer provided by vendor, UI elements are given an address(VP) like in the picture above. I expect lib users to define types to map UI elements to the application code by deriving serde traits and implementing UI element traits(shoutout to James for the postcard). Right now, a button touch event on the HMI or a request from the MCU looks like this on the receiver side: Human touches the button on the HMI or user requests an UI element data. HMI sends the data via UART. User calls macro-generated event handler on the received frame. Event handler splits metadata information from the frame. Event handler tries to match the metadata with the metadata from the user defined types and then deserializes bytes into the matched type. Event handler calls the user defined handler method of the type to do whatever with the received value. User code example for the receiving part ```rust // There is a button defined the HMI UI that holds an u16 value #[derive(Deserialize, Debug)] struct Button { val: u16, } // At the address 0x1234 impl Metadata for Button { const ADDRESS: u16 = 0x1234; } // Do something with the button value impl Handler for Button { fn handler(&self) { // For testing assert_eq!(0xCCDD, self.val); } } // There is a number input field defined the HMI UI that holds an u32 value #[derive(Deserialize, Debug)] struct NumberInput { val: u32, } // At the address 0x1237 impl Metadata for NumberInput { const ADDRESS: u16 = 0x1237; } // Do something with the received input impl Handler for NumberInput { fn handler(&self) { // For testing assert_eq!(0xCCDDEEFF, self.val); } } // Users are expected to define the event handler via this macro define_handler!(event_handler => Button, NumberInput); fn main() { // Button touch example { // Received frame from UART let received = [ 0x5A, 0xA5, 6, 0x83, 0x12, 0x34, 1, 0xCC, 0xDD, 0, 0, 0, 0, 0, 0, ]; // This should call Handler for Button event_handler(&received).unwrap(); } // AnotherButton touch example { // Received frame from UART let received = [ 0x5A, 0xA5, 8, 0x83, 0x12, 0x37, 1, 0xCC, 0xDD, 0xEE, 0xFF, 0, 0, 0, 0, ]; // This should call Handler for NumberInput event_handler(&received).unwrap(); } } ``` The lib code looks like this for the receiving event handler part: ```rust // This is the macro that generates the event handler function #[macro_export] macro_rules! define_handler { ($fn_name:ident => $($type:ident),+) => { pub fn $fn_name(buf: &[u8]) -> $crate::error::Result<()> { // Split metadata from bytes let (metadata, raw_bytes) = $crate::de::split_metadata_from_bytes(&buf)?; // Compare metadata with the user defined type metadatas // metadata() is a type associated function that returns expected metadata for the type $( if metadata == $type::metadata() { // If it matches, deserialize into the matched type let val: $type = $crate::de::from_raw_bytes(raw_bytes)?; // Call user defined handler method to do something with the received data val.handler(); return Ok(()); })+ // No matches Err($crate::error::Error::NoMetadataMatch) } } } ``` This is my first rust project and I would appreciate some feedback for my approach. I also have a concern regarding the handler method. I feel like the event handler macro and the handler method is too limiting for the users. Would it be better have a macro generate an enum that contains the types and a function that returns that enum? I think that would give more freedom to the users.