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

feat: use doc strings from the abi in abigen #1390

Merged
merged 3 commits into from
May 27, 2024
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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ bytes = { version = "1.5.0", default-features = false }
chrono = "0.4.31"
elliptic-curve = { version = "0.13.8", default-features = false }
eth-keystore = "0.5.0"
fuel-abi-types = "0.5.0"
fuel-abi-types = "0.5.2"
futures = "0.3.29"
hex = { version = "0.4.3", default-features = false }
itertools = "0.12.0"
Expand Down
2 changes: 2 additions & 0 deletions e2e/sway/contracts/contract_test/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ impl TestContract for Contract {
value
}

/// This method will read the counter from storage, increment it
/// and write the incremented value to storage
#[storage(read, write)]
fn increment_counter(value: u64) -> u64 {
let new_value = read::<u64>(COUNTER_KEY, 0).unwrap_or(0) + value;
Expand Down
1 change: 1 addition & 0 deletions e2e/sway/scripts/basic_script/src/main.sw
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
script;

/// Compares a to b and returns a `str[5]`
fn main(a: u64, b: u32) -> str[5] {
if a < b.as_u64() {
let my_string: str[5] = __to_str_array("hello");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,7 @@ fn expand_functions(functions: &[FullABIFunction]) -> Result<TokenStream> {
pub(crate) fn expand_fn(abi_fun: &FullABIFunction) -> Result<TokenStream> {
let mut generator = FunctionGenerator::new(abi_fun)?;

generator.set_doc(format!(
"Calls the contract's `{}` function",
abi_fun.name(),
));
generator.set_docs(abi_fun.doc_strings()?);

let original_output = generator.output_type();
generator.set_output_type(
Expand Down Expand Up @@ -189,15 +186,15 @@ mod tests {

use fuel_abi_types::abi::{
full_program::FullABIFunction,
program::{ABIFunction, ProgramABI, TypeApplication, TypeDeclaration},
program::{ABIFunction, Attribute, ProgramABI, TypeApplication, TypeDeclaration},
};
use pretty_assertions::assert_eq;
use quote::quote;

use crate::{error::Result, program_bindings::abigen::bindings::contract::expand_fn};

#[test]
fn test_expand_fn_simple_abi() -> Result<()> {
fn expand_contract_method_simple_abi() -> Result<()> {
let s = r#"
{
"types": [
Expand Down Expand Up @@ -332,7 +329,15 @@ mod tests {
"name": "",
"type": 26,
"typeArguments": []
}
},
"attributes": [
{
"name": "doc-comment",
"arguments": [
"This is a doc string"
]
}
]
}
]
}
Expand All @@ -351,7 +356,7 @@ mod tests {
)?)?;

let expected = quote! {
#[doc = "Calls the contract's `some_abi_funct` function"]
#[doc = "This is a doc string"]
pub fn some_abi_funct(
&self,
s_1: self::MyStruct1,
Expand All @@ -378,14 +383,18 @@ mod tests {
}

#[test]
fn test_expand_fn_simple() -> Result<()> {
fn expand_contract_method_simple() -> Result<()> {
let the_function = ABIFunction {
inputs: vec![TypeApplication {
name: String::from("bimbam"),
type_id: 1,
..Default::default()
}],
name: "HelloWorld".to_string(),
attributes: Some(vec![Attribute {
name: "doc-comment".to_string(),
arguments: vec!["This is a doc string".to_string()],
}]),
..Default::default()
};
let types = [
Expand All @@ -411,7 +420,7 @@ mod tests {
let result = expand_fn(&FullABIFunction::from_counterpart(&the_function, &types)?);

let expected = quote! {
#[doc = "Calls the contract's `HelloWorld` function"]
#[doc = "This is a doc string"]
pub fn HelloWorld(&self, bimbam: ::core::primitive::bool) -> ::fuels::programs::contract::ContractCallHandler<T, ()> {
::fuels::programs::contract::method_hash(
self.contract_id.clone(),
Expand All @@ -431,7 +440,7 @@ mod tests {
}

#[test]
fn test_expand_fn_complex() -> Result<()> {
fn expand_contract_method_complex() -> Result<()> {
// given
let the_function = ABIFunction {
inputs: vec![TypeApplication {
Expand All @@ -445,7 +454,16 @@ mod tests {
type_id: 1,
..Default::default()
},
..Default::default()
attributes: Some(vec![
Attribute {
name: "doc-comment".to_string(),
arguments: vec!["This is a doc string".to_string()],
},
Attribute {
name: "doc-comment".to_string(),
arguments: vec!["This is another doc string".to_string()],
},
]),
};
let types = [
(
Expand Down Expand Up @@ -515,7 +533,8 @@ mod tests {

// Some more editing was required because it is not rustfmt-compatible (adding/removing parentheses or commas)
let expected = quote! {
#[doc = "Calls the contract's `hello_world` function"]
#[doc = "This is a doc string"]
#[doc = "This is another doc string"]
pub fn hello_world(
&self,
the_only_allowed_input: self::SomeWeirdFrenchCuisine
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub(crate) struct FunctionGenerator {
args: Components,
output_type: TokenStream,
body: TokenStream,
doc: Option<String>,
docs: Vec<String>,
}

impl FunctionGenerator {
Expand All @@ -36,7 +36,7 @@ impl FunctionGenerator {
args,
output_type: output_type.to_token_stream(),
body: Default::default(),
doc: None,
docs: vec![],
})
}

Expand All @@ -50,8 +50,8 @@ impl FunctionGenerator {
self
}

pub fn set_doc(&mut self, text: String) -> &mut Self {
self.doc = Some(text);
pub fn set_docs(&mut self, docs: Vec<String>) -> &mut Self {
self.docs = docs;
self
}

Expand Down Expand Up @@ -82,13 +82,13 @@ impl FunctionGenerator {

pub fn generate(&self) -> TokenStream {
let name = safe_ident(&self.name);
let doc = self
.doc
.as_ref()
.map(|text| {
quote! { #[doc = #text] }
let docs: Vec<TokenStream> = self
.docs
.iter()
.map(|doc| {
quote! { #[doc = #doc] }
})
.unwrap_or_default();
.collect();

let arg_declarations = self.args.iter().map(|(name, ty)| {
get_equivalent_bech32_type(ty)
Expand All @@ -104,7 +104,7 @@ impl FunctionGenerator {
let params = quote! { &self, #(#arg_declarations),* };

quote! {
#doc
#(#docs)*
pub fn #name(#params) -> #output_type {
#body
}
Expand Down Expand Up @@ -155,15 +155,19 @@ mod tests {
let function = given_a_fun();
let mut sut = FunctionGenerator::new(&function)?;

sut.set_doc("This is a doc".to_string())
.set_body(quote! {this is ze body});
sut.set_docs(vec![
" This is a doc".to_string(),
" This is another doc".to_string(),
])
.set_body(quote! {this is ze body});

// when
let tokenized: TokenStream = sut.generate();

// then
let expected = quote! {
#[doc = "This is a doc"]
#[doc = " This is a doc"]
#[doc = " This is another doc"]
pub fn test_function(&self, arg_0: self::CustomStruct<::core::primitive::u8>) -> self::CustomStruct<::core::primitive::u64> {
this is ze body
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use fuel_abi_types::abi::full_program::FullProgramABI;
use fuel_abi_types::abi::full_program::{FullABIFunction, FullProgramABI};
use proc_macro2::{Ident, TokenStream};
use quote::quote;

Expand All @@ -19,7 +19,8 @@ pub(crate) fn predicate_bindings(
abi: FullProgramABI,
no_std: bool,
) -> Result<GeneratedCode> {
let encode_function = expand_fn(&abi)?;
let main_function_abi = extract_main_fn(&abi.functions)?;
let encode_function = expand_fn(main_function_abi)?;
let encoder_struct_name = ident(&format!("{name}Encoder"));

let configuration_struct_name = ident(&format!("{name}Configurables"));
Expand Down Expand Up @@ -53,12 +54,10 @@ pub(crate) fn predicate_bindings(
Ok(GeneratedCode::new(code, type_paths, no_std))
}

fn expand_fn(abi: &FullProgramABI) -> Result<TokenStream> {
let fun = extract_main_fn(&abi.functions)?;
let mut generator = FunctionGenerator::new(fun)?;
fn expand_fn(fn_abi: &FullABIFunction) -> Result<TokenStream> {
let mut generator = FunctionGenerator::new(fn_abi)?;

let arg_tokens = generator.tokenized_args();

let body = quote! {
self.encoder.encode(&#arg_tokens)
};
Expand All @@ -67,7 +66,7 @@ fn expand_fn(abi: &FullProgramABI) -> Result<TokenStream> {
};

generator
.set_doc("Run the predicate's encode function with the provided arguments".to_string())
.set_docs(vec!["Encode the predicate arguments".to_string()])
.set_name("encode_data".to_string())
.set_output_type(output_type)
.set_body(body);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::default::Default;

use fuel_abi_types::abi::full_program::FullProgramABI;
use fuel_abi_types::abi::full_program::{FullABIFunction, FullProgramABI};
use proc_macro2::{Ident, TokenStream};
use quote::quote;

Expand All @@ -26,7 +26,8 @@ pub(crate) fn script_bindings(
return Ok(GeneratedCode::default());
}

let main_function = expand_fn(&abi)?;
let main_function_abi = extract_main_fn(&abi.functions)?;
let main_function = expand_fn(main_function_abi)?;

let log_formatters_lookup = log_formatters_instantiation_code(
quote! {::fuels::types::ContractId::zeroed()},
Expand Down Expand Up @@ -103,9 +104,8 @@ pub(crate) fn script_bindings(
Ok(GeneratedCode::new(code, type_paths, no_std))
}

fn expand_fn(abi: &FullProgramABI) -> Result<TokenStream> {
let fun = extract_main_fn(&abi.functions)?;
let mut generator = FunctionGenerator::new(fun)?;
fn expand_fn(fn_abi: &FullABIFunction) -> Result<TokenStream> {
let mut generator = FunctionGenerator::new(fn_abi)?;

let arg_tokens = generator.tokenized_args();
let body = quote! {
Expand All @@ -127,8 +127,88 @@ fn expand_fn(abi: &FullProgramABI) -> Result<TokenStream> {
.set_output_type(
quote! {::fuels::programs::script_calls::ScriptCallHandler<T, #original_output_type> },
)
.set_doc("Run the script's `main` function with the provided arguments".to_string())
.set_docs(fn_abi.doc_strings()?)
.set_body(body);

Ok(generator.generate())
}

#[cfg(test)]
mod tests {
use std::collections::HashMap;

use fuel_abi_types::abi::{
full_program::FullABIFunction,
program::{ABIFunction, Attribute, TypeApplication, TypeDeclaration},
};
use pretty_assertions::assert_eq;
use quote::quote;

use crate::{error::Result, program_bindings::abigen::bindings::script::expand_fn};

#[test]
fn expand_script_main_function() -> Result<()> {
let the_function = ABIFunction {
inputs: vec![TypeApplication {
name: String::from("bimbam"),
type_id: 1,
..Default::default()
}],
name: "main".to_string(),
attributes: Some(vec![
Attribute {
name: "doc-comment".to_string(),
arguments: vec!["This is a doc string".to_string()],
},
Attribute {
name: "doc-comment".to_string(),
arguments: vec!["This is another doc string".to_string()],
},
]),
..Default::default()
};
let types = [
(
0,
TypeDeclaration {
type_id: 0,
type_field: String::from("()"),
..Default::default()
},
),
(
1,
TypeDeclaration {
type_id: 1,
type_field: String::from("bool"),
..Default::default()
},
),
]
.into_iter()
.collect::<HashMap<_, _>>();
let result = expand_fn(&FullABIFunction::from_counterpart(&the_function, &types)?);

let expected = quote! {
#[doc = "This is a doc string"]
#[doc = "This is another doc string"]
pub fn main(&self, bimbam: ::core::primitive::bool) -> ::fuels::programs::script_calls::ScriptCallHandler<T, ()> {
let encoded_args=::fuels::core::codec::ABIEncoder::new(self.encoder_config)
.encode(&[::fuels::core::traits::Tokenizable::into_token(bimbam)]);
let provider = ::fuels::accounts::ViewOnlyAccount::try_provider(&self.account)
.expect("Provider not set up").clone();
::fuels::programs::script_calls::ScriptCallHandler::new(
self.binary.clone(),
encoded_args,
self.account.clone(),
provider,
self.log_decoder.clone()
)
}
};

assert_eq!(result?.to_string(), expected.to_string());

Ok(())
}
}
Loading