Skip to content
This repository was archived by the owner on Jun 21, 2020. It is now read-only.

Ep 748 simplify pub interface #209

Merged
merged 16 commits into from
Sep 22, 2019
Merged

Conversation

reuvenpo
Copy link
Contributor

@reuvenpo reuvenpo commented Aug 27, 2019

rewritten eng_wasm_derive::pub_interface

  • Enabled usage of the #[pub_interface] annotation on impl Struct items
    as well as on trait items. When using the new form, the user may use whatever name they want
    for the struct. When using the trait version the name of the struct/enum implementing
    the methods was hardcoded as Contract, but is now customizable by passing the
    implementor name as an argument to the macro.
    (They can basically use any type they want now)
  • Added the following diagnostics to the macro invocation:
    (when any of these is detected, the user will see a useful error message)
    • The attribute was placed on an item which is not a trait or inherent impl
    • The trait or impl methods use the self receiver
    • Trait methods provided a default implementation (i understand that we
      wanted the users to define the implementations on the Contract struct)
    • Trait method with any additional attribute
    • Impl method with a #[no_mangle] attribute
    • Impl method with visibility which isn't private or pub
      (we don't want them defining pub(crate) or pub(in something) because
      that can be misleading in this context)
    • check that the constructor returns no value
    • check that when applied to an impl-item, the constructor is marked as pub
  • Fixed issue around parsing return values from contract methods where their
    amount was incorrectly calculated
  • When parsing of method inputs fails at runtime, the panic message now
    mentions the type and argument that caused the failure.
  • If an unknown method is called, the panic message mentions the name of
    that method.
  • Using the macro no longer requires writing use eng_wasm::*; in the using
    module
  • restructured the module layout to make it easier to follow.
  • added unittests
  • documented a lot of things

The ERC20 example now generates the following code:
https://gist.github.com/rust-play/d9e375f7a587725be238ced968630d28
EDIT:
https://gist.github.com/rust-play/4a1da16589b738ee2f206d351dfd4c84

@reuvenpo
Copy link
Contributor Author

reuvenpo commented Aug 27, 2019

I'll point out that this code relies on the order of evaluation of function arguments, which is unspecified:
https://www.reddit.com/r/rust/comments/cw0kyd/is_the_order_of_evaluation_of_function_arguments/
but is never going to change from left-to-right:
https://internals.rust-lang.org/t/rust-expression-order-of-evaluation/2605/29
and will be documented as such at some point:
rust-lang/reference#248

EDIT: I removed this dependency anyways, it was fairly easy :)

@moriaab moriaab closed this Sep 2, 2019
@moriaab moriaab reopened this Sep 2, 2019
@reuvenpo reuvenpo force-pushed the EP-748-simplify-pub_interface branch from cfee76b to ef068a1 Compare September 2, 2019 09:08
@@ -0,0 +1,9 @@
pub trait IntoIdent {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice addition!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realised this is probably why it isn't made to be as easy to use as i made it:
https://docs.rs/quote/1.0.2/quote/macro.format_ident.html#panics

@@ -1,333 +1,49 @@
#![deny(unused_extern_crates)]
Copy link
Contributor

@moriaab moriaab Sep 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice cleaning of attributes and dependencies :-)

use super::into_ident::IntoIdent;
use parse_signatures::PubInterfaceSignatures;

const DEFAULT_IMPLEMENTOR_NAME: &str = "Contract";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent addition of definition and work with string constants here!

@@ -0,0 +1,600 @@
//! This module defines the parsing of input for the `#[pub_interface]` macro
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parse_signatures.rs code sets high standards :) Excellent work!

// pwasm_abi/derive/src/lib.rs :: fn generate_eth_endpoint
// which dictates how return values are serialised into the Sink.
// This can be 0 is the return type is () which is correct.
syn::ReturnType::Type(_, box syn::Type::Tuple(return_tuple)) => return_tuple.elems.len(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing catch and fix here!

@@ -0,0 +1 @@
# override global formatting. i want clean and standard runstfmt.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Th project directory contains a fustfmt configuration file with a lot of unusual settings (e.g. line length of 135?). i believe we should use the standard rustfmt settings, so at least for this directory i override the current global settings. i propose to remove the project-wide rustfmt configuration and reformat the project with the standard formatter.

If we keep this, I need to add a newline here

[dependencies]
eng-wasm = { version = "0.1.3", path = "../" }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note that this dependency is both unnecessary, and causes a future compatibility issue. I would like to create a dependency from eng-wasm to eng-wasm-derive so that we can reexport pub_interface from eng-wasm directly (and remove the requirement to depend on eng-wasm-derive directly. This can not happen without bumping the version of eng-wasm to 0.2 as it will not be compatible with older versions of eng-wasm-derive which depend on eng-wasm

[lib]
proc-macro = true
[dev-dependencies]
syn = { version = "1.0", features = ["full", "extra-traits"] }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use the extra-traits feature for printing and comparisons of AST objects

@@ -0,0 +1,9 @@
pub trait IntoIdent {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is fairly self-explanatory, but if not i can add a docstring. i'm surprised this is not implemented upstream, so we can file a pull request with this to https://github.com/dtolnay/syn

@@ -0,0 +1,9 @@
pub trait IntoIdent {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realised this is probably why it isn't made to be as easy to use as i made it:
https://docs.rs/quote/1.0.2/quote/macro.format_ident.html#panics

@reuvenpo reuvenpo force-pushed the EP-748-simplify-pub_interface branch from 5766b3d to b3a0a9a Compare September 9, 2019 12:07
}
}

/// This function checks if the function has a non-unit return type.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work! It is so easy to miss the distinction between empty tuple and no return type.

Copy link
Contributor

@moriaab moriaab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR improves eng-wasm-derive crate significantly in all aspects. Well done!

* Enabled usage of the \#[pub_interface] annotation on `impl Struct` items
  as well as on trait items. When using the trait version the name of the
  struct/enum implementing the methods was (and still is) hardcoded as
  `Contract`. When using the new form, the user may use whatever name they want
  for the struct. It has no side-effects.
  (They can theoretically use any type they want now)
* Added the following diagnostics to the macro invocation:
  (when any of these is detected, the user will see a useful error message)
    * The attribute was placed on an item which is not a trait or inherent impl
    * The trait or impl methods use the `self` receiver
    * Trait methods provided a default implementation (i understand that we
      wanted the users to define the implementations on the `Contract` struct)
    * Trait method with any additional attribute
    * Impl method with a \#[no_mangle] attribute
    * Impl method with visibility which isn't private or `pub`
      (we don't want them defining `pub(crate)` or `pub(in something)` because
      that can be misleading in this context)
* Fixed issue around parsing return values from contract methods where their
  amount was incorrectly calculated
* When parsing of method inputs fails at runtime, the panic message now
  mentions the type and argument that caused the failure.
* If an unknown method is called, the panic message mentions the name of
  that method.
* Using the contract no longer requires writing `use eng_wasm::*;` in the using
  module
* restructured the module layout to make it easier to follow.
* added unittests
* documented a lot of things

The ERC20 example now generates the following code:
https://gist.github.com/rust-play/d9e375f7a587725be238ced968630d28
…mplementing Display on `eng-wasm-derive::pub_interface::parse_signatures::ParseError`
* added check that the constructor returns no value
* added check that when applied to an impl-item, the constructor is marked as `pub`
… macro

* If applied to a trait, the tokens are interpreted as the type that
  implements the trait (this affects code generation, which otherwise
  assumed the implementor was named `Contract`)
* If applied to an impl, and there are extra `attr` tokens, an error is issued.
…n pub_interface

Also slightly improved the generated code for dispatches to contract functions that
do not take arguments.
@reuvenpo reuvenpo force-pushed the EP-748-simplify-pub_interface branch from b35216c to 39cc487 Compare September 18, 2019 11:42
… fn signature\n\npreviously they accidentally pointed to the missing pub token
… written back

Previously the code was removed in case of error, which caused weird "missing function"
errors after macro evaluation
fn expand(input: u32) -> u64;
}

impl MyContract for MyContractImplementation {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would maybe add impl MyContract for another structure in addition, just to emphasize the point of the argument to pub_interface. But it is up to you.

@reuvenpo reuvenpo merged commit cfe501e into develop Sep 22, 2019
@Cashmaney Cashmaney deleted the EP-748-simplify-pub_interface branch December 5, 2019 13:15
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants