ffi_convert_derive/lib.rs
1//! Derive macros for the conversion traits provided by the
2//! [`ffi-convert`](https://docs.rs/ffi-convert) crate.
3//!
4//! The four derives are also re-exported from `ffi-convert`, so users of
5//! `ffi-convert` typically do not need to depend on this crate directly.
6//!
7//! See the top-level [`ffi-convert`](https://docs.rs/ffi-convert) documentation
8//! for the overall design, the type-mapping table, and the caveats that apply
9//! to all four derives. The per-macro documentation below lists the supported
10//! helper attributes.
11
12extern crate proc_macro;
13
14mod asrust;
15mod cdrop;
16mod creprof;
17mod rawpointerconverter;
18mod utils;
19
20use asrust::impl_asrust_macro;
21use cdrop::impl_cdrop_macro;
22use creprof::impl_creprof_macro;
23use proc_macro::TokenStream;
24use rawpointerconverter::impl_rawpointerconverter_macro;
25
26/// Derive [`CReprOf<T>`](../ffi_convert/trait.CReprOf.html) for a struct or unit enum.
27///
28/// Generates a consuming conversion from the idiomatic Rust type named in
29/// `#[target_type(...)]` to `Self`. C-string fields (pointers to `c_char`) are
30/// re-allocated as `CString`s, other pointer fields are boxed via
31/// [`RawPointerConverter::into_raw_pointer`](../ffi_convert/trait.RawPointerConverter.html),
32/// and remaining fields go through their own `CReprOf` impl.
33///
34/// # Struct-level attributes
35///
36/// - `#[target_type(Path)]` — **required**. The idiomatic Rust type this
37/// `#[repr(C)]` struct mirrors.
38///
39/// # Field-level attributes
40///
41/// - `#[nullable]` — required on every pointer field whose Rust counterpart is
42/// an [`Option`]. A `None` value is written as a null pointer.
43/// - `#[target_name(ident)]` — name of the matching field on the Rust side
44/// when it differs from the C-side name.
45/// - `#[c_repr_of_convert(expr)]` — replace the generated conversion with a
46/// custom expression. The owned Rust value `input: TargetType` is in scope.
47/// A field marked with this attribute is also skipped by the `AsRust`
48/// derive — if the reverse direction is needed, provide it with
49/// `#[as_rust_extra_field(...)]` on the struct.
50///
51/// # Enums
52///
53/// Enums are supported only if every variant is a unit variant.
54#[proc_macro_derive(
55 CReprOf,
56 attributes(target_type, nullable, c_repr_of_convert, target_name)
57)]
58pub fn creprof_derive(token_stream: TokenStream) -> TokenStream {
59 let ast = syn::parse(token_stream).unwrap();
60 impl_creprof_macro(&ast)
61}
62
63/// Derive [`AsRust<T>`](../ffi_convert/trait.AsRust.html) for a struct or unit enum.
64///
65/// Generates a non-consuming conversion that returns a freshly-allocated value
66/// of the type named in `#[target_type(...)]`. C-string fields are decoded as
67/// UTF-8 and copied; other pointer fields are borrowed via
68/// [`RawBorrow`](../ffi_convert/trait.RawBorrow.html) and then converted with
69/// their own `AsRust` impl; remaining fields go through their own `AsRust`
70/// impl directly.
71///
72/// The derived `AsRust` reads pointer fields under the same layout assumptions
73/// as `CReprOf` / `CDrop`; deriving all three together keeps them in sync.
74///
75/// # Struct-level attributes
76///
77/// - `#[target_type(Path)]` — **required**.
78/// - `#[as_rust_extra_field(name = expr)]` — initialise an extra field on the
79/// Rust side that has no C counterpart. The attribute can be repeated; `self`
80/// (the C-compatible value) is in scope inside `expr`, allowing
81/// reconstruction from unrelated C-side fields.
82///
83/// # Field-level attributes
84///
85/// - `#[nullable]` — map a null pointer to [`None`] instead of failing.
86/// - `#[target_name(ident)]` — name of the matching field on the Rust side
87/// when it differs from the C-side name.
88///
89/// A field annotated with `#[c_repr_of_convert(...)]` (see [`CReprOf`]) is
90/// skipped by this derive; pair it with `#[as_rust_extra_field]` if the Rust
91/// struct still has a matching field.
92///
93/// # Enums
94///
95/// Enums are supported only if every variant is a unit variant.
96#[proc_macro_derive(
97 AsRust,
98 attributes(
99 target_type,
100 nullable,
101 as_rust_extra_field,
102 as_rust_ignore,
103 target_name
104 )
105)]
106pub fn asrust_derive(token_stream: TokenStream) -> TokenStream {
107 let ast = syn::parse(token_stream).unwrap();
108 impl_asrust_macro(&ast)
109}
110
111/// Derive [`CDrop`](../ffi_convert/trait.CDrop.html) and (by default) [`Drop`]
112/// for a struct or unit enum.
113///
114/// The generated `do_drop` releases every owning pointer field by calling
115/// [`RawPointerConverter::drop_raw_pointer`](../ffi_convert/trait.RawPointerConverter.html),
116/// which takes the value back from the raw pointer and lets it drop. Non-pointer
117/// fields are left to Rust's regular drop glue.
118///
119/// Deriving [`CDrop`] assumes the struct owns its pointer fields and was initialized
120/// via `CReprOf::c_repr_of`. Derive `CReprOf` and `CDrop` together to keep their
121/// assumptions in sync.
122///
123/// The default output also emits a `Drop` impl that calls `do_drop`, so that
124/// letting a value go out of scope releases its pointer fields. A `CDrop`
125/// impl without a matching `Drop` leaks every pointer field on scope exit.
126///
127/// # Struct-level attributes
128///
129/// - `#[no_drop_impl]` — generate only the `CDrop` impl and skip the blanket
130/// `Drop` impl. Use this when you need a manual `Drop`; that manual `Drop`
131/// should call `do_drop`, otherwise the pointer fields leak.
132///
133/// # Field-level attributes
134///
135/// - `#[nullable]` — skip the free when the pointer is null. This is the same
136/// attribute that `CReprOf` and `AsRust` read on the field; annotate the
137/// field once and all three derives stay in sync.
138#[proc_macro_derive(CDrop, attributes(no_drop_impl, nullable))]
139pub fn cdrop_derive(token_stream: TokenStream) -> TokenStream {
140 let ast = syn::parse(token_stream).unwrap();
141 impl_cdrop_macro(&ast)
142}
143
144/// Derive [`RawPointerConverter<Self>`](../ffi_convert/trait.RawPointerConverter.html)
145/// for a struct.
146///
147/// The derived implementation boxes `self` into `*const Self` / `*mut Self`
148/// (and conversely). It is needed on any C-compatible struct that is reached
149/// through a raw pointer field in another C-compatible struct, because the
150/// derived [`CReprOf`] of the parent calls `into_raw_pointer()` on it.
151///
152/// No helper attributes.
153#[proc_macro_derive(RawPointerConverter)]
154pub fn rawpointerconverter_derive(token_stream: TokenStream) -> TokenStream {
155 let ast = syn::parse(token_stream).unwrap();
156 impl_rawpointerconverter_macro(&ast)
157}