Java's Functional Interfaces for Rust/UniFFI

Java's Functional Interfaces for Rust/UniFFI

Functional Interfaces

UniFFI has good support for callback interfaces, allowing calling code to supply its own logic to be called from Rust. How to make this work on the other-language side was relatively obvious to me: you just implement the interface. However, how to make this smooth in Rust took a moment to figure out, so I figured I'd make a note.

A UniFFI callback interface looks (using the proc macros) like this:

#[uniffi::export(callback_interface)]
pub trait MyCallback: Send + Sync {
    fn consume(&self, value: MyValue);
}

(where MyValue has #[uniffi::export] as well)

and some function which takes it (boxed, because we can't know the implementing type at compile time, so it's gotta be a dyn rather than being able to use a generic/impl Trait) like so:

#[uniffi::export]
pub fn do_it(doer: Box<dyn MyCallback>) {
  doer.consume(some_value);
}

Which is all well and good. But using this from Rust is a bit of a pain - there's just one method, so it should be possible to just yunk in a closure. But if you wanna do that you gotta tell Rust that's okay, it doesn't infer it like Java's functional interfaces. Here's how you do that:

impl<T> MyCallback for T
where
    T: Fn(MyValue) -> () + Send + Sync
{
  fn consume(&self, value: MyValue) {
    self(value)
  }
}

Getting the syntax right on this took a sec but it's fairly self-explanatory if you're used to Rust. I also went down a road of trying to use impl From, which doesn't really work out (try it yourself if you want to know why). Anyway, now you can call do_it from Rust and give it a boxed, but otherwise plain, closure:

do_it(Box::new(|_it| {}))