Unverified Commit 0f249fa4 authored by Hero Bird's avatar Hero Bird Committed by GitHub

ink abi v0.2 (#190)

* [abi] add some missing exports to ink_abi

* [abi] add missing docs

* [abi] replace vec![] with Vec::new()

* [abi] add ConstructorSpec + glue code

* [abi] add ConstructorSpecBuilder::done

* [abi] remove old DeployHandlerSpec

* [abi] bump derive_more version 0.14 -> 0.15

* [abi] move Missing struct above state module

* [abi] apply rust fmt

* [abi] add TypeSpec as a new wrapper around type with optional display names

* [abi] make EventParamSpec use new TypeSpec

* [abi] finish integrating the new TypeSpec into specification structs

* [abi] update abi_derive dependencies syn, quote and proc_macro to 1.0

* fix minor spelling in docs
Co-Authored-By: Andrew Jones's avatarAndrew Jones <ascjones@gmail.com>

* [abi] refactor ContractSpecBuilder

* [abi] apply rust fmt

* [lang] implement new ink_abi API for ink_lang

* [lang] apply rust fmt

* [lang] implement display name support

* [lang] adjust compile time tests to new ink_abi codegen
parent a0aac702
......@@ -15,7 +15,7 @@ include = ["/Cargo.toml", "src/**/*.rs", "/README.md", "/LICENSE"]
[dependencies]
serde = { version = "1.0", default-features = false, features = ["derive", "alloc"] }
derive_more = { version = "0.14", features = ["no_std"] }
derive_more = { version = "0.15", default-features = false, features = ["no_std"] }
ink_abi_derive = { version = "0.1.0", path = "derive", default-features = false, optional = true }
type-metadata = { git = "https://github.com/type-metadata/type-metadata.git", default-features = false, features = ["derive"] }
......
......@@ -11,9 +11,9 @@ readme = "../README.md"
proc-macro = true
[dependencies]
quote = "0.6"
syn = { version = "0.15", features = ["full"] }
proc-macro2 = "0.4"
quote = "1.0"
syn = { version = "1.0", features = ["full"] }
proc-macro2 = "1.0"
[features]
default = ["std"]
......
......@@ -35,13 +35,21 @@ pub use self::{
StorageLayout,
},
specs::{
ConstructorSpec,
ConstructorSpecBuilder,
ContractSpec,
DeploySpec,
ContractSpecBuilder,
DisplayName,
EventParamSpec,
EventParamSpecBuilder,
EventSpec,
EventSpecBuilder,
MessageParamSpec,
MessageParamSpecBuilder,
MessageSpec,
MessageSpecBuilder,
ReturnTypeSpec,
TypeSpec,
},
};
......@@ -52,6 +60,7 @@ use type_metadata::{
Registry,
};
/// An entire ink! project for ABI file generation purposes.
#[derive(Debug, Serialize)]
pub struct InkProject {
registry: Registry,
......@@ -62,6 +71,7 @@ pub struct InkProject {
}
impl InkProject {
/// Creates a new ink! project.
pub fn new<L, S>(layout: L, spec: S) -> Self
where
L: Into<StorageLayout>,
......
This diff is collapsed.
......@@ -71,10 +71,10 @@ fn generate_abi_mod_body(contract: &hir::Contract) -> TokenStream2 {
}
}
fn generate_abi_deploy_handler(contract: &hir::Contract) -> TokenStream2 {
let deploy_handler = &contract.on_deploy;
fn generate_abi_constructor(contract: &hir::Contract) -> TokenStream2 {
let constructor = &contract.on_deploy;
let args = deploy_handler
let args = constructor
.decl
.inputs
.iter()
......@@ -109,15 +109,19 @@ fn generate_abi_deploy_handler(contract: &hir::Contract) -> TokenStream2 {
}
};
let ty = &capt.ty;
let type_spec = generate_type_spec_code(ty);
quote! {
ink_abi::MessageParamSpec::new::<#ty>(#name)
ink_abi::MessageParamSpec::new(#name)
.of_type(#type_spec)
.done()
}
})
.collect::<Punctuated<_, Token![,]>>();
let docs = deploy_handler.docs().map(trim_doc_string);
let docs = constructor.docs().map(trim_doc_string);
quote! {
ink_abi::DeploySpec::new()
ink_abi::ConstructorSpec::new("on_deploy")
.selector(0)
.args(vec![
#(#args ,)*
])
......@@ -168,19 +172,23 @@ fn generate_abi_messages<'a>(
_ => unreachable!("encountered invalid argument syntax: the only allowed is `ident : type`"),
};
let ty = &capt.ty;
let type_spec = generate_type_spec_code(ty);
quote! {
ink_abi::MessageParamSpec::new::<#ty>(#name)
ink_abi::MessageParamSpec::new(#name)
.of_type(#type_spec)
.done()
}
});
let ret_type = match &message.sig.decl.output {
syn::ReturnType::Default => {
quote! {
ink_abi::ReturnTypeSpec::none()
ink_abi::ReturnTypeSpec::new(None)
}
}
syn::ReturnType::Type(_, ty) => {
let type_spec = generate_type_spec_code(ty);
quote! {
ink_abi::ReturnTypeSpec::new::<#ty>()
ink_abi::ReturnTypeSpec::new(#type_spec)
}
}
};
......@@ -202,6 +210,30 @@ fn generate_abi_messages<'a>(
})
}
fn generate_type_spec_code(ty: &syn::Type) -> TokenStream2 {
fn without_display_name(ty: &syn::Type) -> TokenStream2 {
quote! { ink_abi::TypeSpec::new::<#ty>() }
}
if let syn::Type::Path(type_path) = ty {
if type_path.qself.is_some() {
return without_display_name(ty)
}
let path = &type_path.path;
if path.segments.len() == 0 {
return without_display_name(ty)
}
let segs = path
.segments
.iter()
.map(|seg| seg.ident.to_string())
.collect::<Vec<_>>();
return quote! {
ink_abi::TypeSpec::with_name_segs::<#ty, _>(vec![#(#segs),*].into_iter().map(AsRef::as_ref))
}
}
without_display_name(ty)
}
fn generate_abi_events<'a>(
contract: &'a hir::Contract,
) -> impl Iterator<Item = TokenStream2> + 'a {
......@@ -211,8 +243,12 @@ fn generate_abi_events<'a>(
let name = &event_arg.ident;
let indexed = event_arg.is_indexed();
let ty = &event_arg.ty;
let type_spec = generate_type_spec_code(ty);
quote! {
ink_abi::EventParamSpec::new::<#ty>(stringify!(#name), #indexed)
ink_abi::EventParamSpec::new(stringify!(#name))
.of_type(#type_spec)
.indexed(#indexed)
.done()
}
});
let docs = event.docs().map(trim_doc_string);
......@@ -238,15 +274,15 @@ fn generate_abi_contract(contract: &hir::Contract) -> TokenStream2 {
// or allow for inner-attribute doc style within the `contract!` macro call.
let docs = quote! {};
let deploy_handler = generate_abi_deploy_handler(contract);
let constructor = generate_abi_constructor(contract);
let messages = generate_abi_messages(contract);
let events = generate_abi_events(contract);
quote! {
ink_abi::ContractSpec::new(#contract_name_lit)
.on_deploy(
#deploy_handler
)
.constructors(vec![
#constructor
])
.messages(vec![
#(#messages ,)*
])
......
......@@ -244,10 +244,12 @@ impl Contract {
}
Some(self_ty) => {
match self_ty {
ast::FnArg::SelfValue(_) | ast::FnArg::Captured(_) => bail!(
ast::FnArg::SelfValue(_) | ast::FnArg::Captured(_) => {
bail!(
self_ty,
"contract messages must operate on `&self` or `&mut self`"
),
)
}
_ => (),
}
}
......
......@@ -308,10 +308,13 @@ fn contract_compiles() {
pub fn ink_generate_abi() -> ink_abi::InkProject {
let contract = {
ink_abi::ContractSpec::new("CallCounter")
.on_deploy(ink_abi::DeploySpec::new()
.args(vec![])
.docs(vec![])
.done())
.constructors(vec![
ink_abi::ConstructorSpec::new("on_deploy")
.selector(0)
.args(vec![])
.docs(vec![])
.done()
])
.messages(vec![
ink_abi::MessageSpec::new("inc")
.selector(257544423u32)
......@@ -325,7 +328,7 @@ fn contract_compiles() {
"Also emits an event.",
])
.returns(
ink_abi::ReturnTypeSpec::none()
ink_abi::ReturnTypeSpec::new(None)
)
.done(),
ink_abi::MessageSpec::new("dec")
......@@ -339,25 +342,40 @@ fn contract_compiles() {
"",
"Also emits an event.",
])
.returns(ink_abi::ReturnTypeSpec::none())
.returns(ink_abi::ReturnTypeSpec::new(None))
.done(),
])
.events(vec![
ink_abi::EventSpec::new(stringify!(DecCalled))
.args(vec![
ink_abi::EventParamSpec::new::<u32>(stringify!(current), false),
ink_abi::EventParamSpec::new(stringify!(current))
.of_type(
ink_abi::TypeSpec::with_name_segs::<u32, _>(
vec!["u32"].into_iter().map(AsRef::as_ref)
)
)
.indexed(false)
.done(),
])
.docs(vec![
"Fires when the value is decremented.",
])
.done(),
ink_abi::EventSpec::new(stringify!(IncCalled))
.args(vec![ink_abi::EventParamSpec::new::<u32>(stringify!(current), false),
])
.docs(vec![
"Fires when the value is incremented.",
])
.done(),
.args(vec![
ink_abi::EventParamSpec::new(stringify!(current))
.of_type(
ink_abi::TypeSpec::with_name_segs::<u32, _>(
vec!["u32"].into_iter().map(AsRef::as_ref)
)
)
.indexed(false)
.done(),
])
.docs(vec![
"Fires when the value is incremented.",
])
.done(),
])
.docs(vec![])
.done()
......
......@@ -206,34 +206,40 @@ fn contract_compiles() {
pub fn ink_generate_abi() -> ink_abi::InkProject{
let contract = {
ink_abi::ContractSpec::new("Flipper")
.on_deploy(ink_abi::DeploySpec::new()
.args(vec![])
.docs(vec![
"The internal boolean is initialized with `true`.",
.constructors(vec![
ink_abi::ConstructorSpec::new("on_deploy")
.selector(0)
.args(vec![])
.docs(vec![
"The internal boolean is initialized with `true`.",
])
.done()
])
.done()
)
.messages(vec![
ink_abi::MessageSpec::new("flip")
.selector(970692492u32)
.mutates(true)
.args(vec![])
.docs(vec!["Flips the internal boolean.",])
.returns(ink_abi::ReturnTypeSpec::none())
.done(),
ink_abi::MessageSpec::new("get")
.selector(4266279973u32)
.mutates(false)
.args(vec![])
.docs(vec!["Returns the internal boolean.",])
.returns(
ink_abi::ReturnTypeSpec::new::<bool>()
)
.done(),
])
.events(vec![])
.docs(vec![])
.done()
.messages(vec![
ink_abi::MessageSpec::new("flip")
.selector(970692492u32)
.mutates(true)
.args(vec![])
.docs(vec!["Flips the internal boolean.",])
.returns(ink_abi::ReturnTypeSpec::new(None))
.done(),
ink_abi::MessageSpec::new("get")
.selector(4266279973u32)
.mutates(false)
.args(vec![])
.docs(vec!["Returns the internal boolean.",])
.returns(
ink_abi::ReturnTypeSpec::new(
ink_abi::TypeSpec::with_name_segs::<bool, _>(
vec!["bool"].into_iter().map(AsRef::as_ref)
)
)
)
.done(),
])
.events(vec![])
.docs(vec![])
.done()
};
let layout = {
unsafe {
......
......@@ -229,27 +229,41 @@ fn contract_compiles() {
pub fn ink_generate_abi() -> ink_abi::InkProject {
let contract = {
ink_abi::ContractSpec::new("Incrementer")
.on_deploy(ink_abi::DeploySpec::new()
.args(vec![
ink_abi::MessageParamSpec::new::<u32>("init_value"),
])
.docs(vec![
"Automatically called when the contract is deployed.",
])
.done()
)
.constructors(vec![
ink_abi::ConstructorSpec::new("on_deploy")
.selector(0)
.args(vec![
ink_abi::MessageParamSpec::new("init_value")
.of_type(
ink_abi::TypeSpec::with_name_segs::<u32, _>(
vec!["u32"].into_iter().map(AsRef::as_ref)
)
)
.done(),
])
.docs(vec![
"Automatically called when the contract is deployed.",
])
.done()
])
.messages(vec![
ink_abi::MessageSpec::new("inc")
.selector(257544423u32)
.mutates(true)
.args(vec![
ink_abi::MessageParamSpec::new::<u32>("by"),
ink_abi::MessageParamSpec::new("by")
.of_type(
ink_abi::TypeSpec::with_name_segs::<u32, _>(
vec!["u32"].into_iter().map(AsRef::as_ref)
)
)
.done(),
])
.docs(vec![
"Increments the internal counter.",
])
.returns(
ink_abi::ReturnTypeSpec::none()
ink_abi::ReturnTypeSpec::new(None)
)
.done(),
ink_abi::MessageSpec::new("get")
......@@ -260,21 +274,36 @@ fn contract_compiles() {
"Returns the internal counter.",
])
.returns(
ink_abi::ReturnTypeSpec::new::<u32>()
ink_abi::ReturnTypeSpec::new(
ink_abi::TypeSpec::with_name_segs::<u32, _>(
vec!["u32"].into_iter().map(AsRef::as_ref)
)
)
)
.done(),
ink_abi::MessageSpec::new("compare")
.selector(363906316u32)
.mutates(false)
.args(vec![ink_abi::MessageParamSpec::new::<u32>("x"),
])
.docs(vec![
"Returns `true` if `x` is greater than the internal value.",
])
.returns(
ink_abi::ReturnTypeSpec::new::<bool>()
)
.done(),
.args(vec![
ink_abi::MessageParamSpec::new("x")
.of_type(
ink_abi::TypeSpec::with_name_segs::<u32, _>(
vec!["u32"].into_iter().map(AsRef::as_ref)
)
)
.done(),
])
.docs(vec![
"Returns `true` if `x` is greater than the internal value.",
])
.returns(
ink_abi::ReturnTypeSpec::new(
ink_abi::TypeSpec::with_name_segs::<bool, _>(
vec!["bool"].into_iter().map(AsRef::as_ref)
)
)
)
.done(),
])
.events(vec![])
.docs(vec![])
......
......@@ -162,17 +162,19 @@ fn contract_compiles() {
pub fn ink_generate_abi() -> ink_abi::InkProject {
let contract = {
ink_abi::ContractSpec::new("Noop")
.on_deploy(ink_abi::DeploySpec::new()
.args(vec![])
.docs(vec![
"Does nothing to initialize itself.",
.constructors(vec![
ink_abi::ConstructorSpec::new("on_deploy")
.selector(0)
.args(vec![])
.docs(vec![
"Does nothing to initialize itself.",
])
.done()
])
.messages(vec![])
.events(vec![])
.docs(vec![])
.done()
)
.messages(vec![])
.events(vec![])
.docs(vec![])
.done()
};
let layout = {
unsafe {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment