# FFI Function Signatures Under this section we discuss the signature requirements of the exported FFI functions. ## C-style Name Export FFI functions must be exported under C names, that is, they must not go through the C++ name mangling mechanism. In Rust, you need to decorate the function with the `#[unsafe(no_mangle)]` attribute together with `extern "C"`, for example: ```rust #[unsafe(no_mangle)] pub extern "C" fn WFStartup() -> CError { // Function body omitted... } // More FFI functions omitted... ``` ## Export Name Style In this subsection, we discuss the naming style of exported functions. In this design, there are exactly two styles to choose from. We call them the Windows style and the POSIX style. Either style can be chosen freely, but within a single library the two styles must not be mixed. We recommend the following selection rule: if your library is Windows-only, choose the Windows style; otherwise, choose the POSIX style. ### Windows Style The Windows style format is `` for ordinary functions, and `` for opaque struct functions. In the format, `` is the name of the opaque struct and `` is the name of the function. Both of them must use PascalCase naming. For ``, it is a prefix identifier that is specific to this library. As we all know, C has no namespace concept, and all functions are exported into the same space. Therefore, avoiding name collisions between functions is an important task. By prepending `` to the function name, name duplication can be avoided as much as possible. For this reason, you need to choose `` carefully and try to pick a prefix that is unlikely to collide. In the Windows style, there are two spellings for ``. One is the all-uppercase style and the other is the style in which only the first letter is uppercase and all remaining letters are lowercase. Choose according to your own needs. In addition, the length of `` must not exceed 5 characters, and it must not contain anything other than letters and digits (that is, underscores are not allowed). The following examples show some legal and illegal Windows style function names: | Name | Verdict | Reason | |------|---------|--------| | `WFStartup` | Legal | An ordinary (non opaque struct) function. | | `WFIconGetHandle` | Legal | An opaque struct function whose `` is `Icon`. | | `WFWordHandleGetHandle` | Legal | An opaque struct function whose `` is `WordHandle`. | | `FlGetMessage` | Legal | Uses a ``, which is `Fl`, that capitalizes only its first letter. | | `MyRustGetMessage` | Illegal | ``, which is `MyRust`, does not keep all remaining letters lowercase. | | `My_RustGetMessage` | Illegal | `` contains an underscore. | | `IconGetHandle` | Illegal | Missing ``. | | `QwertyuiopGetData` | Illegal | ``, which is `Qwertyuiop`, is too long. | | `WFget_message` | Illegal | ``, which is `get_message`, is not PascalCase. | | `WFicon_handleGetMessage` | Illegal | ``, which is `icon_handle`, is not PascalCase. | ### POSIX Style The POSIX style format is `_` for ordinary functions, and `__` for opaque struct functions. The ``, `` and `` components in the format have the same meaning as in the Windows style, but the format is different. `` and `` must use snake_case naming. `` must be all lowercase, and it must not contain anything other than letters and digits (that is, underscores are not allowed). Its length and selection requirements are the same as in the Windows style. The following examples show some legal and illegal POSIX style function names: | Name | Verdict | Reason | |------|---------|--------| | `wf_startup` | Legal | An ordinary (non opaque struct) function. | | `wf_icon_get_handle` | Legal | An opaque struct function whose `` is `icon`. | | `wf_word_handle_get_handle` | Legal | An opaque struct function whose `` is `word_handle`. | | `Fl_get_message` | Illegal | ``, which is `Fl`, is not all lowercase. | | `my_rust_get_message` | Illegal | ``, which is `my_rust`, contains an underscore. | | `icon_get_handle` | Illegal | Missing ``. | | `qwertyuiop_get_data` | Illegal | ``, which is `qwertyuiop`, is too long. | | `wf_GetMessage` | Illegal | ``, which is `GetMessage`, is not snake_case. | | `wf_Icon_get_message` | Illegal | ``, which is `Icon`, is not snake_case. | ## Parameters and Return Value Under this section we discuss the parameters and return value of the exported functions. A standard FFI function looks like the following on the Rust side: ```rust #[unsafe(no_mangle)] pub extern "C" fn FBAdd( in_a: in_param_ty!(u32), in_b: in_param_ty!(u32), out_rv: out_param_ty!(u32), out_overflow: out_param_ty!(bool), ) -> CError { // Function body omitted... } ``` As shown in the example, this function has four parameters. The first two are input parameters and the last two are output parameters. The return value of the function is `CError`. ### Parameter Rules To follow the best practice of C for the signature of functions with any number of input parameters and output parameters, we must design the function signature this way. To implement such a function that accepts any number of inputs and outputs, we need to put both the input parameters and the output parameters into the parameter list. All input parameters must precede any output parameter. The return value, `CError`, is used only to indicate whether the function succeeded or failed. The naming style of the function parameters (both input and output) must be snake_case and must not start with an underscore. #### Input Parameters Input parameters are passed directly by value (for example, integers, floats or pointers). In the example, `in_a` and `in_b` are both of type `u32`. You can use the `in_param_ty!` macro provided by the crate to conveniently mark this. By convention, input parameters are prefixed with `in_`, but this is not enforced. #### Output Parameters Output parameters are passed as pointers. In the example, `out_rv` is actually of type `*mut u32` and `out_overflow` is actually of type `*mut bool`. To avoid repeatedly writing these pointer types and to avoid writing them incorrectly, you can use the `out_param_ty!` macro provided by the crate, which is symmetric with `in_param_ty!`. At the same time, you can use the `deref_out_param!` macro provided by the crate to conveniently dereference an output parameter for assignment, or directly use the `set_out_param!` macro provided by the crate for assignment. But you usually do not need to do that, because in later chapters you will be guided on how to correctly use `cffi_wrapper!` to maximize the efficiency of writing FFI functions. By convention, output parameters are prefixed with `out_`, but this is not enforced. ### The Return Value The return value of an FFI function must be of the `CError` type. `CError` is defined in `last_error::CError` as a plain `u32`. It is not an enum with a fixed set of members. Instead, `CERROR_OK` is the single value that represents absolute, unambiguous success. Every other value's meaning is decided by the consuming project: it may denote a failure, or, like some Win32 functions, a partial success. #### Migrating from a bool Return Value Projects that previously returned a plain `bool` can adopt the error-code scheme with minimal change: define exactly one non-success code, for example `const CERROR_FAIL: CError = 1;`, and map every error type to it. The result is equivalent to a `bool`: `CERROR_OK` for success and `CERROR_FAIL` for any failure, while leaving room to introduce finer-grained codes later.