Skip to content

Commit

Permalink
fix: add support for multiple event enums in the same file
Browse files Browse the repository at this point in the history
  • Loading branch information
coleFD committed Oct 31, 2022
1 parent 51b59cf commit 6eecebe
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 48 deletions.
8 changes: 4 additions & 4 deletions near-sdk-macros/src/core_impl/event/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use proc_macro2::Span;
use quote::quote;
use syn::{parse_quote, ItemEnum, LitStr};

/// this function is used to inject Serialization Macros and the `near_sdk::EventMetadata` macro.
/// this function is used to inject serialization macros and the `near_sdk::EventMetadata` macro.
/// In addition, this function extracts the event's `standard` value and injects it as a constant to be used by
/// the `near_sdk::EventMetadata` derive macro
pub(crate) fn near_events(attr: TokenStream, item: TokenStream) -> TokenStream {
Expand All @@ -13,7 +13,7 @@ pub(crate) fn near_events(attr: TokenStream, item: TokenStream) -> TokenStream {
return TokenStream::from(
syn::Error::new(
Span::call_site(),
"Near events must have a `standard` value as an argument for `events` in the `near_bindgen` arguments. The value must be a string literal.",
"Near events must have a `standard` value as an argument for `event_json` in the `near_bindgen` arguments. The value must be a string literal.",
)
.to_compile_error(),
);
Expand All @@ -39,7 +39,7 @@ pub(crate) fn near_events(attr: TokenStream, item: TokenStream) -> TokenStream {
TokenStream::from(
syn::Error::new(
Span::call_site(),
"`#[near_bindgen(events(standard = \"nepXXX\"))]` can only be used as an attribute on enums.",
"`#[near_bindgen(event_json(standard = \"nepXXX\"))]` can only be used as an attribute on enums.",
)
.to_compile_error(),
)
Expand All @@ -57,7 +57,7 @@ pub(crate) fn get_event_version(var: &syn::Variant) -> Option<LitStr> {
None
}

/// this function returns the `standard` value from `#[near_bindgen(events(standard = "nepXXX"))]`
/// this function returns the `standard` value from `#[near_bindgen(event_json(standard = "nepXXX"))]`
fn get_standard_arg(args: &[syn::NestedMeta]) -> Option<LitStr> {
let mut standard: Option<LitStr> = None;
for arg in args.iter() {
Expand Down
52 changes: 25 additions & 27 deletions near-sdk-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ use syn::{parse_quote, File, ItemEnum, ItemImpl, ItemStruct, ItemTrait, WhereCla
/// }
/// ```
#[proc_macro_attribute]
pub fn near_bindgen(_attr: TokenStream, item: TokenStream) -> TokenStream {
if _attr.to_string().contains("event_json") {
return core_impl::near_events(_attr, item);
pub fn near_bindgen(attr: TokenStream, item: TokenStream) -> TokenStream {
if attr.to_string().contains("event_json") {
return core_impl::near_events(attr, item);
}

if let Ok(input) = syn::parse::<ItemStruct>(item.clone()) {
Expand Down Expand Up @@ -360,7 +360,7 @@ pub fn function_error(item: TokenStream) -> TokenStream {
})
}

/// Adding the `events` argument for the `#[near_bindgen]` macro injects this derive macro and should be the used instead of this
/// NOTE: This is an internal implementation for `#[near_bindgen(events(standard = ...))]` attribute.
///
/// This derive macro is used to inject the necessary wrapper and logic to auto format
/// standard event logs. The other appropriate attribute macros are not injected with this macro.
Expand All @@ -378,62 +378,60 @@ pub fn function_error(item: TokenStream) -> TokenStream {
pub fn derive_event_attributes(item: TokenStream) -> TokenStream {
if let Ok(input) = syn::parse::<ItemEnum>(item) {
let name = &input.ident;
// build wrapper name
let wrapper_name = format!("{}EventBuilder", name);
let wrapper_ident = syn::Ident::new(&wrapper_name, Span::call_site());
// get `standard` const injected from `near_events`
let standard_name = format!("{}_event_standard", name);
let standard_ident = syn::Ident::new(&standard_name, Span::call_site());
// version from each attribute macro
let mut attr_error: u8 = 0;
let mut event_meta: Vec<proc_macro2::TokenStream> = vec![];
let _ = &input.variants.iter().for_each(|var| {
for var in &input.variants {
if let Some(version) = core_impl::get_event_version(var) {
let var_ident = &var.ident;
event_meta.push(quote! {
#name::#var_ident { .. } => {(#standard_ident.to_string(), #version.to_string())}
})
} else {
attr_error += 1;
return TokenStream::from(
syn::Error::new(
Span::call_site(),
"Near events must have `event_version`. Must have a single string literal value.",
)
.to_compile_error(),
);
}
});
}

// handle lifetimes, generics, and where clauses
let (impl_generics, type_generics, where_clause) = &input.generics.split_for_impl();
// add 'near_event lifetime for user defined events
// add `'near_event` lifetime for user defined events
let mut generics = input.generics.clone();
let event_lifetime = syn::Lifetime::new("'near_event", Span::call_site());
generics.params.insert(
generics.params.len(),
syn::GenericParam::Lifetime(syn::LifetimeDef::new(event_lifetime.clone())),
);
generics
.params
.insert(0, syn::GenericParam::Lifetime(syn::LifetimeDef::new(event_lifetime.clone())));
let (custom_impl_generics, ..) = generics.split_for_impl();

if attr_error > 0 {
return TokenStream::from(
syn::Error::new(
Span::call_site(),
"Near events must have `event_version`. Must have a single string literal value.",
)
.to_compile_error(),
);
}

TokenStream::from(quote! {

#[derive(near_sdk::serde::Serialize)]
#[serde(crate="near_sdk::serde")]
#[serde(rename_all="snake_case")]
struct EventBuilder #custom_impl_generics #where_clause {
struct #wrapper_ident #custom_impl_generics #where_clause {
standard: String,
version: String,
#[serde(flatten)]
event_data: &#event_lifetime #name #type_generics
}

impl #impl_generics near_sdk::EventJson for #name #type_generics #where_clause {
type EventString = String;
fn format(&self) -> Self::EventString {
type EventMessage = String;
fn format(&self) -> Self::EventMessage {
let (standard, version): (String, String) = match self {
#(#event_meta),*
};
let event = EventBuilder {standard, version, event_data: self };
let event = #wrapper_ident {standard, version, event_data: self };
near_sdk::serde_json::to_string(&event)
.unwrap_or_else(|_| near_sdk::env::abort())
}
Expand Down
46 changes: 29 additions & 17 deletions near-sdk/src/types/event.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pub trait EventJson {
type EventString: std::convert::AsRef<str>;
fn format(&self) -> Self::EventString;
type EventMessage: std::convert::AsRef<str>;
fn format(&self) -> Self::EventMessage;
fn emit(&self) {
crate::env::log_str(&format!("EVENT_JSON:{}", self.format().as_ref()));
}
Expand Down Expand Up @@ -41,6 +41,12 @@ pub mod tests {
LifetimeTestB(&'b str),
}

#[near_bindgen(event_json(standard = "another_standard"))]
pub enum AnotherEvent {
#[event_version("1.0.0")]
Test,
}

#[test]
fn test_json_emit() {
let token_in: AccountId = "wrap.near".parse().unwrap();
Expand All @@ -58,27 +64,33 @@ pub mod tests {

TestEvents::LifetimeTestB::<String>("lifetime_b").emit();

AnotherEvent::Test.emit();

let logs = get_logs();

assert!(
logs[0]
== r#"EVENT_JSON:{"standard":"test_standard","version":"1.0.0","event":"swap","data":{"token_in":"wrap.near","token_out":"test.near","amount_in":100,"amount_out":200,"test":"tst"}}"#
assert_eq!(
logs[0],
r#"EVENT_JSON:{"standard":"test_standard","version":"1.0.0","event":"swap","data":{"token_in":"wrap.near","token_out":"test.near","amount_in":100,"amount_out":200,"test":"tst"}}"#
);
assert_eq!(
logs[1],
r#"EVENT_JSON:{"standard":"test_standard","version":"2.0.0","event":"string_event","data":"string"}"#
);
assert!(
logs[1]
== r#"EVENT_JSON:{"standard":"test_standard","version":"2.0.0","event":"string_event","data":"string"}"#
assert_eq!(
logs[2],
r#"EVENT_JSON:{"standard":"test_standard","version":"3.0.0","event":"empty_event"}"#
);
assert!(
logs[2]
== r#"EVENT_JSON:{"standard":"test_standard","version":"3.0.0","event":"empty_event"}"#
assert_eq!(
logs[3],
r#"EVENT_JSON:{"standard":"test_standard","version":"4.0.0","event":"lifetime_test_a","data":"lifetime"}"#
);
assert!(
logs[3]
== r#"EVENT_JSON:{"standard":"test_standard","version":"4.0.0","event":"lifetime_test_a","data":"lifetime"}"#
assert_eq!(
logs[4],
r#"EVENT_JSON:{"standard":"test_standard","version":"5.0.0","event":"lifetime_test_b","data":"lifetime_b"}"#
);
assert!(
logs[4]
== r#"EVENT_JSON:{"standard":"test_standard","version":"5.0.0","event":"lifetime_test_b","data":"lifetime_b"}"#
assert_eq!(
logs[5],
r#"EVENT_JSON:{"standard":"another_standard","version":"1.0.0","event":"test"}"#
);
}
}

0 comments on commit 6eecebe

Please sign in to comment.