This question already has answers here:
"Expected fn item, found a different fn item" when working with function pointers
(2 answers)
Closed 6 years ago.
How do you stick functions (or function pointers) into an array for testing purposes?
fn foo() -> isize { 1 }
fn bar() -> isize { 2 }
fn main() {
let functions = vec![foo, bar];
println!("foo() = {}, bar() = {}", functions[0](), functions[1]());
}
This code in the Rust playground
This is the error code I get:
error: mismatched types:
expected `fn() -> isize {foo}`,
found `fn() -> isize {bar}`
(expected fn item,
found a different fn item) [E0308]
let functions = vec![foo, bar];
^~~
Rust is treating my functions (values) as different types despite having the same signatures, which I find surprising.
At some point recently, each function was given its own, distinct type for... reasons that I don't recall. Upshot is that you need to give the compiler a hint (note the type on functions):
fn foo() -> isize {
1
}
fn bar() -> isize {
2
}
fn main() {
let functions: Vec<fn() -> isize> = vec![foo, bar];
println!("foo() = {}, bar() = {}", functions[0](), functions[1]());
}
You can also do this like so:
let functions = vec![foo as fn() -> isize, bar];
Related
The following Rust code tries to store a closure of zero arguments in an array and call the function.
fn main() {
println!("The answer is: {}", solution_fns[0]());
}
const solution_fns: [fn() -> isize] =
[|| (1..=999).filter(|e| divides(3, e) || divides(5, e)).sum()];
fn divides(d: usize, n: usize) -> bool {
n % d == 0
}
Link to Rust playground. Unfortunately it does not compile:
error[E0277]: the size for values of type [fn() -> isize] cannot be
known at compilation time --> src/main.rs:5:21 | 5 | const
solution_fns: [fn() -> isize] = |
^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | =
help: the trait Sized is not implemented for [fn() -> isize]
I understand that you cannot constuct an array (or Vec) of things of which the size is not known at compile-time. However I understand the type [fn() -> isize] to be array of function pointers, and I don't see why a function pointer should not have a known size. Sticking the closure in a Box does not seem to help:
const solution_fns: [Box<fn() -> isize>] = [Box::new(|| {
(1..=999).filter(|e| divides(3, e) || divides(5, e)).sum()
})];
How then can I store an array of closures?
The problem is not in the fn pointer, but that your array doesnt have a size. It is simply solved by adding the expected size to the array declaration:
const solution_fns: [fn() -> usize; 1] =
[|| (1..=999usize).filter(|&e| divides(3, e) || divides(5, e)).sum()];
Playground
If you use a slice, then you don't have to specify the size:
fn main() {
println!("The answer is: {}", SOLVERS[0]());
}
const SOLVERS : &[fn() -> usize] =
&[|| (1..=999).filter(|&e| divides(3, e) || divides(5, e)).sum()];
fn divides(d: usize, n: usize) -> bool {
n % d == 0
}
Link to the playground.
The C function I wish to call is documented as:
GDALVectorTranslateOptions* GDALVectorTranslateOptionsNew(char** papszArgv, GDALVectorTranslateOptionsForBinary* psOptionsForBinary)
...and is imported to swift as:
public func GDALVectorTranslateOptionsNew(_ papszArgv: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!, _ psOptionsForBinary: OpaquePointer!) -> OpaquePointer!
I have been unable to convert my swift array of strings into a C array of C strings in such a way that does not produce an error.
I have tried various methods found during research, and they all end up with similar errors being produced. My current method is to use the following function to convert the Swift array of strings to be used within a closure:
public func withArrayOfCStrings<R>(_ args: [String], _ body: ([UnsafeMutablePointer<CChar>?]) -> R) -> R {
var cStrings = args.map { strdup($0) }
cStrings.append(nil)
defer {
cStrings.forEach { free($0) }
}
return body(cStrings)
}
I'm attempting to use it all like this:
var opts = ["blah1", "blah2"]
withArrayOfCStrings(opts) { (cOpts) in
let translateOpts = GDALVectorTranslateOptionsNew(cOpts, nil)
}
But I get the error:
Cannot convert value of type '[UnsafeMutablePointer?]' (aka 'Array<Optional<UnsafeMutablePointer>>') to expected argument type 'UnsafeMutablePointer<UnsafeMutablePointer?>?'
How should I be doing this?
That withArrayOfCStrings function works with C functions taking a char * const * argument, i.e. a pointer to constant pointers to characters.
If you change the C declaration to
GDALVectorTranslateOptions* GDALVectorTranslateOptionsNew(char* const* papszArgv,
GDALVectorTranslateOptionsForBinary* psOptionsForBinary)
then it compiles and runs as expected.
If you do not have the option to modify the C code then you can change the helper method to
public func withArrayOfCStrings<R>(_ args: [String],
_ body: (UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>) -> R) -> R {
var cStrings = args.map { strdup($0) }
cStrings.append(nil)
defer {
cStrings.forEach { free($0) }
}
return body(&cStrings)
}
The body is now called with a UnsafeMutablePointer<UnsafeMutablePointer<Int8>?> argument, which corresponds to a C char ** argument.
I'm trying to combine my Rust program with a library written in C in a more complex scenario.
The library provides this interface:
use std::os::raw::{c_char, c_void};
extern "C" {
pub fn register_function(
name: *const c_char, signature: *const c_char,
func_ptr: *mut c_void, attachment: *mut c_void,
);
}
The signature can be a string describing the arguments and return type of the function as 32 or 64 bit ints and floats (representations: b'i' = i32, b'I' = i64, b'f' = f32, b'F' = f64). The registered function gets called with an array of u64 (uint64_t) values which correspond to the arguments from the signature.
I would like to abstract this registration and callback process, so that I can switch to another library in the future which provides a similar but different interface. My idea was to to create a proxy function that is registered instead of the actual function. This would then also provide a custom context struct.
My own functions could look like this:
use std::boxed::Box;
use std::pin::Pin;
fn return_void(context: Pin<Box<MyAttachment>>) {
// ...
}
fn return_32(context: Pin<Box<MyAttachment>>, a: u32, b: u32) -> u32 {
context.important_stuff();
// ...
}
// floating point values would be nice, but are optional
fn return_64(a: i32, b: i64, c: f64) -> f64 {
// ...
}
MyAttachment is supposed to be the context and provide the proxy function that gets an arbitrary number of arguments as array:
use std::cmp;
use std::ffi::CString;
use std::slice;
#[derive(PartialEq)]
enum ReturnType {
VOID,
BITS32,
BITS64,
}
struct MyAttachment {
real_func_ptr: *mut c_void,
signature: String,
argc: u32,
pass_attachment: bool,
return_type: ReturnType,
}
impl MyAttachment {
pub fn important_stuff(&self) {
// ...
}
unsafe extern "C" fn function_proxy(attachment: *mut c_void, argv: *mut u64) {
// Given: attachment is the pointer to MyAttachment and argv is the array of arguments.
let this = attachment.cast::<Self>();
if this.is_null() || argv.is_null() {
// error handling
return;
}
let this = Pin::new_unchecked(Box::from_raw(this)); // restore
let args = slice::from_raw_parts_mut(
argv,
// There is at least one element in argv if the function is supposed to return a value,
// because we need to write our result there.
cmp::max(
match this.return_type {
ReturnType::VOID => 0,
ReturnType::BITS32 | ReturnType::BITS64 => 1,
},
this.argc as usize,
),
);
let func_ptr = this.real_func_ptr;
// I can get the argument types from the signature.
// TODO cast to correct pointer type. For example:
// case return_void: Fn(Pin<Box<MyAttachment>>)
// case return_32: Fn(Pin<Box<MyAttachment>>, u64, u64) -> u32
// case return_64: Fn(u64, u64, f64) -> f64
// TODO call it:
if this.return_type != ReturnType::VOID {
//args[0] = func_ptr(...args);
// or
//args[0] = func_ptr(this, ...args);
} else {
//func_ptr(...args);
}
Box::into_raw(Pin::into_inner_unchecked(this)); // delay dropping of this
}
}
fn main() {
// defining functions like:
let func1 = Box::pin(MyAttachment {
real_func_ptr: return_32 as *mut _,
signature: String::from("(ii)i"),
argc: 2, // inferred from signature
pass_attachment: true,
return_type: ReturnType::BITS32, // inferred from signature
});
let name = CString::new("return_32").unwrap();
let signature = CString::new(func1.signature.as_str()).unwrap();
// leak the raw pointer
let func1_ptr = Box::into_raw(unsafe { Pin::into_inner_unchecked(func1) });
let _func1 = unsafe { Pin::new_unchecked(Box::from_raw(func1_ptr)) }; // just for housekeeping
unsafe {
register_function(
name.as_ptr(),
signature.as_ptr(),
MyAttachment::function_proxy as *mut _,
func1_ptr as *mut _,
)
};
// ...
// somewhere here is my proxy called from C
// ...
// automatic cleanup of MyAttachment structs, because the Boxes are dropped
}
How do I fill these TODOs with code?
I have seen this in C code somewhere by using a generic function pointer and defining a fixed number of calls:
void (*func_ptr)();
if (argc == 0)
func_ptr();
else if (argc == 1)
func_ptr(argv[0]);
else if (argc == 2)
func_ptr(argv[0], argv[1]);
// ... and so on
But is there a solution to do this in Rust? (This only needs to work for x86_64/amd64)
Thanks in advance for reading all this and trying to help.
(I added the reflection tag, because this would be done via reflection if Rust had any)
==== edit
I have seen these related questions, but I don't think they apply here:
Call a raw address from Rust -> My type is not given at compile time
How do I pass each element of a slice as a separate argument to a variadic C function? -> My arguments are somewhat of fixed size and don't use a valist
This question already has answers here:
How to iterate over and filter an array?
(3 answers)
Closed 2 years ago.
The code below compiles, but if the 'args' passed to the function 'f' is changed from a Vec to an array of Strings it does not. I'm trying to understand why. I assume it has something to do with the ownership rules, but I could use some clarification. Thanks.
fn f(args: Box<dyn Iterator<Item=String>>) {
for arg in args {
println!("{}", arg)
}
}
fn main() {
let args = vec!["one_arg".to_string()]; // If changed to array, I get error below
f(Box::new(args.into_iter()));
}
If vec!["one_arg".to_string()]; is changed to: ["one_arg".to_string()];, the error below is the result.
error[E0271]: type mismatch resolving `<std::slice::Iter<'_, std::string::String> as std::iter::Iterator>::Item == std::string::String`
--> src/main.rs:10:7
|
10 | f(Box::new(args.into_iter()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::string::String`, found reference
|
= note: expected struct `std::string::String`
found reference `&std::string::String`
= note: required for the cast to the object type `dyn std::iter::Iterator<Item = std::string::String>`
The reason is because Vec::into_iter returns an iterator over its items, while slice::into_iter returns an iterator over references to its items. So, args.into_iter() is an Iterator<Item=&String> instead of Iterator<Item=String> when args is a slice. On a side note, don't Box a dyn Iterator and instead just use a generic:
fn f<I: Iterator<Item=String>>(args: I) {
for arg in args {
println!("{}", arg)
}
}
fn main() {
let args = vec!["one_arg".to_string()];
f(args.into_iter());
}
I have seen:
Rust array of functions
Iterate over vector of functions
and searched online. I do not want closures. I am trying to implement a classic dynamic(-ish) function lookup table.
mod impl_foo;
mod impl_bar;
use utils;
// a CmdResult is a Result with a tuple of an int and a string
static FUNCTIONS: &'static [fn(&[String]) -> utils::CmdResult] = &[
("bar".to_string(), impl_bar::call_bar),
("foo".to_string(), impl_foo::call),
];
fn find_action(name: &String) -> (fn(&[String]) -> utils::CmdResult) {
match FUNCTIONS.binary_search_by(|item| item[0].cmp(name)) {
Ok(action) => action,
Err(_) => (|&[String]| Err((1, format!("Unknown '{}'", name))))
}
}
// later on in another function ....
action = find_action("foo");
let result = action(args);
// process results
But this does not compile:
src/main.rs:44:5: 44:50 error: mismatched types:
expected `fn(&[collections::string::String]) -> core::result::Result<i32, (i32, collections::string::String)>`,
found `(collections::string::String, fn(&[collections::string::String]) -> core::result::Result<i32, (i32, collections::string::String)> {impl_foo::call})`
and again for impl_bar::call_bar.
What am I missing? It appears to have something to do with the use of different modules since it clearly works for other people.
I also tried to define a type:
type Action = fn(&[String]) -> utils::CmdResult;
and use that to cut down on typing but no luck there either.
BTW, you need #![feature(slice_patterns)] because of the &[String].
Edit the next morning.....
As Francis points out below my transcription here had a flaw. It did not exactly match the real problem I had but it helped me see with fresh eyes.
The slice pattern requirement is because I was trying to handle unknown functions with a closure. Once I removed that the complaint went away. I was trying to be a little too dynamic language style I think :-)
Below is the completed code that actually works so that people finding this question can see working code.
type Action = fn(&[String]) -> utils::CmdResult;
static FUNCTIONS: &'static [(&'static str, Action)] = &[
("bar", impl_bar::call),
("foo", impl_foo::call_foo),
];
fn find_action(prog: &String) -> Option<Action> {
match FUNCTIONS.binary_search_by(|&(name,_)| name.cmp(prog)) {
Ok(idx) => Some(FUNCTIONS[idx].1),
Err(_) => None,
}
}
fn invoke(prog: &String, args: &[String]) -> i32 {
let result = match find_action(prog) {
Some(action) => action(args),
None => Err((1, format!("Unknown: {}", prog))),
};
result.unwrap_or_else(|(n, msg)| {
writeln!(io::stderr(), "{}", msg).ok();
n
})
}
Read the error message carefully:
src/main.rs:44:5: 44:50 error: mismatched types:
expected `fn(&[collections::string::String]) -> core::result::Result<i32, (i32, collections::string::String)>`,
found `(collections::string::String, fn(&[collections::string::String]) -> core::result::Result<i32, (i32, collections::string::String)> {impl_foo::call})`
Let's simplify it:
src/main.rs:44:5: 44:50 error: mismatched types:
expected `fn(&[String]) -> Result<i32, (i32, String)>`,
found `(String, fn(&[String]) -> Result<i32, (i32, String)> {impl_foo::call})`
What this message is telling you is that you're trying to put a tuple of String and a function type into an array that expects only the function type.
You probably meant to define your array like this:
static FUNCTIONS: &'static [(&'static str, fn(&[String]) -> utils::CmdResult]) = &[
("bar", impl_bar::call_bar),
("foo", impl_foo::call),
];