Skip to content

Commit b8d163a

Browse files
committed
C binding experiments
Simplify conversion functions Reorder padding/margin examples Add getter example Return error code rather than panicking on null style pointer cargo fmt Documentation get_style and with_style_mut macros Split FFI into multiple files Rename api module to style Make style getters/setters unsafe Add grid placement APIs Prefix style methods with TaffyStyle Move c bindings to an external crate Eliminate boxes and raw pointers from C api cargo fmt Make function UpperCamelCase with underscore between struct name and function name Use repr(C) instead of repr(u8) Replace trbl function with function with dynamic edge parameter Implement getters/setters for all non-grid numeric style properties Format grid style Update style size tests to include alignment Add Overflow to prelude Remove padding trbl function Implement Display, Position, Overflow Start generating bindings Add style getters/setters for enum styles Add abstraction for f32 getters/setters Use individual unit and value for style value setters Use TaffyStyleConstRef and TaffyStyleMutRef types fmt + clippy fmt prelude Use generic result struct Prefix enum variant names + make screaming snake case Core: Add try_style_mut function to Taffy struct Refactor error handling + add initial tree manipulation functions Get "basic" example running via C bindings Fix clippy lint Allow AvailableSpace to be specified in TaffyTree_ComputeLayout Exclude example binaries from git Rename StyleValueUnit to TaffyUnit Ensure all types are prefixed by Taffy Add style getter/setters for grid row Add TaffyTree_GetLayout method Remove bindgen from compile_basic.sh README WIP README WIP Fix build Fix markdown lints Fix bindings after rebase Add ability to set measure function Add script to regenerate header file Add CI task to build C bindings example Remove result types from style getters Move c bindings to bindings/c directory Fix build after rebase Use nightly toolchain for c bindings (to enable cbindgen to work) Fix c bindings ci Ignore scratch dir Signed-off-by: Nico Burns <[email protected]>
1 parent ef85431 commit b8d163a

File tree

22 files changed

+2211
-36
lines changed

22 files changed

+2211
-36
lines changed

.github/workflows/ci.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,3 +294,19 @@ jobs:
294294
name: Build benchmarks (w/yoga)
295295
env:
296296
RUSTFLAGS: "-C opt-level=0"
297+
298+
build-c-bindings:
299+
name: Build C Bindings
300+
runs-on: ubuntu-latest
301+
steps:
302+
- uses: actions/checkout@v4
303+
- uses: dtolnay/rust-toolchain@stable
304+
- run: |
305+
cd bindings/c
306+
cargo build
307+
name: Build ctaffy library
308+
- run: |
309+
cd bindings/c/examples
310+
./compile_basic.sh
311+
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../../../target/debug ./basic
312+
name: Build C Bindings

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
/yoga_test_fixtures
55
/yoga_test_fixtures_grouped
66
/test_fixtures/_scratch
7+
_scratch
78

89
**/*.rs.bk
910
Cargo.lock

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ members = [
107107
"scripts/import-yoga-tests",
108108
"benches",
109109
"tests/common",
110+
"bindings/c"
110111
]
111112
# The cosmic_text example is excluded from the workspace as including it breaks compilation
112113
# of all crates in the workspace with our MSRV compiler

bindings/c/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
examples/basic

bindings/c/Cargo.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[package]
2+
name = "ctaffy"
3+
version = "0.0.1"
4+
authors = [
5+
"Nico Burns <[email protected]>",
6+
]
7+
edition = "2021"
8+
include = ["src/**/*", "Cargo.toml"]
9+
description = "C bindings to Taffy (A flexible UI layout library)"
10+
repository = "https://github.com/DioxusLabs/taffy"
11+
license = "MIT"
12+
13+
[lib]
14+
name = "ctaffy"
15+
crate-type = ["staticlib", "cdylib", "rlib"]
16+
17+
[dependencies]
18+
taffy = { path = "../.." }

