foreign_class!

foreign_class! is the way to describe an entity that will be visible for the "foreign language" as a class.

The basic example is:

use super::{f2, Foo};

foreign_class!(class Foo {
    self_type Foo;
    constructor Foo::new(_: i32) -> Foo;
    fn Foo::set_field(&mut self, _: i32);
    fn Foo::f(&self, _: i32, _: i32) -> i32;
    fn f2(_: i32) -> i32;
});

Here Foo may be struct or enum or a more complex type (see below). The self_type can be omitted if there are no constructors and all fn do not accept self.

self_type

The self_type is used as a "neat" way to call methods of types inside "smart pointers". For example sometimes you can not use your struct or enum explicitly, because of the semantic of the "foreign language" does not allow it, then you can write:

foreign_class!(class CircularDepsA {
    self_type CircularDepsA;
    constructor CircularDepsA::java_new(_: &str) -> Arc<Mutex<CircularDepsA>>;
    fn CircularDepsA::a(&self, b: &CircularDepsB) -> String;
});

And flapigen will be instructed to generate code to call each method listed above with lock().unwrap().method syntax.

Also maybe you want export a trait implementation as foregin_class. The flapigen cannot work with Box<Trait>, because it requires unstable/unsafe APIs to convert the boxed trait into something that can be transferred over the FFI border, but it can work with Box<Box<Trait>>, so via self_type you can represent a boxed trait as class:

pub trait Interface {
    fn f(&self, _: i32) -> i32;
    fn set(&mut self, _: i32);
}
struct InterfaceImpl {
    base: i32,
}

impl Interface for InterfaceImpl {
    fn f(&self, x: i32) -> i32 {
        self.base + x
    }
    fn set(&mut self, x: i32) {
        self.base = x;
    }
}

fn create_interface() -> Box<Box<dyn Interface>> {
    Box::new(Box::new(InterfaceImpl { base: 17 }))
}

foreign_class!(class Interface {
    self_type dyn Interface;
    constructor create_interface() -> Box<Box<dyn Interface>>;
    fn Interface::f(&self, _: i32) -> i32;
    fn Interface::set(&mut self, x: i32);
});

Also it should be noted that flapigen generates code that uses "Universal Function Call Syntax", so methods can be fake methods and declared outside of impl blocks:

pub struct TestMethodNotMethod;

impl TestMethodNotMethod {
    fn new() -> Self {
        TestMethodNotMethod
    }
}

fn method_not_method(_this: &TestMethodNotMethod) {}

foreign_class!(class TestMethodNotMethod {
    self_type TestMethodNotMethod;
    constructor TestMethodNotMethod::new() -> TestMethodNotMethod;
    fn method_not_method(&self);
});

Access modifiers

By default, methods in generated class are public. You can change access level via protected and private keywords.

foreign_class!(
    class Foo {
        self_type Foo;
        constructor Foo::new() -> Foo;
        private constructor Foo::from_int(_: i32) -> Foo;
        private fn Foo::private_f();
        fn Foo::public_f();
        protected fn Foo::protected_f();
    }
);

Inline methods

It is also sometimes convenient to write short methods just inside foreign_class!, for example to add a way to access fields of a struct or to export a result of a Rust macro call:

foreign_class!(class TestFnInline {
    fn int_to_str(a: i32) -> String {
        format!("{}", a)
    }
});

To reference self in inline methods you should use the this variable, because the inline method is not the real one, it is just code block that gets included into the generated code:

pub struct Session {
    name: String,
}

foreign_class!(
    #[derive(SmartPtrCopy)]
    class Session {
        self_type Session;
        constructor session_init(name: &str) -> Rc<RefCell<Session>> {
            Rc::new(RefCell::new(Session {
                name: name.into(),
            }))
        }
        fn name(&self) -> &str {
            &this.name
        }
    }
);

Methods aliases

Also you can create an alias for a function name:

    fn Foo::f(&self, _: i32, _: i32) -> i32;  alias calcF;

So it would be called by path with fn in Rust code, and you can call it via name with alias in foreign language.

This may be useful for example if you want to name functions in Java in camel case style, while you want to use snake case style in Rust.

Constructors

Constructors are Rust methods that mapped to constructors in terms of the "foreign" language. Also constructors, more precisely, the return type of constructors can be used to ask flapigen to simplify calls of methods, see the self_type section for more details. Sometimes you need a constructor, but you don't want allow the user to construct objects, then you can use an empty constructor:

foreign_class!(
    class GamepadId {
        self_type GamepadId;
        private constructor = empty;
        fn GamepadId::value(&self) -> usize;
    }
);

foreigner_code

flapigen also supports bypassing code generation:

foreign_class!(class TestPathAndResult {
    self_type TestPathAndResult;
    constructor TestPathAndResult::empty() -> Result<TestPathAndResult, String>;
    constructor TestPathAndResult::new(path: &Path) -> Result<TestPathAndResult, String>;
    fn TestPathAndResult::get_path(&self) -> String; alias getPath;
    fn TestPathAndResult::get_boo(&self) -> Rc<RefCell<Boo>>; alias getBoo;
    foreign_code "    public int javaFunc() { return 17; }\n";
    foreign_code r#"
    public Boo[] testHandArrayReturn() { return do_testHandArrayReturn(this.mNativeObj); }
    private static native Boo[] do_testHandArrayReturn(long me);
"#;
    fn TestPathAndResult::get_foo_list(&self) -> Vec<Foo>;
    fn TestPathAndResult::get_result_foo_list(generate_err: bool) -> Result<Vec<Foo>, String>;
});

After that you can implement the Java_com_example_TestPathAndResult_do_1testHandArrayReturn function yourself, useful for when flapigen cannot handle something automatically, or you want to do something special.

Doc comments

You can also add comments to generated code with Rust doc comments:

foreign_class!(
/// Class comment description for Foo.
#[derive(Clone)]
class Foo {
    self_type Foo;
    /// some text about the new function
    ///
    /// ```
    /// some markdown example in the text
    /// ```
    ///
    /// @param val - some number
    /// @param name - more information
    constructor Foo::new(val: i32, name: &str) -> Foo;

Derives

You can use "derive" syntax on the declaration of classes, in a similar way to the usage on "Rust" structs:

/// Class comment description for Foo.
#[derive(Clone)]
class Foo {
    self_type Foo;

Usage of derives changes generated code in various ways. For example, you can use Clone,Copy to force the generation of a copy constructor and operator= in C++ case. You can also use camelCaseAliases to change names of all methods to camel case.