| 1 | use defmt_parser::Level; |
| 2 | use proc_macro::TokenStream; |
| 3 | use quote::quote; |
| 4 | use syn::{parse_macro_input, punctuated::Punctuated}; |
| 5 | |
| 6 | use crate::{construct, function_like::log}; |
| 7 | |
| 8 | use self::args::Args; |
| 9 | |
| 10 | mod args; |
| 11 | |
| 12 | pub(crate) fn eq(args: TokenStream) -> TokenStream { |
| 13 | expand(args, binop:BinOp::Eq) |
| 14 | } |
| 15 | |
| 16 | pub(crate) fn ne(args: TokenStream) -> TokenStream { |
| 17 | expand(args, binop:BinOp::Ne) |
| 18 | } |
| 19 | |
| 20 | fn expand(args: TokenStream, binop: BinOp) -> TokenStream { |
| 21 | let args = parse_macro_input!(args as Args); |
| 22 | |
| 23 | let left = args.left; |
| 24 | let right = args.right; |
| 25 | |
| 26 | let mut formatting_args = Punctuated::new(); |
| 27 | |
| 28 | let extra_string = if let Some(log_args) = args.log_args { |
| 29 | if let Some(args) = log_args.formatting_args { |
| 30 | formatting_args.extend(args); |
| 31 | } |
| 32 | format!(": {}" , log_args.format_string.value()) |
| 33 | } else { |
| 34 | String::new() |
| 35 | }; |
| 36 | |
| 37 | let vals = match binop { |
| 38 | BinOp::Eq => &["left_val" , "right_val" ][..], |
| 39 | BinOp::Ne => &["left_val" ][..], |
| 40 | }; |
| 41 | |
| 42 | for val in vals { |
| 43 | formatting_args.push(construct::variable(val)); |
| 44 | } |
| 45 | |
| 46 | let panic_msg = match binop { |
| 47 | BinOp::Eq => format!( |
| 48 | "panicked at 'assertion failed: `(left == right)` {}' |
| 49 | left: ` {{:? }}` |
| 50 | right: ` {{:? }}`" , |
| 51 | extra_string |
| 52 | ), |
| 53 | BinOp::Ne => format!( |
| 54 | "panicked at 'assertion failed: `(left != right)` {}' |
| 55 | left/right: ` {{:? }}`" , |
| 56 | extra_string |
| 57 | ), |
| 58 | }; |
| 59 | |
| 60 | let log_args = log::Args { |
| 61 | format_string: construct::string_literal(&panic_msg), |
| 62 | formatting_args: Some(formatting_args), |
| 63 | }; |
| 64 | let log_stmt = log::expand_parsed(Level::Error, log_args); |
| 65 | |
| 66 | let mut cond = quote!(*left_val == *right_val); |
| 67 | if binop == BinOp::Eq { |
| 68 | cond = quote!(!(#cond)); |
| 69 | } |
| 70 | |
| 71 | quote!( |
| 72 | // evaluate arguments first |
| 73 | match (&(#left), &(#right)) { |
| 74 | (left_val, right_val) => { |
| 75 | // following `core::assert_eq!` |
| 76 | if #cond { |
| 77 | #log_stmt; |
| 78 | defmt::export::panic() |
| 79 | } |
| 80 | } |
| 81 | } |
| 82 | ) |
| 83 | .into() |
| 84 | } |
| 85 | |
| 86 | #[derive (PartialEq)] |
| 87 | enum BinOp { |
| 88 | Eq, |
| 89 | Ne, |
| 90 | } |
| 91 | |