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

Allow functions with return type '-> ()' to be bound #123

Merged
merged 3 commits into from
Jul 6, 2022
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ pub fn import_timestamp(arg: MyDateTime) -> MyDateTime;
#[fp_bindgen_support::fp_import_signature]
pub fn import_void_function();

#[fp_bindgen_support::fp_import_signature]
pub fn import_void_function_empty_return();
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is functionally a duplicate of import_void_function() :)

Copy link
Contributor Author

@sagacity sagacity Jul 6, 2022

Choose a reason for hiding this comment

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

Agreed, but the protocol specifies a -> () return type here, which gets omitted during codegen. Once that is done, the two functions are indeed identical.

Copy link
Contributor

Choose a reason for hiding this comment

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

Good point, I overlooked that 👍


/// Logs a message to the (development) console.
#[fp_bindgen_support::fp_import_signature]
pub fn log(message: String);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,7 @@ fn create_import_object(store: &Store, env: &RuntimeInstanceData) -> ImportObjec
"__fp_gen_import_string" => Function :: new_native_with_env (store , env . clone () , _import_string) ,
"__fp_gen_import_timestamp" => Function :: new_native_with_env (store , env . clone () , _import_timestamp) ,
"__fp_gen_import_void_function" => Function :: new_native_with_env (store , env . clone () , _import_void_function) ,
"__fp_gen_import_void_function_empty_return" => Function :: new_native_with_env (store , env . clone () , _import_void_function_empty_return) ,
"__fp_gen_log" => Function :: new_native_with_env (store , env . clone () , _log) ,
"__fp_gen_make_http_request" => Function :: new_native_with_env (store , env . clone () , _make_http_request) ,
}
Expand Down Expand Up @@ -1005,6 +1006,10 @@ pub fn _import_void_function(env: &RuntimeInstanceData) {
let result = super::import_void_function();
}

pub fn _import_void_function_empty_return(env: &RuntimeInstanceData) {
let result = super::import_void_function_empty_return();
}

pub fn _log(env: &RuntimeInstanceData, message: FatPtr) {
let message = import_from_guest::<String>(env, message);
let result = super::log(message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export type Imports = {
importString: (arg: string) => string;
importTimestamp: (arg: MyDateTime) => MyDateTime;
importVoidFunction: () => void;
importVoidFunctionEmptyReturn: () => void;
log: (message: string) => void;
makeHttpRequest: (request: Request) => Promise<HttpResult>;
};
Expand Down Expand Up @@ -345,6 +346,9 @@ export async function createRuntime(
__fp_gen_import_void_function: () => {
importFunctions.importVoidFunction();
},
__fp_gen_import_void_function_empty_return: () => {
importFunctions.importVoidFunctionEmptyReturn();
},
__fp_gen_log: (message_ptr: FatPtr) => {
const message = parseObject<string>(message_ptr);
importFunctions.log(message);
Expand Down
3 changes: 3 additions & 0 deletions examples/example-protocol/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ fp_import! {
// No arguments, no return type:
fn import_void_function();

// No arguments, empty return type:
fn import_void_function_empty_return() -> ();

// Passing primitives:
fn import_primitive_bool(arg: bool) -> bool;
fn import_primitive_f32(arg: f32) -> f32;
Expand Down
14 changes: 6 additions & 8 deletions fp-bindgen/src/functions.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::utils::normalize_return_type;
use crate::{docs::get_doc_lines, types::TypeIdent};
use quote::{format_ident, quote, ToTokens};
use std::{collections::BTreeSet, convert::TryFrom};
use syn::{token::Async, FnArg, ForeignItemFn, ReturnType};
use syn::{token::Async, FnArg, ForeignItemFn};

/// Maps from function name to the stringified function declaration.
#[derive(Debug, Default)]
Expand Down Expand Up @@ -71,13 +72,10 @@ impl Function {
},
})
.collect();
let return_type = match &item.sig.output {
ReturnType::Default => None,
ReturnType::Type(_, return_type) => Some(
TypeIdent::try_from(return_type.as_ref())
.unwrap_or_else(|_| panic!("Invalid return type for function {}", name)),
),
};
let return_type = normalize_return_type(&item.sig.output).map(|return_type| {
TypeIdent::try_from(return_type)
.unwrap_or_else(|_| panic!("Invalid return type for function {}", name))
});
let is_async = item.sig.asyncness.is_some();

Self {
Expand Down
1 change: 1 addition & 0 deletions fp-bindgen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ mod serializable;
pub mod prelude;
pub mod primitives;
pub mod types;
mod utils;

use fp_bindgen_macros::primitive_impls;
use prelude::*;
Expand Down
17 changes: 17 additions & 0 deletions fp-bindgen/src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use syn::{ReturnType, Type};

// This is the same as the one in macros/src/lib.rs, which we unfortunately cannot export.
pub(crate) fn normalize_return_type(ty: &ReturnType) -> Option<&Type> {
match ty {
ReturnType::Default => None,
ReturnType::Type(_, ty) => {
match ty.as_ref() {
Type::Tuple(tuple) if tuple.elems.is_empty() => {
/* An empty '-> ()' return value */
None
}
r => Some(r),
}
}
}
}
21 changes: 8 additions & 13 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use syn::{
AttributeArgs, FnArg, ForeignItemFn, GenericParam, ItemFn, ItemType, ItemUse, Pat, PatPath,
Path, PathArguments, PathSegment, ReturnType,
};
use utils::flatten_using_statement;
use utils::{flatten_using_statement, normalize_return_type};

mod primitives;
mod serializable;
Expand Down Expand Up @@ -128,19 +128,14 @@ fn parse_statements(token_stream: TokenStream) -> ParsedStatements {
}
}

match &function.sig.output {
ReturnType::Default => { /* No return value. */ }
ReturnType::Type(_, ty) => {
type_paths.insert(extract_path_from_type(ty.as_ref()).unwrap_or_else(
|| {
panic!(
"Only value types are supported. \
if let Some(ty) = normalize_return_type(&function.sig.output) {
type_paths.insert(extract_path_from_type(ty).unwrap_or_else(|| {
panic!(
"Only value types are supported. \
Incompatible return type in function declaration: {:?}",
function.sig
)
},
));
}
function.sig
)
}));
}

functions.push(function.into_token_stream().to_string());
Expand Down
18 changes: 17 additions & 1 deletion macros/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use std::collections::VecDeque;
use proc_macro::TokenStream;
use proc_macro2::Ident;
use syn::{
punctuated::Punctuated, Generics, Item, ItemUse, Path, PathArguments, PathSegment, Type,
punctuated::Punctuated, Generics, Item, ItemUse, Path, PathArguments, PathSegment, ReturnType,
Type,
};

pub(crate) fn extract_path_from_type(ty: &Type) -> Option<Path> {
Expand Down Expand Up @@ -80,3 +81,18 @@ pub(crate) fn flatten_using_statement(using: ItemUse) -> impl Iterator<Item = Pa

result.into_iter()
}

pub(crate) fn normalize_return_type(ty: &ReturnType) -> Option<&Type> {
match ty {
ReturnType::Default => None,
ReturnType::Type(_, ty) => {
match ty.as_ref() {
Type::Tuple(tuple) if tuple.elems.is_empty() => {
/* An empty '-> ()' return value */
None
}
r => Some(r),
}
}
}
}