near_sdk_macros/
lib.rs

1#![recursion_limit = "128"]
2extern crate proc_macro;
3
4mod core_impl;
5
6use core_impl::{ext::generate_ext_structs, metadata::generate_contract_metadata_method};
7
8use proc_macro::TokenStream;
9
10use self::core_impl::*;
11use darling::ast::NestedMeta;
12use darling::{Error, FromMeta};
13use proc_macro2::{Ident, Span};
14use quote::{quote, ToTokens};
15use syn::{parse_quote, Expr, ImplItem, ItemEnum, ItemImpl, ItemStruct, ItemTrait, WhereClause};
16
17#[derive(Debug, Clone)]
18struct Serializers {
19    vec: Vec<Expr>,
20}
21
22impl FromMeta for Serializers {
23    fn from_expr(expr: &syn::Expr) -> Result<Self, darling::Error> {
24        match expr {
25            syn::Expr::Array(expr_array) => Ok(Serializers {
26                vec: expr_array
27                    .elems
28                    .iter()
29                    .map(<Expr as FromMeta>::from_expr)
30                    .map(|x| x.unwrap())
31                    .collect::<Vec<_>>(),
32            }),
33            _ => Err(Error::unexpected_expr_type(expr)),
34        }
35    }
36}
37
38#[derive(FromMeta)]
39struct NearMacroArgs {
40    serializers: Option<Serializers>,
41    contract_state: Option<bool>,
42    contract_metadata: Option<core_impl::ContractMetadata>,
43    inside_nearsdk: Option<bool>,
44}
45
46fn has_nested_near_macros(item: TokenStream) -> bool {
47    syn::parse::<syn::Item>(item)
48        .ok()
49        .and_then(|item_ast| {
50            let attrs = match item_ast {
51                syn::Item::Struct(s) => s.attrs,
52                syn::Item::Enum(e) => e.attrs,
53                syn::Item::Impl(i) => i.attrs,
54                _ => vec![], // Other cases don't support near macros anyway
55            };
56
57            attrs.into_iter().find(|attr| {
58                let path_str = attr.path().to_token_stream().to_string();
59                path_str == "near" || path_str == "near_bindgen"
60            })
61        })
62        .is_some()
63}
64
65#[proc_macro_attribute]
66pub fn near(attr: TokenStream, item: TokenStream) -> TokenStream {
67    if attr.to_string().contains("event_json") {
68        return core_impl::near_events(attr, item);
69    }
70
71    let meta_list = match NestedMeta::parse_meta_list(attr.into()) {
72        Ok(v) => v,
73        Err(e) => {
74            return TokenStream::from(Error::from(e).write_errors());
75        }
76    };
77
78    let near_macro_args = match NearMacroArgs::from_list(&meta_list) {
79        Ok(v) => v,
80        Err(e) => {
81            return TokenStream::from(e.write_errors());
82        }
83    };
84
85    let near_sdk_crate = if near_macro_args.inside_nearsdk.unwrap_or(false) {
86        quote! {crate}
87    } else {
88        quote! {::near_sdk}
89    };
90
91    // Check for nested near macros by parsing the input and examining actual attributes
92    if has_nested_near_macros(item.clone()) {
93        return TokenStream::from(
94            syn::Error::new(
95                Span::call_site(),
96                "#[near] or #[near_bindgen] attributes are not allowed to be nested inside of the outmost #[near] attribute. Only a single #[near] attribute is allowed",
97            )
98            .to_compile_error(),
99        );
100    }
101    let string_borsh_crate = quote! {#near_sdk_crate::borsh}.to_string();
102    let string_serde_crate = quote! {#near_sdk_crate::serde}.to_string();
103
104    let mut expanded: proc_macro2::TokenStream = quote! {};
105
106    if near_macro_args.contract_state.unwrap_or(false) {
107        if let Some(metadata) = near_macro_args.contract_metadata {
108            expanded = quote! {#[#near_sdk_crate::near_bindgen(#metadata)]}
109        } else {
110            expanded = quote! {#[#near_sdk_crate::near_bindgen]}
111        }
112    };
113
114    let mut has_borsh = false;
115    let mut has_json = false;
116
117    let mut borsh_attr = quote! {};
118
119    match near_macro_args.serializers {
120        Some(serializers) => {
121            let attr2 = serializers.clone();
122
123            attr2.vec.iter().for_each(|old_expr| {
124                let new_expr = &mut old_expr.clone();
125                match &mut *new_expr {
126                    Expr::Call(ref mut call_expr) => {
127                        if let Expr::Path(ref mut path) = &mut *call_expr.func {
128                            if let Some(ident) = path.path.get_ident() {
129                                if *ident == "json" {
130                                    has_json = true;
131                                    path.path =
132                                        syn::Path::from(Ident::new("serde", Span::call_site()));
133                                    call_expr.args.push(parse_quote! {crate=#string_serde_crate});
134                                } else if *ident == "borsh" {
135                                    has_borsh = true;
136                                    call_expr.args.push(parse_quote! {crate=#string_borsh_crate});
137                                }
138                            }
139                        }
140                        borsh_attr = quote! {#[#new_expr]};
141                    }
142                    Expr::Path(ref mut path_expr) => {
143                        if let Some(ident) = path_expr.path.get_ident() {
144                            if *ident == "json" {
145                                has_json = true;
146                            }
147                            if *ident == "borsh" {
148                                has_borsh = true;
149                                borsh_attr = quote! {#[borsh(crate=#string_borsh_crate)]};
150                            }
151                        }
152                    }
153                    _ => {}
154                }
155            });
156        }
157        None => {
158            has_borsh = true;
159            borsh_attr = quote! {#[borsh(crate = #string_borsh_crate)]};
160        }
161    }
162
163    #[cfg(feature = "abi")]
164    {
165        let schema_derive: proc_macro2::TokenStream =
166            get_schema_derive(has_json, has_borsh, near_sdk_crate.clone(), false);
167        expanded = quote! {
168            #expanded
169            #schema_derive
170        };
171    }
172
173    if has_borsh {
174        expanded = quote! {
175            #expanded
176            #[derive(#near_sdk_crate::borsh::BorshSerialize, #near_sdk_crate::borsh::BorshDeserialize)]
177            #borsh_attr
178        };
179    }
180
181    if has_json {
182        expanded = quote! {
183            #expanded
184            #[derive(#near_sdk_crate::serde::Serialize, #near_sdk_crate::serde::Deserialize)]
185            #[serde(crate = #string_serde_crate)]
186        };
187    }
188
189    if let Ok(input) = syn::parse::<ItemStruct>(item.clone()) {
190        expanded = quote! {
191            #expanded
192            #input
193        };
194    } else if let Ok(input) = syn::parse::<ItemEnum>(item.clone()) {
195        expanded = quote! {
196            #expanded
197            #input
198        };
199    } else if let Ok(input) = syn::parse::<ItemImpl>(item) {
200        expanded = quote! {
201            #[#near_sdk_crate::near_bindgen]
202            #input
203        };
204    } else {
205        return TokenStream::from(
206            syn::Error::new(
207                Span::call_site(),
208                "near macro can only be used on struct or enum definition and impl sections.",
209            )
210            .to_compile_error(),
211        );
212    }
213
214    TokenStream::from(expanded)
215}
216
217#[proc_macro_attribute]
218pub fn near_bindgen(attr: TokenStream, item: TokenStream) -> TokenStream {
219    if attr.to_string().contains("event_json") {
220        return core_impl::near_events(attr, item);
221    }
222
223    let generate_metadata = |ident: &Ident,
224                             generics: &syn::Generics|
225     -> Result<proc_macro2::TokenStream, proc_macro2::TokenStream> {
226        let metadata_impl_gen = generate_contract_metadata_method(ident, generics).into();
227
228        let metadata_impl_gen = syn::parse::<ItemImpl>(metadata_impl_gen)
229            .expect("failed to generate contract metadata");
230        process_impl_block(metadata_impl_gen)
231    };
232
233    if let Ok(input) = syn::parse::<ItemStruct>(item.clone()) {
234        let metadata = core_impl::contract_source_metadata_const(attr);
235
236        let metadata_impl_gen = generate_metadata(&input.ident, &input.generics);
237
238        let metadata_impl_gen = match metadata_impl_gen {
239            Ok(metadata) => metadata,
240            Err(err) => return err.into(),
241        };
242
243        let ext_gen = generate_ext_structs(&input.ident, Some(&input.generics));
244        #[cfg(feature = "__abi-embed-checked")]
245        let abi_embedded = abi::embed();
246        #[cfg(not(feature = "__abi-embed-checked"))]
247        let abi_embedded = quote! {};
248        TokenStream::from(quote! {
249            #input
250            #ext_gen
251            #abi_embedded
252            #metadata
253            #metadata_impl_gen
254        })
255    } else if let Ok(input) = syn::parse::<ItemEnum>(item.clone()) {
256        let metadata = core_impl::contract_source_metadata_const(attr);
257        let metadata_impl_gen = generate_metadata(&input.ident, &input.generics);
258
259        let metadata_impl_gen = match metadata_impl_gen {
260            Ok(metadata) => metadata,
261            Err(err) => return err.into(),
262        };
263
264        let ext_gen = generate_ext_structs(&input.ident, Some(&input.generics));
265        #[cfg(feature = "__abi-embed-checked")]
266        let abi_embedded = abi::embed();
267        #[cfg(not(feature = "__abi-embed-checked"))]
268        let abi_embedded = quote! {};
269        TokenStream::from(quote! {
270            #input
271            #ext_gen
272            #abi_embedded
273            #metadata
274            #metadata_impl_gen
275        })
276    } else if let Ok(input) = syn::parse::<ItemImpl>(item) {
277        for method in &input.items {
278            if let ImplItem::Fn(m) = method {
279                let ident = &m.sig.ident;
280                if ident.eq("__contract_abi") || ident.eq("contract_source_metadata") {
281                    return TokenStream::from(
282                        syn::Error::new_spanned(
283                            ident.to_token_stream(),
284                            "use of reserved contract method",
285                        )
286                        .to_compile_error(),
287                    );
288                }
289            }
290        }
291        match process_impl_block(input) {
292            Ok(output) => output,
293            Err(output) => output,
294        }
295        .into()
296    } else {
297        TokenStream::from(
298            syn::Error::new(
299                Span::call_site(),
300                "near_bindgen can only be used on struct or enum definition and impl sections.",
301            )
302            .to_compile_error(),
303        )
304    }
305}
306
307// This function deals with impl block processing, generating wrappers and ABI.
308//
309// # Arguments
310// * input - impl block to process.
311//
312// The Result has a TokenStream error type, because those need to be propagated to the compiler.
313fn process_impl_block(
314    mut input: ItemImpl,
315) -> Result<proc_macro2::TokenStream, proc_macro2::TokenStream> {
316    let item_impl_info = match ItemImplInfo::new(&mut input) {
317        Ok(x) => x,
318        Err(err) => return Err(err.to_compile_error()),
319    };
320
321    #[cfg(not(feature = "__abi-generate"))]
322    let abi_generated = quote! {};
323    #[cfg(feature = "__abi-generate")]
324    let abi_generated = abi::generate(&item_impl_info);
325
326    let generated_code = item_impl_info.wrapper_code();
327
328    // Add wrapper methods for ext call API
329    let ext_generated_code = item_impl_info.generate_ext_wrapper_code();
330
331    Ok(TokenStream::from(quote! {
332        #ext_generated_code
333        #input
334        #generated_code
335        #abi_generated
336    })
337    .into())
338}
339
340#[proc_macro_attribute]
341pub fn ext_contract(attr: TokenStream, item: TokenStream) -> TokenStream {
342    if let Ok(mut input) = syn::parse::<ItemTrait>(item) {
343        let mod_name: Option<proc_macro2::Ident> = if attr.is_empty() {
344            None
345        } else {
346            match syn::parse(attr) {
347                Ok(x) => x,
348                Err(err) => {
349                    return TokenStream::from(
350                        syn::Error::new(
351                            Span::call_site(),
352                            format!("Failed to parse mod name for ext_contract: {err}"),
353                        )
354                        .to_compile_error(),
355                    )
356                }
357            }
358        };
359        let item_trait_info = match ItemTraitInfo::new(&mut input, mod_name) {
360            Ok(x) => x,
361            Err(err) => return TokenStream::from(err.to_compile_error()),
362        };
363        let ext_api = item_trait_info.wrap_trait_ext();
364
365        TokenStream::from(quote! {
366            #input
367            #ext_api
368        })
369    } else {
370        TokenStream::from(
371            syn::Error::new(Span::call_site(), "ext_contract can only be used on traits")
372                .to_compile_error(),
373        )
374    }
375}
376
377#[cfg(feature = "abi")]
378#[derive(darling::FromDeriveInput, Debug)]
379#[darling(attributes(abi), forward_attrs(serde, borsh_skip, schemars, validate))]
380struct DeriveNearSchema {
381    attrs: Vec<syn::Attribute>,
382    json: Option<bool>,
383    borsh: Option<bool>,
384}
385
386#[proc_macro_derive(NearSchema, attributes(abi, serde, borsh, schemars, validate, inside_nearsdk))]
387pub fn derive_near_schema(#[allow(unused)] input: TokenStream) -> TokenStream {
388    #[cfg(not(feature = "abi"))]
389    {
390        TokenStream::from(quote! {})
391    }
392
393    #[cfg(feature = "abi")]
394    {
395        use darling::FromDeriveInput;
396
397        let derive_input = syn::parse_macro_input!(input as syn::DeriveInput);
398        let generics = derive_input.generics.clone();
399        let args = match DeriveNearSchema::from_derive_input(&derive_input) {
400            Ok(v) => v,
401            Err(e) => {
402                return TokenStream::from(e.write_errors());
403            }
404        };
405
406        if args.borsh.is_none()
407            && args.json.is_none()
408            && derive_input.clone().attrs.iter().any(|attr| attr.path().is_ident("abi"))
409        {
410            return TokenStream::from(
411                syn::Error::new_spanned(
412                    derive_input.to_token_stream(),
413                    "At least one of `json` or `borsh` inside of `#[abi(...)]` must be specified",
414                )
415                .to_compile_error(),
416            );
417        }
418
419        // #[abi(json, borsh)]
420        let (json_schema, borsh_schema) = (args.json.unwrap_or(false), args.borsh.unwrap_or(false));
421        let mut input = derive_input.clone();
422        input.attrs = args.attrs;
423
424        let strip_unknown_attr = |attrs: &mut Vec<syn::Attribute>| {
425            attrs.retain(|attr| {
426                ["serde", "schemars", "validate", "borsh"]
427                    .iter()
428                    .any(|&path| attr.path().is_ident(path))
429            });
430        };
431
432        match &mut input.data {
433            syn::Data::Struct(data) => {
434                for field in &mut data.fields {
435                    strip_unknown_attr(&mut field.attrs);
436                }
437            }
438            syn::Data::Enum(data) => {
439                for variant in &mut data.variants {
440                    strip_unknown_attr(&mut variant.attrs);
441                    for field in &mut variant.fields {
442                        strip_unknown_attr(&mut field.attrs);
443                    }
444                }
445            }
446            syn::Data::Union(_) => {
447                return TokenStream::from(
448                    syn::Error::new_spanned(
449                        input.to_token_stream(),
450                        "`NearSchema` does not support derive for unions",
451                    )
452                    .to_compile_error(),
453                )
454            }
455        }
456
457        let near_sdk_crate =
458            if derive_input.attrs.iter().any(|attr| attr.path().is_ident("inside_nearsdk")) {
459                quote! {crate}
460            } else {
461                quote! {::near_sdk}
462            };
463
464        // <unspecified> or #[abi(json)]
465        let json_schema = json_schema || !borsh_schema;
466
467        let derive = get_schema_derive(json_schema, borsh_schema, near_sdk_crate.clone(), true);
468
469        let input_ident = &input.ident;
470
471        let input_ident_proxy = quote::format_ident!("{}__NEAR_SCHEMA_PROXY", input_ident);
472
473        let json_impl = if json_schema {
474            let where_clause = get_where_clause(
475                &generics,
476                input_ident,
477                quote! {#near_sdk_crate::schemars::JsonSchema},
478            );
479            quote! {
480                #[automatically_derived]
481                impl #generics #near_sdk_crate::schemars::JsonSchema for #input_ident_proxy #generics #where_clause {
482                    fn schema_name() -> ::std::string::String {
483                        <#input_ident #generics as #near_sdk_crate::schemars::JsonSchema>::schema_name()
484                    }
485
486                    fn json_schema(gen: &mut #near_sdk_crate::schemars::gen::SchemaGenerator) -> #near_sdk_crate::schemars::schema::Schema {
487                        <#input_ident #generics as #near_sdk_crate::schemars::JsonSchema>::json_schema(gen)
488                    }
489                }
490            }
491        } else {
492            quote! {}
493        };
494
495        let borsh_impl = if borsh_schema {
496            let where_clause = get_where_clause(
497                &generics,
498                input_ident,
499                quote! {#near_sdk_crate::borsh::BorshSchema},
500            );
501            quote! {
502                #[automatically_derived]
503                impl #generics #near_sdk_crate::borsh::BorshSchema for #input_ident_proxy #generics #where_clause {
504                    fn declaration() -> #near_sdk_crate::borsh::schema::Declaration {
505                        <#input_ident #generics as #near_sdk_crate::borsh::BorshSchema>::declaration()
506                    }
507
508                    fn add_definitions_recursively(
509                        definitions: &mut #near_sdk_crate::borsh::__private::maybestd::collections::BTreeMap<
510                            #near_sdk_crate::borsh::schema::Declaration,
511                            #near_sdk_crate::borsh::schema::Definition
512                        >,
513                    ) {
514                        <#input_ident #generics as #near_sdk_crate::borsh::BorshSchema>::add_definitions_recursively(definitions);
515                    }
516                }
517            }
518        } else {
519            quote! {}
520        };
521
522        TokenStream::from(quote! {
523            #[cfg(not(target_arch = "wasm32"))]
524            const _: () = {
525                #[allow(non_camel_case_types)]
526                type #input_ident_proxy #generics = #input_ident #generics;
527                {
528                    #derive
529                    #[allow(dead_code)]
530                    #input
531
532                    #json_impl
533                    #borsh_impl
534                };
535            };
536        })
537    }
538}
539
540#[allow(dead_code)]
541fn get_schema_derive(
542    json_schema: bool,
543    borsh_schema: bool,
544    near_sdk_crate: proc_macro2::TokenStream,
545    need_borsh_crate: bool,
546) -> proc_macro2::TokenStream {
547    let string_borsh_crate = quote! {#near_sdk_crate::borsh}.to_string();
548    let string_schemars_crate = quote! {#near_sdk_crate::schemars}.to_string();
549
550    let mut derive = quote! {};
551    if borsh_schema {
552        derive = quote! {
553            #[cfg_attr(not(target_arch = "wasm32"), derive(#near_sdk_crate::borsh::BorshSchema))]
554        };
555        if need_borsh_crate {
556            derive = quote! {
557                #derive
558                #[cfg_attr(not(target_arch = "wasm32"), borsh(crate = #string_borsh_crate))]
559            };
560        }
561    }
562    if json_schema {
563        derive = quote! {
564            #derive
565            #[cfg_attr(not(target_arch = "wasm32"), derive(#near_sdk_crate::schemars::JsonSchema))]
566            #[cfg_attr(not(target_arch = "wasm32"), schemars(crate = #string_schemars_crate))]
567        };
568    }
569    derive
570}
571
572#[cfg(feature = "abi")]
573fn get_where_clause(
574    generics: &syn::Generics,
575    input_ident: &syn::Ident,
576    trait_name: proc_macro2::TokenStream,
577) -> WhereClause {
578    let (_, ty_generics, where_clause) = generics.split_for_impl();
579
580    let predicate = parse_quote!(#input_ident #ty_generics: #trait_name);
581
582    let where_clause: WhereClause = if let Some(mut w) = where_clause.cloned() {
583        w.predicates.push(predicate);
584        w
585    } else {
586        parse_quote!(where #predicate)
587    };
588    where_clause
589}
590
591#[proc_macro_derive(PanicOnDefault)]
592pub fn derive_no_default(item: TokenStream) -> TokenStream {
593    if let Ok(input) = syn::parse::<ItemStruct>(item) {
594        let name = &input.ident;
595        TokenStream::from(quote! {
596            impl ::std::default::Default for #name {
597                fn default() -> Self {
598                    ::near_sdk::env::panic_str("The contract is not initialized");
599                }
600            }
601        })
602    } else {
603        TokenStream::from(
604            syn::Error::new(
605                Span::call_site(),
606                "PanicOnDefault can only be used on type declarations sections.",
607            )
608            .to_compile_error(),
609        )
610    }
611}
612
613#[proc_macro_derive(BorshStorageKey)]
614pub fn borsh_storage_key(item: TokenStream) -> TokenStream {
615    let (name, generics) = if let Ok(input) = syn::parse::<ItemEnum>(item.clone()) {
616        (input.ident, input.generics)
617    } else if let Ok(input) = syn::parse::<ItemStruct>(item) {
618        (input.ident, input.generics)
619    } else {
620        return TokenStream::from(
621            syn::Error::new(
622                Span::call_site(),
623                "BorshStorageKey can only be used as a derive on enums or structs.",
624            )
625            .to_compile_error(),
626        );
627    };
628    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
629    let predicate = parse_quote!(#name #ty_generics: ::near_sdk::borsh::BorshSerialize);
630    let where_clause: WhereClause = if let Some(mut w) = where_clause.cloned() {
631        w.predicates.push(predicate);
632        w
633    } else {
634        parse_quote!(where #predicate)
635    };
636    TokenStream::from(quote! {
637        impl #impl_generics ::near_sdk::__private::BorshIntoStorageKey for #name #ty_generics #where_clause {}
638    })
639}
640
641#[proc_macro_derive(FunctionError)]
642pub fn function_error(item: TokenStream) -> TokenStream {
643    let name = if let Ok(input) = syn::parse::<ItemEnum>(item.clone()) {
644        input.ident
645    } else if let Ok(input) = syn::parse::<ItemStruct>(item) {
646        input.ident
647    } else {
648        return TokenStream::from(
649            syn::Error::new(
650                Span::call_site(),
651                "FunctionError can only be used as a derive on enums or structs.",
652            )
653            .to_compile_error(),
654        );
655    };
656    TokenStream::from(quote! {
657        impl ::near_sdk::FunctionError for #name {
658            fn panic(&self) -> ! {
659                ::near_sdk::env::panic_str(&::std::string::ToString::to_string(&self))
660            }
661        }
662    })
663}
664
665#[proc_macro_derive(EventMetadata, attributes(event_version))]
666pub fn derive_event_attributes(item: TokenStream) -> TokenStream {
667    if let Ok(input) = syn::parse::<ItemEnum>(item) {
668        let name = &input.ident;
669        // get `standard` const injected from `near_events`
670        let standard_name = format!("{name}_event_standard");
671        let standard_ident = syn::Ident::new(&standard_name, Span::call_site());
672        // version from each attribute macro
673        let mut event_meta: Vec<proc_macro2::TokenStream> = vec![];
674        for var in &input.variants {
675            if let Some(version) = core_impl::get_event_version(var) {
676                let var_ident = &var.ident;
677                event_meta.push(quote! {
678                    #name::#var_ident { .. } => {(::std::string::ToString::to_string(&#standard_ident), ::std::string::ToString::to_string(#version))}
679                })
680            } else {
681                return TokenStream::from(
682                    syn::Error::new(
683                        Span::call_site(),
684                        "Near events must have `event_version`. Must have a single string literal value.",
685                    )
686                    .to_compile_error(),
687                );
688            }
689        }
690
691        // handle lifetimes, generics, and where clauses
692        let (impl_generics, type_generics, where_clause) = &input.generics.split_for_impl();
693        // add `'near_event` lifetime for user defined events
694        let mut generics = input.generics.clone();
695        let event_lifetime = syn::Lifetime::new("'near_event", Span::call_site());
696        generics.params.insert(
697            0,
698            syn::GenericParam::Lifetime(syn::LifetimeParam::new(event_lifetime.clone())),
699        );
700        let (custom_impl_generics, ..) = generics.split_for_impl();
701
702        TokenStream::from(quote! {
703            impl #impl_generics #name #type_generics #where_clause {
704                pub fn emit(&self) {
705                    use ::std::string::String;
706
707                    let (standard, version): (String, String) = match self {
708                        #(#event_meta),*
709                    };
710
711                    #[derive(::near_sdk::serde::Serialize)]
712                    #[serde(crate="::near_sdk::serde")]
713                    #[serde(rename_all="snake_case")]
714                    struct EventBuilder #custom_impl_generics #where_clause {
715                        standard: String,
716                        version: String,
717                        #[serde(flatten)]
718                        event_data: &#event_lifetime #name #type_generics
719                    }
720                    let event = EventBuilder { standard, version, event_data: self };
721                    let json = ::near_sdk::serde_json::to_string(&event)
722                            .unwrap_or_else(|_| ::near_sdk::env::abort());
723                    ::near_sdk::env::log_str(&::std::format!("EVENT_JSON:{}", json));
724                }
725
726                pub fn to_json(&self) -> ::near_sdk::serde_json::Value {
727                    use ::std::string::String;
728
729                    let (standard, version): (String, String) = match self {
730                        #(#event_meta),*
731                    };
732
733                    #[derive(::near_sdk::serde::Serialize)]
734                    #[serde(crate="::near_sdk::serde")]
735                    #[serde(rename_all="snake_case")]
736                    struct EventBuilder #custom_impl_generics #where_clause {
737                        standard: String,
738                        version: String,
739                        #[serde(flatten)]
740                        event_data: &#event_lifetime #name #type_generics
741                    }
742                    let event = EventBuilder { standard, version, event_data: self };
743                    ::near_sdk::serde_json::to_value(&event)
744                        .unwrap_or_else(|_| ::near_sdk::env::abort())
745                }
746            }
747        })
748    } else {
749        TokenStream::from(
750            syn::Error::new(
751                Span::call_site(),
752                "EventMetadata can only be used as a derive on enums.",
753            )
754            .to_compile_error(),
755        )
756    }
757}