Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: use attr sig info in abi generator #1036

Merged
merged 7 commits into from
Jun 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
358 changes: 284 additions & 74 deletions near-sdk-macros/src/core_impl/abi/abi_generator.rs

Large diffs are not rendered by default.

31 changes: 28 additions & 3 deletions near-sdk-macros/src/core_impl/code_generator/attr_sig_info.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,40 @@
use proc_macro2::TokenStream as TokenStream2;

use crate::core_impl::info_extractor::{ArgInfo, AttrSigInfoV2, BindgenArgType, SerializerType};
use crate::core_impl::utils;
use crate::core_impl::info_extractor::{ArgInfo, AttrSigInfo, BindgenArgType, SerializerType};
use crate::core_impl::{utils, MethodKind};
use quote::quote;

impl AttrSigInfoV2 {
impl AttrSigInfo {
/// Whether the signature has function arguments.
pub fn has_input_args(&self) -> bool {
self.input_args().next().is_some()
}

/// Whether the method has `payable` attribute.
/// Only available when `__abi-generate` feature is enabled as it's only in the abi generator
/// currently.
#[cfg(feature = "__abi-generate")]
pub fn is_payable(&self) -> bool {
use MethodKind::*;

match &self.method_kind {
Call(call_method) => call_method.is_payable,
Init(init_method) => init_method.is_payable,
View(_) => false,
}
}

/// Whether the method has `private` attribute.
pub fn is_private(&self) -> bool {
use MethodKind::*;

match &self.method_kind {
Call(call_method) => call_method.is_private,
Init(_) => false,
View(view_method) => view_method.is_private,
}
}

pub fn input_struct_ser(&self) -> TokenStream2 {
let args: Vec<_> = self.input_args().collect();
assert!(
Expand Down
8 changes: 4 additions & 4 deletions near-sdk-macros/src/core_impl/code_generator/ext.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::core_impl::{serializer, AttrSigInfoV2};
use crate::core_impl::{serializer, AttrSigInfo};
use proc_macro2::{Ident, Span, TokenStream as TokenStream2};
use quote::{format_ident, quote, ToTokens};
use syn::{parse_quote, Attribute, Generics, Path, Signature};
Expand Down Expand Up @@ -97,7 +97,7 @@ fn is_fn_attribute_to_forward(attribute: &Attribute) -> bool {
/// Generate methods on <StructName>Ext to enable calling each method.
pub(crate) fn generate_ext_function_wrappers<'a>(
ident: &Ident,
methods: impl IntoIterator<Item = &'a AttrSigInfoV2>,
methods: impl IntoIterator<Item = &'a AttrSigInfo>,
) -> TokenStream2 {
let ext_ident = format_ident!("{}Ext", ident);
let mut res = TokenStream2::new();
Expand All @@ -111,12 +111,12 @@ pub(crate) fn generate_ext_function_wrappers<'a>(
}
}

fn generate_ext_function(attr_signature_info: &AttrSigInfoV2) -> TokenStream2 {
fn generate_ext_function(attr_signature_info: &AttrSigInfo) -> TokenStream2 {
let pat_type_list = attr_signature_info.pat_type_list();
let serialize =
serializer::generate_serializer(attr_signature_info, &attr_signature_info.input_serializer);

let AttrSigInfoV2 { non_bindgen_attrs, ident, original_sig, .. } = attr_signature_info;
let AttrSigInfo { non_bindgen_attrs, ident, original_sig, .. } = attr_signature_info;
let ident_str = ident.to_string();
let mut new_non_bindgen_attrs = TokenStream2::new();
for attribute in non_bindgen_attrs.iter() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,36 +171,15 @@ impl ImplItemMethodInfo {
}

fn private_check_tokens(&self) -> TokenStream2 {
use MethodKind::*;

let reject_cross_call = || {
if self.attr_signature_info.is_private() {
let error = format!("Method {} is private", self.attr_signature_info.ident);
quote! {
if near_sdk::env::current_account_id() != near_sdk::env::predecessor_account_id() {
near_sdk::env::panic_str(#error);
}
}
};

match &self.attr_signature_info.method_kind {
Call(call_method) => {
if call_method.is_private {
reject_cross_call()
} else {
quote! {}
}
}

// Init methods cannot be private.
Init(_) => quote! {},

View(view_method) => {
if view_method.is_private {
reject_cross_call()
} else {
quote! {}
}
}
} else {
quote! {}
}
}

Expand Down
4 changes: 2 additions & 2 deletions near-sdk-macros/src/core_impl/code_generator/serializer.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::core_impl::info_extractor::{AttrSigInfoV2, SerializerType};
use crate::core_impl::info_extractor::{AttrSigInfo, SerializerType};
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;

pub fn generate_serializer(
attr_sig_info: &AttrSigInfoV2,
attr_sig_info: &AttrSigInfo,
serializer: &SerializerType,
) -> TokenStream2 {
let has_input_args = attr_sig_info.input_args().next().is_some();
Expand Down
2 changes: 0 additions & 2 deletions near-sdk-macros/src/core_impl/info_extractor/arg_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use proc_macro2::{Span, TokenStream};
use quote::ToTokens;
use syn::{spanned::Spanned, Attribute, Error, Ident, Pat, PatType, Token, Type};

#[derive(Clone)]
pub enum BindgenArgType {
/// Argument that we read from `env::input()`.
Regular,
Expand All @@ -17,7 +16,6 @@ pub enum BindgenArgType {
}

/// A single argument of a function after it was processed by the bindgen.
#[derive(Clone)]
pub struct ArgInfo {
/// Attributes not related to bindgen.
pub non_bindgen_attrs: Vec<Attribute>,
Expand Down
97 changes: 5 additions & 92 deletions near-sdk-macros/src/core_impl/info_extractor/attr_sig_info.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
use super::visitor::Visitor;
use super::{
ArgInfo, BindgenArgType, InitAttr, MethodKind, MethodType, ReturnKind, SerializerAttr,
SerializerType,
};
use super::{ArgInfo, BindgenArgType, InitAttr, MethodKind, SerializerAttr, SerializerType};
use crate::core_impl::{utils, Returns};
use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::ToTokens;
use syn::spanned::Spanned;
use syn::{Attribute, Error, FnArg, GenericParam, Ident, Receiver, ReturnType, Signature, Type};
use syn::{Attribute, Error, FnArg, GenericParam, Ident, ReturnType, Signature, Type};

/// Information extracted from method attributes and signature.
#[derive(Clone)]
pub struct AttrSigInfoV2 {
pub struct AttrSigInfo {
/// The name of the method.
pub ident: Ident,
/// Attributes not related to bindgen.
Expand All @@ -28,90 +24,7 @@ pub struct AttrSigInfoV2 {
pub original_sig: Signature,
}

/// Information extracted from method attributes and signature.
pub struct AttrSigInfoV1 {
/// The name of the method.
pub ident: Ident,
/// Attributes not related to bindgen.
pub non_bindgen_attrs: Vec<Attribute>,
/// All arguments of the method.
pub args: Vec<ArgInfo>,
/// Describes the type of the method.
pub method_type: MethodType,
/// Whether method accepting $NEAR.
pub is_payable: bool,
/// Whether method can accept calls from self (current account)
pub is_private: bool,
/// Whether method returns Result type where only Ok type is serialized
pub is_handles_result: bool,
/// The serializer that we use for `env::input()`.
pub input_serializer: SerializerType,
/// The serializer that we use for the return type.
pub result_serializer: SerializerType,
/// The receiver, like `mut self`, `self`, `&mut self`, `&self`, or `None`.
pub receiver: Option<Receiver>,
/// What this function returns.
pub returns: ReturnType,
/// The original method signature.
pub original_sig: Signature,
}

// FIXME: Remove once we refactor ABI generator to use `AttrSigInfoV2`
// Tracking issue: https://github.com/near/near-sdk-rs/issues/1032
impl From<AttrSigInfoV2> for AttrSigInfoV1 {
fn from(info: AttrSigInfoV2) -> Self {
match info.method_kind {
MethodKind::Call(call_method) => AttrSigInfoV1 {
ident: info.ident,
non_bindgen_attrs: info.non_bindgen_attrs,
args: info.args,
method_type: MethodType::Regular,
is_payable: call_method.is_payable,
is_private: call_method.is_private,
is_handles_result: matches!(info.returns.kind, ReturnKind::HandlesResult { .. }),
input_serializer: info.input_serializer,
result_serializer: call_method.result_serializer,
receiver: call_method.receiver,
returns: info.returns.original,
original_sig: info.original_sig,
},
MethodKind::View(view_method) => AttrSigInfoV1 {
ident: info.ident,
non_bindgen_attrs: info.non_bindgen_attrs,
args: info.args,
method_type: MethodType::View,
is_payable: false,
is_private: view_method.is_private,
is_handles_result: matches!(info.returns.kind, ReturnKind::HandlesResult { .. }),
input_serializer: info.input_serializer,
result_serializer: view_method.result_serializer,
receiver: view_method.receiver,
returns: info.returns.original,
original_sig: info.original_sig,
},
MethodKind::Init(init_method) => AttrSigInfoV1 {
ident: info.ident,
non_bindgen_attrs: info.non_bindgen_attrs,
args: info.args,
method_type: if init_method.ignores_state {
MethodType::InitIgnoreState
} else {
MethodType::Init
},
is_payable: init_method.is_payable,
is_private: false,
is_handles_result: matches!(info.returns.kind, ReturnKind::HandlesResult { .. }),
input_serializer: info.input_serializer,
result_serializer: SerializerType::JSON,
receiver: None,
returns: info.returns.original,
original_sig: info.original_sig,
},
}
}
}

impl AttrSigInfoV2 {
impl AttrSigInfo {
/// Apart from replacing `Self` types with their concretions, returns spans of all `Self` tokens found.
fn sanitize_self(
original_sig: &mut Signature,
Expand Down Expand Up @@ -235,7 +148,7 @@ impl AttrSigInfoV2 {
//
}

let mut result = AttrSigInfoV2 {
let mut result = AttrSigInfo {
ident,
non_bindgen_attrs,
args,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use crate::core_impl::info_extractor::AttrSigInfoV2;
use crate::core_impl::info_extractor::AttrSigInfo;
use crate::core_impl::utils;
use quote::ToTokens;
use syn::{ImplItemMethod, Type, Visibility};

/// Information extracted from `ImplItemMethod`.
pub struct ImplItemMethodInfo {
/// Information on the attributes and the signature of the method.
pub attr_signature_info: AttrSigInfoV2,
pub attr_signature_info: AttrSigInfo,
/// The type of the contract struct.
pub struct_type: Type,
}
Expand All @@ -21,8 +21,7 @@ impl ImplItemMethodInfo {
let ImplItemMethod { attrs, sig, .. } = original;
utils::sig_is_supported(sig)?;
if is_trait_impl || matches!(original.vis, Visibility::Public(_)) {
let attr_signature_info =
AttrSigInfoV2::new(attrs, sig, &struct_type.to_token_stream())?;
let attr_signature_info = AttrSigInfo::new(attrs, sig, &struct_type.to_token_stream())?;
Ok(Some(Self { attr_signature_info, struct_type }))
} else {
Ok(None)
Expand Down
11 changes: 1 addition & 10 deletions near-sdk-macros/src/core_impl/info_extractor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ mod arg_info;
pub use arg_info::{ArgInfo, BindgenArgType};

mod attr_sig_info;
pub use attr_sig_info::{AttrSigInfoV1, AttrSigInfoV2};
pub use attr_sig_info::AttrSigInfo;

mod impl_item_method_info;
pub use impl_item_method_info::ImplItemMethodInfo;
Expand Down Expand Up @@ -35,15 +35,6 @@ pub enum SerializerType {
Borsh,
}

/// Type of the method.
#[derive(PartialEq, Eq)]
pub enum MethodType {
Regular,
View,
Init,
InitIgnoreState,
}

#[derive(Clone, PartialEq, Eq)]
pub enum MethodKind {
Call(CallMethod),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::AttrSigInfoV2;
use super::AttrSigInfo;
use crate::core_impl::utils;
use proc_macro2::TokenStream as TokenStream2;
use syn::spanned::Spanned;
Expand All @@ -7,7 +7,7 @@ use syn::{Error, LitStr, TraitItemMethod};
/// Information extracted from trait method.
pub struct TraitItemMethodInfo {
/// Attributes and signature information.
pub attr_sig_info: AttrSigInfoV2,
pub attr_sig_info: AttrSigInfo,
/// The original AST of the trait item method.
pub original: TraitItemMethod,
/// String representation of method name, e.g. `"my_method"`.
Expand All @@ -28,7 +28,7 @@ impl TraitItemMethodInfo {
let TraitItemMethod { attrs, sig, .. } = original;

utils::sig_is_supported(sig)?;
let attr_sig_info = AttrSigInfoV2::new(attrs, sig, trait_name)?;
let attr_sig_info = AttrSigInfo::new(attrs, sig, trait_name)?;

let ident_byte_str =
LitStr::new(&attr_sig_info.ident.to_string(), attr_sig_info.ident.span());
Expand Down