bindings/c/README.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# C API for Taffy (ctaffy)
2+
3+
Taffy is a flexible, high-performance, cross-platform UI layout library written in Rust.
4+
5+
This directory contains C bindings for Taffy. The API is a pure C API (no C++ features are used), and is designed to be easy to build other language bindings on top of. In addition to the documentation below, you may to read through the header file (`include/taffy.h`).
6+
7+
## Examples
8+
9+
There are readable examples in the examples directory.
10+
11+
Assuming you have Rust and Cargo installed (and a C compiler), then this should work to run the basic example:
12+
13+
```bash
14+
git clone https://github.com/DioxusLabs/taffy.git
15+
cd taffy/ctaffy/examples
16+
./compile-basic.sh
17+
./basic
18+
```
19+
20+
## Naming Conventions
21+
22+
- Everything in the Taffy C API is prefixed with `Taffy`, except enum variant names which are prefixed with `TAFFY_`
23+
- Structs and Enums are named in UpperCamelCase (e.g. `TaffyTree`, `TaffyStyle`)
24+
- Functions begin with the name of the struct they apply to, followed by an underscore, followed by the name of the function in UpperCamelCase (e.g. `TaffyTree_New`, `TaffyStyle_SetFlexBasis`)
25+
- Enum variants are SCREAMING_SNAKE_CASE
26+
27+
## Error Handling
28+
29+
Error handling is managed by the use of return codes and "result" structs. All functions in the API return either an `enum TaffyReturnCode` or one of the `struct Taffy*Result` structs (or `void` in the case of infallible operations that don't return anything).
30+
31+
### Return codes
32+
33+
Error handling is managed by the use of an enum `TaffyReturnCode`:
34+
35+
```c
36+
typedef enum TaffyReturnCode {
37+
TAFFY_RETURN_CODE_OK,
38+
TAFFY_RETURN_CODE_NULL_STYLE_POINTER,
39+
TAFFY_RETURN_CODE_NULL_TREE_POINTER,
40+
// ... (see header file for full definition)
41+
} TaffyReturnCode;
42+
```
43+
44+
`TAFFY_RETURN_CODE_OK` indicates that the operation succeeded. All other variant indicate
45+
46+
### Result structs
47+
48+
"Result structs" are used for functions that need to return another value in addition to a `TaffyReturnCode` indicating success/failure (such as style getters which need to return the relevant style value). As C doesn't support generic structs, there are several "Result structs": one for each type of value. But each struct follows the same structure as the following example (varying only in the name of the struct and the type of the `value` field):
49+
50+
<table>
51+
<tr><th>TaffyIntResult</th><th>TaffyDimensionResult</th></tr>
52+
<tr>
53+
<td>
54+
55+
```c
56+
typedef struct TaffyIntResult {
57+
enum TaffyReturnCode return_code;
58+
int32_t value;
59+
} TaffyIntResult;
60+
```
61+
62+
</td>
63+
<td>
64+
65+
```c
66+
typedef struct TaffyDimensionResult {
67+
enum TaffyReturnCode return_code;
68+
struct TaffyDimension value;
69+
} TaffyDimensionResult;
70+
```
71+
72+
</td>
73+
</tr>
74+
</table>
75+
76+
Functions that return Result structs will either return a `TAFFY_RETURN_CODE_OK` along with a meaningful value, or a error variant of `TaffyReturnCode` along with
77+
78+
## API Usage
79+
80+
### Tree Creation and Manipulation
81+
82+
The `TaffyTree` struct is the entrypoint to the Taffy C API and represents an entire tree of UI nodes. Taffy uses arena allocation, so the `TaffyTree` owns the entire tree of nodes at all times.
83+
84+
You only ever get access to a `TaffyNodeId` handle which can be used to manipulate the structure of the tree, or pointers to `TaffyStyle` object (which can be used to set styles on a Node, but are considered borrowed pointers and thus must only be held temporarily).
85+
86+
#### Lifecycle
87+
88+
- `TaffyTree_New` allocates a new `TaffyTree` and returns an owned pointer to it.
89+
- `TaffyTree_Free` can be used to free the tree once you are done with it.
90+
91+
All other functions in the API which accept a pointer to a `TaffyTree` have borrowing semantics: they access the tree during the duration of the function (and if the pointer is not a `const` pointer, may modify the tree), but will not store the pointer or take ownership of the tree.
92+
93+
#### Node creation and manipulation
94+
95+
- `TaffyTree_NewNode` creates a new Node within the tree and returns a `TaffyNodeId` handle to it. The node will initially have the default styles
96+
97+
### Setting styles on node

bindings/c/cbindgen.toml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
language = "c"
2+
cpp_compat = true
3+
documentation_style = "c99"
4+
line_length = 120
5+
6+
[enum]
7+
rename_variants = "QualifiedScreamingSnakeCase"
8+
9+
[export]
10+
include = ["TaffyNodeId"]
11+
12+
[export.rename]
13+
TaffyResult_f32 = "TaffyFloatResult"
14+
TaffyResult_i32 = "TaffyIntResult"
15+
TaffyResult_TaffyNodeId = "TaffyNodeIdResult"
16+
TaffyResult_TaffyDimension = "TaffyDimensionResult"
17+
TaffyResult_TaffyGridPlacement = "TaffyGridPlacementResult"
18+
TaffyResult_TaffyStyleMutRef = "TaffyStyleMutRefResult"
19+
20+
[parse.expand]
21+
crates = ["ctaffy"]
22+

bindings/c/examples/basic.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include <stdlib.h>
2+
#include <stdint.h>
3+
#include <math.h>
4+
#include <stdio.h>
5+
6+
#include "taffy.h"
7+
8+
int main() {
9+
// Create tree
10+
TaffyTree *tree = TaffyTree_New();
11+
12+
// Create child (+set styles)
13+
TaffyNodeId child = TaffyTree_NewNode(tree).value;
14+
TaffyStyle *child_style = TaffyTree_GetStyleMut(tree, child).value;
15+
TaffyStyle_SetWidth(child_style, 0.5, TAFFY_UNIT_PERCENT);
16+
TaffyStyle_SetHeight(child_style, 0, TAFFY_UNIT_AUTO);
17+
18+
// Create parent (+set styles)
19+
TaffyNodeId parent = TaffyTree_NewNode(tree).value;
20+
TaffyStyle *parent_style = TaffyTree_GetStyleMut(tree, parent).value;
21+
TaffyStyle_SetWidth(parent_style, 100, TAFFY_UNIT_LENGTH);
22+
TaffyStyle_SetHeight(parent_style, 100, TAFFY_UNIT_LENGTH);
23+
TaffyStyle_SetJustifyContent(parent_style, TAFFY_ALIGN_CONTENT_CENTER);
24+
25+
// Setup parent-child relationship
26+
TaffyTree_AppendChild(tree, parent, child);
27+
28+
// Compute layout (100x100 viewport)
29+
printf("\nCompute layout with 100x100 viewport:\n");
30+
TaffyTree_ComputeLayout(tree, parent, 100, 100);
31+
TaffyTree_PrintTree(tree, parent);
32+
33+
// Compute layout (infinite viewport)
34+
printf("\nCompute layout with infinite viewport:\n");
35+
TaffyTree_ComputeLayout(tree, parent, INFINITY, INFINITY);
36+
TaffyTree_PrintTree(tree, parent);
37+
38+
// Free tree
39+
TaffyTree_Free(tree);
40+
return 0;
41+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/sh
2+
3+
set -ex
4+
5+
cargo build --manifest-path ../Cargo.toml
6+
gcc -O3 -DDEBUG -o basic basic.c -std=c99 -Wall -I../include -L../../../target/debug -lctaffy

bindings/c/generate-bindings.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/sh
2+
3+
cbindgen --crate ctaffy --output include/taffy.h

0 commit comments

Comments
 (0)