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

Have #[handle_result] support Result types regardless of how they're referred to #1057

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
12 changes: 8 additions & 4 deletions near-sdk-macros/src/core_impl/abi/abi_generator.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::{format_ident, quote};
use syn::{Attribute, Lit::Str, Meta::NameValue, MetaNameValue, Type};
use syn::{parse_quote, Attribute, Lit::Str, Meta::NameValue, MetaNameValue, Type};

use crate::core_impl::{
utils, BindgenArgType, ImplItemMethodInfo, ItemImplInfo, MethodKind, ReturnKind, SerializerType,
Expand Down Expand Up @@ -202,7 +202,11 @@ impl ImplItemMethodInfo {
match &self.attr_signature_info.returns.kind {
Default => quote! { None },
General(ty) => self.abi_result_tokens_with_return_value(ty),
HandlesResult { ok_type } => self.abi_result_tokens_with_return_value(ok_type),
HandlesResult { ty } => {
// extract the `Ok` type from the result
let ty = parse_quote! { <#ty as near_sdk::__private::ResultTypeExt>::Okay };
self.abi_result_tokens_with_return_value(&ty)
}
}
}

Expand Down Expand Up @@ -329,7 +333,7 @@ mod tests {
callbacks: vec![],
callbacks_vec: None,
result: Some(near_sdk::__private::AbiType::Json {
type_schema: gen.subschema_for::<IsOk>(),
type_schema: gen.subschema_for::< <Result<IsOk, Error> as near_sdk::__private::ResultTypeExt>::Okay>(),
uint marked this conversation as resolved.
Show resolved Hide resolved
})
}
};
Expand Down Expand Up @@ -366,7 +370,7 @@ mod tests {
callbacks: vec![],
callbacks_vec: None,
result: Some(near_sdk::__private::AbiType::Borsh {
type_schema: <IsOk as near_sdk::borsh::BorshSchema>::schema_container(),
type_schema: < <Result<IsOk, Error> as near_sdk::__private::ResultTypeExt>::Okay as near_sdk::borsh::BorshSchema>::schema_container(),
})
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,6 @@ mod tests {
assert!(matches!(actual, ReturnType::Type(_, ty) if ty.as_ref() == &expected));
}

#[test]
fn handle_result_incorrect_return_type() {
uint marked this conversation as resolved.
Show resolved Hide resolved
let impl_type: Type = syn::parse_str("Hello").unwrap();
let mut method: ImplItemMethod = parse_quote! {
#[handle_result]
pub fn method(&self) -> &'static str { }
};
let actual = ImplItemMethodInfo::new(&mut method, false, impl_type).map(|_| ()).unwrap_err();
let expected = "Function marked with #[handle_result] should return Result<T, E> (where E implements FunctionError).";
assert_eq!(expected, actual.to_string());
}

#[test]
fn handle_result_without_marker() {
let impl_type: Type = syn::parse_str("Hello").unwrap();
Expand Down
2 changes: 1 addition & 1 deletion near-sdk-macros/src/core_impl/info_extractor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,5 @@ pub struct Returns {
pub enum ReturnKind {
Default,
General(Type),
HandlesResult { ok_type: Type },
HandlesResult { ty: Type },
uint marked this conversation as resolved.
Show resolved Hide resolved
}
9 changes: 1 addition & 8 deletions near-sdk-macros/src/core_impl/info_extractor/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,14 +209,7 @@ fn is_view(sig: &Signature) -> bool {

fn parse_return_kind(typ: &Type, handles_result: bool) -> syn::Result<ReturnKind> {
if handles_result {
if let Some(ok_type) = utils::extract_ok_type(typ) {
Ok(ReturnKind::HandlesResult { ok_type: ok_type.clone() })
} else {
Err(Error::new(
uint marked this conversation as resolved.
Show resolved Hide resolved
typ.span(),
"Function marked with #[handle_result] should return Result<T, E> (where E implements FunctionError).",
))
}
Ok(ReturnKind::HandlesResult { ty: typ.clone() })
} else if utils::type_is_result(typ) {
Err(Error::new(
typ.span(),
Expand Down
1 change: 1 addition & 0 deletions near-sdk/compilation_tests/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ fn compilation_tests() {
t.compile_fail("compilation_tests/generic_function.rs");
t.compile_fail("compilation_tests/generic_const_function.rs");
t.pass("compilation_tests/self_support.rs");
t.pass("compilation_tests/handle_result_alias.rs");
// The following couple tests should be activated before releasing 5.0
// See: https://github.com/near/near-sdk-rs/issues/1005
//
Expand Down
20 changes: 20 additions & 0 deletions near-sdk/compilation_tests/handle_result_alias.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use borsh::{BorshDeserialize, BorshSerialize};
use near_sdk::near_bindgen;

type MyResult = Result<u32, &'static str>;

#[near_bindgen]
#[derive(Default, BorshDeserialize, BorshSerialize)]
struct Contract {
value: u32,
}

#[near_bindgen]
impl Contract {
#[handle_result]
pub fn fun(&self) -> MyResult {
Err("error")
}
}

fn main() {}
3 changes: 3 additions & 0 deletions near-sdk/src/private/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ pub use schemars;
mod metadata;
pub use metadata::{Metadata, MethodMetadata};

mod result_type_ext;
pub use result_type_ext::ResultTypeExt;

use crate::IntoStorageKey;
use borsh::BorshSerialize;

Expand Down
17 changes: 17 additions & 0 deletions near-sdk/src/private/result_type_ext.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
pub trait ResultTypeExt: seal::ResultTypeExtSeal {
type Okay;
type Error;
}

impl<T, E> ResultTypeExt for Result<T, E> {
type Okay = T;
type Error = E;
}

// This is the "sealed trait" pattern:
// https://rust-lang.github.io/api-guidelines/future-proofing.html
mod seal {
pub trait ResultTypeExtSeal {}

impl<T, E> ResultTypeExtSeal for Result<T, E> {}
}