Skip to content

Commit

Permalink
Merge pull request #1379 from pentamassiv/master
Browse files Browse the repository at this point in the history
Reworked the book/tutorial
  • Loading branch information
sdroege committed Feb 9, 2023
2 parents 425f84d + 8243392 commit 43b9242
Show file tree
Hide file tree
Showing 14 changed files with 748 additions and 483 deletions.
12 changes: 7 additions & 5 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# Summary

- [Introduction](introduction.md)
- [Configuration](config_introduction.md)
- [FFI Options](config_ffi.md)
- [API Options](config_api.md)
- [Crate name override](config_name_override.md)
- [Tutorial](tutorial/introduction.md)
- [Preparation](tutorial/preparation.md)
- [Finding .gir files](tutorial/finding_gir_files.md)
- [Generating the FFI library](tutorial/sys_library.md)
- [Generating the Rust API](tutorial/high_level_rust_api.md)
- [Handling generation errors](tutorial/handling_errors.md)
- [Generating documentation](generate_docs.md)
- [Generating documentation](tutorial/generate_docs.md)
- [Configuration files](config/introduction.md)
- [FFI Options](config/ffi.md)
- [API Options](config/api.md)
- [Crate name override](config/name_override.md)
104 changes: 62 additions & 42 deletions book/src/config_api.md → book/src/config/api.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# API Options

This mode requires you to write another TOML file. [gtk/Gir.toml](https://github.com/gtk-rs/gtk/blob/master/Gir.toml) is a good example.
This mode requires you to write another TOML file.
[gtk/Gir.toml](https://github.com/gtk-rs/gtk/blob/master/Gir.toml) is a good example.

```toml
[options]
Expand Down Expand Up @@ -40,14 +41,17 @@ disable_format = true
generate_builder = true
```

This mode generates only the specified objects. You can either add the object's fullname to the `generate` array or add it to the `manual` array (but in this case, it won't be generated, just used in other functions/methods instead of generating an "ignored" argument). Example:
This mode generates only the specified objects.
You can either add the object's fullname to the `generate` array or add it to the `manual` array (but in this case, it won't be generated, just used in other functions/methods instead of generating an "ignored" argument).
Example:

```toml
generate = ["Gtk.Widget", "Gtk.Window"]
manual = ["Gtk.Button"]
```

So in here, both `GtkWidget` and `GtkWindow` will be fully generated and functions/methods using `GtkButton` will be uncommented. To generate code for all global functions, add `Gtk.*` to the `generate` array.
So in here, both `GtkWidget` and `GtkWindow` will be fully generated and functions/methods using `GtkButton` will be uncommented.
To generate code for all global functions, add `Gtk.*` to the `generate` array.

To also generate a `Builder` struct for a widget, it needs to be set with the `generate_builder` flag in object configuration:

Expand Down Expand Up @@ -303,7 +307,8 @@ status = "generate"
generate_doc = false
```

Which will prevent gir from generating `stock_list_ids`. If you want to specify
Which will prevent gir from generating `stock_list_ids`.
If you want to specify
that a function will be manually implemented, you can use:

```toml
Expand Down Expand Up @@ -339,10 +344,13 @@ status = "generate"
Constants also support `version` and `cfg_condition` fields.

In various cases, GObjects or boxed types can be used from multiple threads
and have certain concurrency guarantees. This can be configured with the
`concurrency` setting at the top-level options or per object. It will
and have certain concurrency guarantees.
This can be configured with the
`concurrency` setting at the top-level options or per object.
It will
automatically implement the `Send` and `Sync` traits for the resulting object
and set appropriate trait bounds for signal callbacks. The default is `none`,
and set appropriate trait bounds for signal callbacks.
The default is `none`,
and apart from that `send` and `send+sync` are supported.

