-
Notifications
You must be signed in to change notification settings - Fork 249
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
feat: near_abi!
macro
#831
Conversation
const _: () = { | ||
#[no_mangle] | ||
#[cfg(not(target_arch = "wasm32"))] | ||
pub fn __near_abi() -> near_sdk::__private::AbiRoot { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that this will fail to compile when there are multiple impl sections with near_bindgen
, right? Will double check tomorrow
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, it should not as long as all impl sections are wrapped in the same near_abi!
call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
didn't realize that case is handled. It limits the ability to have impl sections in diff modules, though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True. I am unsure how to handle this though... I have tried depending on modules like this:
#[near_abi]
mod abi {
#[path = "utility.rs"]
mod abi_utility;
#[near_bindgen]
#[derive(Default, BorshDeserialize, BorshSerialize)]
pub struct Contract {}
...
}
But apparently including non-inline modules in proc macro input is an unstable feature.
I was thinking I could maybe create a global state that would be modified by all #[near_abi]
annotations and then add another macro that would output the accumulated state into one ABI structure. The problem is that I think there is no way to enforce macro execution order. Do you have any ideas I could explore?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another very vague idea I have considered is to generate a bunch of symbols (e.g. __near_abi_lib_rs
, __near_abi_utility_rs
etc) and then somehow get a list of them from cargo extension and call all of them. The main problem here is that I cannot find if there is a rustc/cargo API that would allow me to list all symbols from a crate.
} | ||
|
||
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { | ||
T::json_schema(gen) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that right now nothing restricts a developer from having the promise return a different schema type than T
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I also thought about this. Returning different things feels like a strange pattern to me, but I guess since we are not discouraging this pattern I should not presume that there is only one possible return type. I could represent this as an equivalent of Either<Any, T>
or just simply Any
. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about a Result<T>
since this is looks to be fallible and we're expecting a type T
. Maybe not for this function, but another one for that can return a Result
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it is not really fallible as it is non-restrictive to just T
, so I don't think Result
suits unless I am missing something here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that making the assumption as one type is fine, it would nudge developers in the correct pattern, but I'm just making the comment so we don't ignore the cases where maybe someone might return different types that serialize as the same thing. Can't immediately think of an implication that would be an issue, though
Hmm, yeah either master becomes the 5.0 path and we backport non-breaking changes to some 4.x branch, or we put these changes into a branch that targets the main branch and only merge those commits in when we are ready to release the next version. Seems like maybe the first option might be cleaner, and then we can just cherry-pick commits when we want to release any 4.x branch. Might be more work, but seems okay |
Yeah sounds good to me. Do we want to put this macro and ABI models under unstable for now? |
} | ||
|
||
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { | ||
T::json_schema(gen) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about a Result<T>
since this is looks to be fallible and we're expecting a type T
. Maybe not for this function, but another one for that can return a Result
Yes, please. |
.attr_signature_info | ||
.args | ||
.iter() | ||
.filter(|arg| matches!(arg.bindgen_ty, BindgenArgType::CallbackArg)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This handles callback, but does not handle CallbackResultArg
. Am I missing something with this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, yeah, you are right. I took it from here: https://github.com/near/near-sdk-rs/blob/master/near-sdk-macros/src/core_impl/metadata/metadata_generator.rs#L69, so I guess the previous metadata implementation is not accounting for this case either. Should I fix it in a separate PR or do you think it is inconsequential at this point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it depends what we do with metadata, but my assumption is that it would be deprecated.
As for callback result, will this not have to be handled more specifically than ccfba2e
(#831) to ignore the wrapping Result
type in the schema?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, good catch. I have refactored the entire argument processing flow because it was getting out of hand, this case should be handled now.
near-sdk/src/lib.rs
Outdated
#[doc(hidden)] | ||
pub use schemars; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's just remove this altogether, re-exporting things like this is generally a bad pattern and the others would be purged if it wasn't very breaking of a change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noting again this would be ideal not to export and require that we keep this API stable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha, moved behind __private
for now since I can't figure out how to remove it
bc59ec3
to
ddc6824
Compare
@austinabell so after our last conversation I am not sure if it makes sense to leave |
no, if we are adding a feature, it should be something long-term because removing is unergonomic for anyone who specified it previously (breaking change). If you wanted it to be |
Makes sense, I am putting everything behind |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks generally good! Just a few small comments and should be good
/// If args are serialized with Borsh it will not include `#[derive(borsh::BorshSchema)]`. | ||
pub fn abi_struct(&self) -> TokenStream2 { | ||
let function_name_str = self.attr_signature_info.ident.to_string(); | ||
let is_view = matches!(&self.attr_signature_info.method_type, &MethodType::View); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that we should start thinking of ways to avoid false positives for this. The MethodType::View
is just used for codegen, but can't reliably indicate a function is view externally. Wonder if analysis of the wasm binary to see if any non-view functions are used (state write, promises) will be necessary.
This is probably fine for now, though. We should open an issue for this before or after this comes in
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, created an issue: #850
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, one thing I overlooked and then good
const _: () = { | ||
#[no_mangle] | ||
pub fn #near_abi_symbol() -> near_sdk::__private::AbiRoot { | ||
let mut gen = schemars::gen::SchemaGenerator::default(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should use the re-export from the SDK. Ideally behind a private module. This forces a developer to import schemars even if they don't use
This should be near_sdk::__private::schemars::
or near_sdk::schemars::
if that re-export is not moved from other comment
near-sdk/src/lib.rs
Outdated
#[doc(hidden)] | ||
pub use schemars; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noting again this would be ideal not to export and require that we keep this API stable
Basically just the macro and ABI models without all other extra stuff from
daniyar/aci
like cargo extension, cross contract calls etc.We have not decided in what branch this should live in, so I am targeting
master
for now.