Skip to content

Commit 863c2c6

Browse files
committed
Add bindings README
1 parent 80a1001 commit 863c2c6

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

lightning-c-bindings/README.md

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
The wrapper crate and C/C++ Headers in this folder are auto-generated from the Rust-Lightning
2+
source by the c-bindings-gen crate contained in the source tree and
3+
[cbindgen](https://github.com/eqrion/cbindgen). They are intended to be used as a base for building
4+
language-specific bindings, and are thus incredibly low-level and may be difficult to work with
5+
directly.
6+
7+
In other words, if you're reading this, you're either writing bindings for a new language, or
8+
you're in the wrong place - individual language bindings should come with their own documentation.
9+
10+
LDK C Bindings
11+
===================
12+
13+
The C bindings available at include/lightning.h require inclusion of include/rust_types.h first.
14+
15+
All of the Rust-Lightning types are mapped into C equivalents which take a few forms, namely:
16+
17+
* Structs are mapped into a simple wrapper containing a pointer to the native Rust-Lightning
18+
object and a flag to indicate whether the object is owned or only a reference. Such mappings
19+
usually generate a `X_free` function which must be called to release the allocated resources.
20+
Note that calling `X_free` will do nothing if the underlying pointer is NULL or if the reference
21+
flag is set.
22+
23+
You MUST NOT create such wrapper structs manually, relying instead on constructors which have
24+
been mapped from equivalent Rust constructors.
25+
26+
Note that, thanks to the is-reference flag, such structs effectively represent both `&RustThing`
27+
and `RustThing`. Further, the same applies to `Option<RustThing>`, in which cases `inner` may be
28+
set to NULL.
29+
30+
For example, this is the mapping of ChannelManager.
31+
```
32+
typedef struct MUST_USE_STRUCT LDKChannelManager {
33+
/** ... */
34+
LDKlnChannelManager *inner;
35+
bool _underlying_ref;
36+
} LDKChannelManager;
37+
```
38+
39+
* Traits are mapped into a concrete struct containing a void pointer and a jump table listing the
40+
functions which the trait must implement. The void pointer may be set to any value and is never
41+
interpreted (or dereferenced) by the bindings logic in any way. It is passed as the first
42+
argument to all function calls in the trait. You may wish to use it as a pointer to your own
43+
internal data structure, though it may also occasionally make sense to e.g. cast a file
44+
descriptor into a void pointer and use it to track a socket.
45+
46+
Each trait additionally contains a `free` and `clone` function pointer, which may be NULL. The
47+
`free` function is passed the void pointer when the object is `Drop`ed in Rust. The `clone`
48+
function is passed the void pointer when the object is `Clone`ed in Rust, returning a new void
49+
pointer for the new object.
50+
51+
For example, `LDKSocketDescriptor` is mapped as follows:
52+
```
53+
typedef struct LDKSocketDescriptor {
54+
void *this_arg;
55+
/** ... */
56+
uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);
57+
/** ... */
58+
void (*disconnect_socket)(void *this_arg);
59+
bool (*eq)(const void *this_arg, const void *other_arg);
60+
uint64_t (*hash)(const void *this_arg);
61+
void *(*clone)(const void *this_arg);
62+
void (*free)(void *this_arg);
63+
} LDKSocketDescriptor;
64+
```
65+
66+
* Rust structs that implement a trait result in the generation of an `X_as_Y` function which allows
67+
you to use the native Rust object in place of the trait. Such generated objects are only valid as
68+
long as the original Rust native object is owned by a C-wrapped struct, and has not been `free`'d
69+
or moved as a part of a Rust function call.
70+
71+
* Rust "unitary" enums are mapped simply as an equivalent C enum, however some Rust enums have
72+
variants which contain payloads. Such enums are mapped automatically by cbindgen as a tag which
73+
indicates the type and a union which holds the relevant fields for a given tag. A `X_free`
74+
function is provided for the enum as a whole which automatically frees the correct fields for a
75+
given tag, and a `Sentinel` tag is provided which causes the free function to do nothing (but
76+
which must never appear in an enum when accessed by Rust code). The `Sentinel` tag is used by
77+
the C++ wrapper classes to allow moving the ownership of an enum while invalidating the old copy.
78+
79+
* Struct member functions are mapped as `Struct_function_name` and take a reference to the mapped
80+
struct as their first argument. Free-standing functions are mapped simply as `function_name` and
81+
take the relevant mapped type arguments.
82+
83+
Functions may return a reference to an underlying Rust object with a mapped struct or an owned
84+
Rust object with the same. The mapped struct contains a flag to indicate if the poitned-to Rust
85+
object is owned or only a reference, and the object's corresponding free function will Do The
86+
Right Thing based on the flag. In order to determine the expected return type, you should
87+
reference the Rust documentation for the function.
88+
89+
Similarly, when a function takes an `Option<RustType>` as a parameter or a return value, the C
90+
type is the same as if it took only `RustType`, with the `inner` field set to NULL to indicate
91+
None. For example, `ChannelManager_create_channel` takes an `Option<LDKUserCOnfig>` not an
92+
`LDKUserConfig`, but its definition is:
93+
```
94+
MUST_USE_RES LDKCResult_NoneAPIErrorZ ChannelManager_create_channel(const LDKChannelManager *this_arg, ..., LDKUserConfig override_config);
95+
```
96+
97+
As the bindings are auto-generated, the best resource for documentation on them is the native Rust
98+
docs available via `cargo doc` or [docs.rs/lightning](https://docs.rs/lightning).
99+
100+
The memory model is largely the Rust memory model and not a native C-like memory model. Thus,
101+
function parameters are largely only ever passed by reference or by move, with pass-by-copy
102+
semantics only applying to primitive types. However, because the underlying types are largely
103+
pointers, the same function signature may imply two different memory ownership semantics. Thus, you
104+
MUST read the Rust documentation while using the C bindings. For functions which ownership is moved
105+
to Rust, the corresponding `X_fre`e function MUST NOT be called on the object, whereas for all other
106+
objects, `X_free` MUST be used to free resources.
107+
108+
LDK C++ Bindings
109+
================
110+
111+
The C++ bindings available at include/lightningpp.hpp require extern "C" inclusion of lightning.h
112+
and rust_types.h first. They represent thin wrappers around the C types which provide a few
113+
C++-isms to make memory model correctness easier to achieve. They provide:
114+
* automated destructors which call the relevant `X_free` C functions,
115+
* move constructors both from C++ classes and the original C struct, with the original object
116+
cleared to ensure destruction/`X_free` calls do not cause a double-free.
117+
* Move semantics via the () operator, returning the original C struct and clearing the C++ object.
118+
This allows calls such as `C_function(cpp_object)` which works as expected with move semantics.
119+
120+
In general, you should prefer to use the C++ bindings if possible, as they make memory leaks and
121+
other violations somewhat easier to avoid. Note that, because the C functions are not redefined in
122+
C++, all functions return the C type. Thus, you must bind returned values to the equivalent C++ type
123+
(replacing LDKX with LDK::X) to ensure the destructor is properly run. A demonstration of such usage
124+
is available at [demo.cpp](demo.cpp).
125+
126+
**It is highly recommended that you test any code which relies on the C (or C++) bindings in
127+
valgrind, MemorySanitizer, or other similar tools to ensure correctness.**
128+

0 commit comments

Comments
 (0)