2
votes

In rust when a name denotes a function, its type is actually specific to that function:

fn f(){}

The type of f is not fn() but fn() {f}. This actually causing me serious trouble in production code.

I would like to know if there is a way that turns any "specific function type" into a function pointer type without the need to repeat what is the function type. The function would map

  • fn() {f} to fn()
  • fn(i32) {g} to fn(i32)
  • ...

Let's see a simplified example of the issue:

trait X{}

impl<R> X for fn()->R {
}
impl<R,A> X for fn(A)->R {
}

fn f(){}
fn g(i32){}
fn h(f32){}

fn test<T:X>(_:T){}

fn main() {
    test(f); // Compiler Error
    test(g); // Compiler Error
    test(h); // Compiler Error

    // All work around implies that library users
    // have to write the function type
    let a: fn() = f;
    test(a); 
    let b: fn(i32) = g;
    test(b); 
    let c: fn(f32) = h;
    test(h); 

    test(f as fn()); 
    test(g as fn(i32)); 
    test(h as fn(f32)); 

    // I would like something as:
    test(to_fn_pointer(f)); 
    test(to_fn_pointer(g)); 
    test(to_fn_pointer(h)); 
}


About the real case:

I have written a tiny layer on the java native interface to ensure type safety.

When the library written in "native" code is bound to java code manually we have to call RegisterNative.

This function takes as an argument a string representation of the signature of the java function and a pointer to a (rust) function.

To ensure that the function pointer passed to that function and the java function signature matches, I have written a trait that generates directly the "signature" from the function type.

What is bellow is a simplification but it exposes the trouble:

struct NativeMethod{
   signature: CString,
   function: *const c_void,
}
trait Signature {
  fn signature() -> String;
}
impl<R:Signature> Signature for fn()-> {
  fn signature() -> CString {
    "()" + R::signature()
  }
}
impl<R,A> Signature for fn(A) {
  fn signature() -> CString {
    "(" + A::signature() + ")" + R::signature
  }
}
// ... for functions of x arguments
impl Signature for f32 {
  fn signature() -> String {
    "F".to_owned()
  }
}
//... 

pub fn declare_native_method<T: Signature + IsFnPointer>(function: T) -> {
  NativeMethod {
   signature: T::signature(),
   ptr: function as * const c_void,
  } 
}

Unfortunately I cannot call declare_native_method(function) because i must explicitly convert afunction to a function pointer. The code is thus verbose and needs duplication of the function type.

1
I don't think there's any way to generically coerce function item types to their respective function pointer types. Perhaps if you could explain a little more about your X trait, and in particular how it is used within the test function, there may be A Better Way of approaching this problem?eggyal
@eggyal Ok I have just done it.Oliv

1 Answers

1
votes

There is no such way, at least as far as I know.

Instead, I would create a (probably proc-)macro that will verify the signature. It can take the Java signature and the Rust function pointer, convert the Java signature to Rust signature and call register("javaSig", rustFn as RustSig). This will generate a compile-time error if the signature is wrong.