```toml
Expand All @@ -358,7 +366,8 @@ concurrency = "send+sync"

Note that `send` is only valid for types that are either not reference counted
(i.e. `clone()` copies the object) or that are read-only (i.e. no API for
mutating the object exists). `send+sync` is valid if the type can be sent to
mutating the object exists).
`send+sync` is valid if the type can be sent to
different threads and all API allows simultaneous calls from different threads
due to internal locking via e.g. a mutex.

Expand All @@ -376,7 +385,8 @@ types are wrong in autogenerated functions that have such objects as argument.
This can be overridden with the `ref_mode` configuration.

Getters are automatically renamed to comply with Rust codying style guidelines.
However, this can cause name clashes with existing functions. If you want to
However, this can cause name clashes with existing functions.
If you want to
bypass the automatic renaming mechanism, use `bypass_auto_rename = true`:

```toml
Expand All @@ -389,7 +399,8 @@ name = "Gtk.TextBuffer"
bypass_auto_rename = true
```

Some constructors are not annotated as `constructor` in the `gir` files. In
Some constructors are not annotated as `constructor` in the `gir` files.
In
order for the naming convention to be applied, you can force a function to be
considered as a constructor:

Expand All @@ -403,10 +414,13 @@ constructor = true
## conversion_type "Option"

The `conversion_type` variant `Option` is available for types `T` implementing
`glib::TryFromGlib<Error=GlibNoneError>`. As a reminder, this allows
`glib::TryFromGlib<Error=GlibNoneError>`.
As a reminder, this allows
implementing `FromGlib` for `Option<T>` and usually goes alongside with `ToGlib`
for both `T` and `Option<T>`. In this case, `Option<T>` will be used for return
values (including ffi output arguments). For in-arguments, except if the
for both `T` and `Option<T>`.
In this case, `Option<T>` will be used for return
values (including ffi output arguments).
For in-arguments, except if the
parameter is declared `mandatory`, `impl Into<Option<T>>` so that either an
`Option<T>` or `T` can be used.

Expand All @@ -424,7 +438,8 @@ The type `ClockTime` implements `glib::TryFromGlib<Error=GlibNoneError>` (and
`Option<ClockTime>`.

Additionally, the user can instruct `gir` to `expect` `Some` or `Ok` results for
specific arguments or return values. E.g.:
specific arguments or return values.
E.g.:

``` rust
[[object]]
Expand All @@ -438,12 +453,9 @@ manual_traits = ["ClockExtManual"]
mandatory = true
```

In the above example, the user instructs gir to consider the `internal` argument
(which also happens to be an out argument) with type gir `Gst.ClockTime` can be
represented as a `ClockTime` without the `Option`. This argument is actually
part of a set of output arguments. With the above gir declaration, the generated
signature is the following (the implementation takes care of `expect`ing the
value to be defined):
In the above example, the user instructs gir to consider the `internal` argument (which also happens to be an out argument) with type gir `Gst.ClockTime` can be represented as a `ClockTime` without the `Option`.
This argument is actually part of a set of output arguments.
With the above gir declaration, the generated signature is the following (the implementation takes care of `expect`ing the value to be defined):

``` rust
fn get_calibration(
Expand Down Expand Up @@ -471,17 +483,19 @@ For a return value, the mandatory declaration reads:

The `conversion_type` variant `Result` is available for types `T` implementing
`glib::TryFromGlib<Error=Err>` where `Err` is neither `GlibNoneError` nor
`GlibNoneOrInvalidError`. In this case, `Result<T, ErrorType>` will be used for
`GlibNoneOrInvalidError`.
In this case, `Result<T, ErrorType>` will be used for
return values (including `ffi` output arguments) and the type itself in argument
position.

In `gstreamer-rs`, the C type `GstStateChangeReturn` can represent both a
successful or an error return value. In Rust, the `Result` `enum` is the
idiomatic way of returning an error. In `gstreamer-rs`, bindings to functions
returning `GstStateChangeReturn` had to be manually implemented so as to return
`Result<StateChangeSuccess, StateChangeError>`. Note that in this case, the type
implementing `TryFromGlib` is `StateChangeSuccess` and not
`GstStateChangeReturn`. These functions can be auto-generated using:
successful or an error return value.
In Rust, the `Result` `enum` is the idiomatic way of returning an error.
In `gstreamer-rs`, bindings to functions
returning `GstStateChangeReturn` had to be manually implemented so as to return `Result<StateChangeSuccess, StateChangeError>`.
Note that in this case, the type implementing `TryFromGlib` is `StateChangeSuccess` and not
`GstStateChangeReturn`.
These functions can be auto-generated using:

``` rust
[[object]]
Expand All @@ -497,18 +511,15 @@ must_use = true
## Boxed types vs. BoxedInline types

For boxed types / records, gir auto-detects `copy`/`free` or `ref`/`unref`
function pairs for memory management on records. It falls back to generic
`g_boxed_copy`/`g_boxed_free` if these are not found, based on an existing
implementation of `get_type`. Otherwise no record implementation can be
generated.
function pairs for memory management on records.
It falls back to generic `g_boxed_copy`/`g_boxed_free` if these are not found, based on an existing implementation of `get_type`.
Otherwise no record implementation can be generated.

This works for the majority of boxed types, which are literally boxed: their
memory is always allocated on the heap and memory management is left to the C
library. Some boxed types, however, are special and in C code they are usually
allocated on the stack or inline inside another struct. As such, their struct
definition is public and part of the API/ABI. Usually these types are
relatively small and allocated regularly, which would make heap allocations
costly.
memory is always allocated on the heap and memory management is left to the C library.
Some boxed types, however, are special and in C code they are usually allocated on the stack or inline inside another struct.
As such, their struct definition is public and part of the API/ABI.
Usually these types are relatively small and allocated regularly, which would make heap allocations costly.

These special boxed types are usually allocated by the caller of the C
functions, and the functions are then only filling in the memory and taking
Expand All @@ -533,7 +544,8 @@ from one value into another one, and to free any resources that might be
stored in values of that boxed types.

By default the memory is zero-initialized and copying is done via
`std::ptr::copy()`. If the boxed type contains memory that needs to be freed
`std::ptr::copy()`.
If the boxed type contains memory that needs to be freed
then these functions must be provided.

The following configuration is equivalent with the one above.
Expand All @@ -550,13 +562,17 @@ clear_function_expression = "|_ptr| ()"

## Generation in API mode

To generate the Rust-user API level, The command is very similar to the previous one. It's better to not put this output in the same directory as where the FFI files are. Just run:
To generate the Rust-user API level, The command is very similar to the previous one.
It's better to not put this output in the same directory as where the FFI files are.
Just run:

```sh
cargo run --release -- -c YourGirFile.toml -d ../gir-files -o the-output-directory
```

Now it should be done. Just go to the output directory (so `the-output-directory/auto` in our case) and try to build using `cargo build`. Don't forget to update your dependencies in both projects: nothing much to do in the FFI/sys one but the Rust-user API level will need to have a dependency over the FFI/sys one.
Now it should be done.
Just go to the output directory (so `the-output-directory/auto` in our case) and try to build using `cargo build`.
Don't forget to update your dependencies in both projects: nothing much to do in the FFI/sys one but the Rust-user API level will need to have a dependency over the FFI/sys one.

Now, at your crate entry point (generally `lib.rs`), add the following to include all generated files:

Expand All @@ -566,7 +582,8 @@ pub use auto::*;

## Add manual bindings alongside generated code

Unfortunately, `gir` isn't perfect (yet) and will certainly not be able to generate all the code on its own. So here's what a `gir` generated folder looks like:
Unfortunately, `gir` isn't perfect (yet) and will certainly not be able to generate all the code on its own.
So here's what a `gir` generated folder looks like:

```text
- your_folder
Expand All @@ -580,7 +597,10 @@ Unfortunately, `gir` isn't perfect (yet) and will certainly not be able to gener
|- (all files generated by gir)
```

You can add your manual bindings directly inside the `src` folder (at the same level as `lib.rs`). Then don't forget to reexport them. Let's say you added a `Color` type in a `color.rs` file. You need to add in `lib.rs`:
You can add your manual bindings directly inside the `src` folder (at the same level as `lib.rs`).
Then don't forget to reexport them.
Let's say you added a `Color` type in a `color.rs` file.
You need to add in `lib.rs`:

```rust
// We make the type public for the API users.
Expand Down
29 changes: 14 additions & 15 deletions book/src/config_ffi.md → book/src/config/ffi.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
# FFI Options

In FFI (`-m sys`) mode, `gir` generates as much as it can. So in this mode, the TOML file is mostly used to ignore some objects. To do so, you need to add its fullname to an `ignore` array. Example:
In FFI (`-m sys`) mode, `gir` generates as much as it can.
So in this mode, the TOML file is mostly used to ignore some objects.
To do so, you need to add its fullname to an `ignore` array.
Example:

```toml
ignore = ["Gtk.Widget", "Gtk.Window"]
```

And that's all! Neither `GtkWidget` nor `GtkWindow` (alongside with their functions) will be generated.
And that's all.
Neither `GtkWidget` nor `GtkWindow` (alongside with their functions) will be generated.

You also need to add any needed external libraries in the "external_libraries" parameter. Example:
You also need to add any needed external libraries in the "external_libraries" parameter.
Example:

```toml
[options]
Expand Down Expand Up @@ -52,16 +57,6 @@ dependencies = [
]
```

You can mark some functions that has suffix `_utf8` on Windows:

```toml
[[object]]
name = "GdkPixbuf.PixbufAnimation"
status = "generate"
[[object.function]]
name = "new_from_file"
```

Also, you can add rust cfg conditions on objects, functions and constants, for example, when flagging for conditional compilation:

```toml
Expand All @@ -76,12 +71,16 @@ cfg_condition = "feature = \"egl\""

## Generation in FFI mode

When you're ready, let's generate the FFI part. In the command we'll execute, `../gir-files` is where the directory with your `.gir` files is. (But again, you can just clone the [gir-files repository](https://github.com/gtk-rs/gir-files) and add your file(s) in it). Then let's run the command:
When you're ready, let's generate the FFI part.
In the command we'll execute, `../gir-files` is where the directory with your `.gir` files is.
(But again, you can just clone the [gir-files repository](https://github.com/gtk-rs/gir-files) and add your file(s) in it).
Then let's run the command:

```sh
cargo run --release -- -c YourSysGirFile.toml -d ../gir-files -m sys -o the-output-directory-sys
```

The generated files will be placed in `the-output-directory-sys`. Just take care about the dependencies and the crate's name generated in the `Cargo.toml` file (update them if they don't work as expected).
The generated files will be placed in `the-output-directory-sys`.
Just take care about the dependencies and the crate's name generated in the `Cargo.toml` file (update them if they don't work as expected).

You now have the sys part of your binding!
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Configuration

GIR uses two configurations files, one for generating the FFI part of the bindings and the other file for the Rust API. The configuration files must be named `Gir.toml`
GIR uses two configurations files, one for generating the FFI part of the bindings and the other file for the Rust API.
The configuration files must be named `Gir.toml`

- The FFI configuration allows things such as ignoring objects, overriding the minimum required version for a specific type or renaming the generated crate name.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Crate name overrides

`gir` uses simple rule to convert a namespace to a crate name and it sometimes goes wrong. For example, "WebKit2WebExtension" namespace will be converted to "web_kit2_web_extension", which looks bad.
`gir` uses simple rule to convert a namespace to a crate name and it sometimes goes wrong.
For example, "WebKit2WebExtension" namespace will be converted to "web_kit2_web_extension", which looks bad.

To fix it, the `crate_name_overrides` option can be used.

Expand Down
32 changes: 0 additions & 32 deletions book/src/generate_docs.md

This file was deleted.

Loading

0 comments on commit 43b9242

Please sign in to comment.