1use proc_macro::TokenStream;
6use quote::quote;
7use syn::{DeriveInput, parse_macro_input};
8
9#[proc_macro_attribute]
22pub fn claims(_args: TokenStream, input: TokenStream) -> TokenStream {
23 let input = parse_macro_input!(input as DeriveInput);
24
25 let struct_name = &input.ident;
26 let vis = &input.vis;
27 let generics = &input.generics;
28
29 let existing_fields = if let syn::Data::Struct(syn::DataStruct {
31 fields: syn::Fields::Named(fields),
32 ..
33 }) = &input.data
34 {
35 &fields.named
36 } else {
37 return syn::Error::new_spanned(
38 struct_name,
39 "#[claims] can only be applied to structs with named fields",
40 )
41 .to_compile_error()
42 .into();
43 };
44
45 let expanded = quote! {
48 #[derive(Debug, Clone, miniserde::Deserialize)]
49 #vis struct #struct_name #generics {
50 #[serde(rename = "iss")]
51 pub issuer: Option<String>,
52 #[serde(rename = "sub")]
53 pub subject: Option<String>,
54 #[serde(rename = "aud")]
55 pub audience: Option<String>,
56 #[serde(rename = "exp")]
57 pub expiration: Option<i64>,
58 #[serde(rename = "nbf")]
59 pub not_before: Option<i64>,
60 #[serde(rename = "iat")]
61 pub issued_at: Option<i64>,
62 #[serde(rename = "jti")]
63 pub jwt_id: Option<String>,
64
65 #existing_fields
66 }
67
68 impl #generics jwtype::StandardClaims for #struct_name #generics {
69 fn issuer(&self) -> Option<&str> {
70 self.issuer.as_deref()
71 }
72
73 fn subject(&self) -> Option<&str> {
74 self.subject.as_deref()
75 }
76
77 fn audience(&self) -> Option<&str> {
78 self.audience.as_deref()
79 }
80
81 fn expiration(&self) -> Option<i64> {
82 self.expiration
83 }
84
85 fn not_before(&self) -> Option<i64> {
86 self.not_before
87 }
88
89 fn issued_at(&self) -> Option<i64> {
90 self.issued_at
91 }
92
93 fn jwt_id(&self) -> Option<&str> {
94 self.jwt_id.as_deref()
95 }
96 }
97 };
98
99 TokenStream::from(expanded)
100}