expect_json_macros/
lib.rs1use proc_macro::TokenStream;
2use proc_macro2::TokenStream as TokenStream2;
3use quote::quote;
4use syn::parse_macro_input;
5
6mod args;
7use args::*;
8
9#[proc_macro_attribute]
10pub fn expect_op(args: TokenStream, input: TokenStream) -> TokenStream {
11 let args = parse_macro_input!(args as Args);
12
13 expect_op_impl(args, input)
14}
15
16#[doc(hidden)]
17#[proc_macro_attribute]
18pub fn expect_op_for_axum_test(args: TokenStream, input: TokenStream) -> TokenStream {
19 let mut args = parse_macro_input!(args as Args);
20 if args.crate_name_str != "expect_json" {
21 panic!("expect_op does not support internal for axum test");
22 }
23
24 args.crate_name_str = "::axum_test::expect_json";
25 args.crate_name = quote!(::axum_test::expect_json);
26
27 expect_op_impl(args, input)
28}
29
30fn expect_op_impl(args: Args, input: TokenStream) -> TokenStream {
31 let crate_name_str = args.crate_name_str;
32 let crate_name = args.crate_name;
33
34 let input_tokens: TokenStream2 = input.clone().into();
35 let input_item = syn::parse_macro_input!(input as syn::Item);
36 let struct_name = match input_item {
37 syn::Item::Struct(item_struct) => item_struct.ident,
38 syn::Item::Enum(item_enum) => item_enum.ident,
39 _ => panic!("expect_op can only be used on structs or enums"),
40 };
41 let struct_name_str = args.display_name.unwrap_or_else(|| struct_name.to_string());
42 let serde_trampoline_path = format!("{crate_name_str}::__private::serde_trampoline");
43
44 let output = quote! {
45 #[derive(#crate_name::__private::serde::Serialize, #crate_name::__private::serde::Deserialize)]
46 #[serde(crate = #serde_trampoline_path)]
47 #input_tokens
48
49 impl #crate_name::__private::serde::Serialize for #struct_name {
50 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
51 where
52 S: #crate_name::__private::serde::Serializer,
53 {
54 #crate_name::SerializeExpectOp::serialize(self, serializer)
55 }
56 }
57
58 use #crate_name::__private::typetag;
59 #[#crate_name::__private::typetag::serde]
60 impl #crate_name::ExpectOpSerialize for #struct_name {}
61
62 impl #crate_name::ExpectOpExt for #struct_name {
63 fn name(&self) -> &'static str {
64 #struct_name_str
65 }
66 }
67
68 impl From<#struct_name> for #crate_name::__private::serde_json::Value {
69 fn from(value: #struct_name) -> Self {
70 #crate_name::__private::serde_json::to_value(&value).unwrap()
71 }
72 }
73 };
74
75 output.into()
76}