1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
//! Proc macros for [Interoptopus](https://github.com/ralfbiedert/interoptopus). //! //! Items in here will be re-exported by [the main crate](https://crates.io/crates/interoptopus). extern crate proc_macro; // Apparently needed to be imported like this. mod constants; mod functions; mod types; mod util; use proc_macro::TokenStream; use syn::{parse_macro_input, AttributeArgs}; /// Enable a `struct` or `enum` to appear in generated bindings. /// /// This will derive [`CTypeInfo`](interoptopus::lang::rust::CTypeInfo) based on the _visible_ information in the type definition. This /// is the preferred way of enabling FFI types; although in some cases (e.g., when dealing with /// types outside of your control) you will have to implement a **surrogate** manually, see below. /// /// A number of attributes are available: /// /// | Attribute | On | Explanation | /// | --- | --- | --- | /// | `name="X"` | `struct`,`enum` | Uses `name` as the base interop name instead of the item's Rust name.<sup>1</sup> | /// | `namespace="X"` | `struct`,`enum` | Determine which namespace or file item should go. <sup>2</sup> /// | `skip(x)` | `struct,enum` | Skip field or variant `x` in the definition, e.g., some `x` of [`PhantomData`](std::marker::PhantomData). <sup>⚠️</sup> /// | `patterns(p)` | `struct`,`enum` | Mark this type as part of a pattern, see below. <sup>2</sup> /// | `opaque` | `struct` | Creates an opaque type without fields. Can only be used behind a pointer. | /// | `surrogates(x="f")` | `struct` | Invoke function `f` to provide a [`CTypeInfo`](interoptopus::lang::rust::CTypeInfo) for field `x`, see below. <sup>⚠️</sup> /// | `visibility(x="v")` | `struct` | Override visibility for field `x` as `public` or `private`; `_` means all fields. <sup>2</sup> /// | `debug` | * | Print generated helper code in console. /// | `unsafe` | * | Unlocks unsafe options marked: <sup>⚠️</sup> /// /// <sup>1</sup> While a type's name must be unique (even across modules) backends are free to further transform this name, e.g., by converting /// `MyVec` to `LibraryMyVec`. In other words, using `name` will change a type's name, but not using `name` is no guarantee the final name will /// not be modified. /// /// <sup>2</sup> Will not be reflected in C backend, but available to languages supporting them, /// e.g., C# will emit field visibility and generate classes from service patterns. /// /// <sup>⚠️</sup> This attribute can lead to undefined behavior when misapplied. You should only /// suppress fields that have no impact on the type layout (e.g., zero-sized `Phantom` data). /// When using surrogates you must ensure the surrogate matches. /// /// /// # Including Types /// /// In contrast to functions and constants types annotated with `#[ffi_type]` will be detected /// automatically and do not have to be explicitly mentioned for the definition of the `inventory!()`. /// /// # Surrogates /// /// When dealing with types outside of your control you will not be able to implement [`CTypeInfo`](interoptopus::lang::rust::CTypeInfo) for them. /// Instead you need a **surrogate**, a helper function which returns that info for the type. /// /// The surrogate's signature is: /// /// ```rust /// # use interoptopus::lang::c::CType; /// fn some_foreign_type() -> CType { /// // Return an appropriate CType /// # interoptopus::lang::c::CType::Primitive(interoptopus::lang::c::PrimitiveType::U8) /// } /// ``` /// /// # Patterns /// /// Patterns allow you to write, and backends to generate more idiomatic code. The following /// patterns are currently supported by this annotation: /// /// | Pattern | On | Explanation | /// | --- | --- | --- | /// | `success_enum` | `enum` | Denotes this as a [`SuccessEnum`](interoptopus::patterns::successenum::SuccessEnum). | /// /// # Examples /// /// ``` /// use interoptopus::ffi_type; /// /// #[ffi_type(opaque, name = "MyVec")] /// #[derive(Copy, Clone, Debug)] /// #[repr(C)] /// pub struct Vec2f32 { /// pub x: f32, /// pub y: f32, /// pub z: f32, /// } /// ``` /// #[proc_macro_attribute] // Can now be used as `#[my_attribute]` pub fn ffi_type(attr: TokenStream, item: TokenStream) -> TokenStream { let input = proc_macro2::TokenStream::from(item); let attr_args = parse_macro_input!(attr as AttributeArgs); let rval = types::ffi_type(attr_args, input); rval.into() } /// Enable an `extern "C"` function to appear in generated bindings. /// /// This will derive [`FunctionInfo`](interoptopus::lang::rust::FunctionInfo) for a helper struct /// of the same name containing the function's name, parameters and return value. /// /// The following attributes can be provided: /// /// | Attribute | Explanation | /// | --- | --- | /// | `surrogates(x="y")` | Invoke function `y` to provide a [`CTypeInfo`](interoptopus::lang::rust::CTypeInfo) for parameter `x`, see below. <sup>⚠️</sup> /// | `debug` | Print generated helper code in console. /// | `unsafe` | Unlocks unsafe options marked: <sup>⚠️</sup> /// /// <sup>⚠️</sup> This attribute can lead to undefined behavior when misapplied. /// When using surrogates you must ensure the surrogate matches the parameter's type. /// /// # Surrogates /// /// When dealing with types outside of your control you will not be able to implement [`CTypeInfo`](interoptopus::lang::rust::CTypeInfo) for them. /// Instead you need a **surrogate**, a helper function which returns that info for the type. /// /// The surrogate's signature is: /// /// ```rust /// # use interoptopus::lang::c::CType; /// fn some_foreign_type() -> CType { /// // Return an appropriate CType /// # interoptopus::lang::c::CType::Primitive(interoptopus::lang::c::PrimitiveType::U8) /// } /// ``` /// /// # Example /// /// ``` /// use interoptopus::ffi_function; /// /// #[ffi_function] /// #[no_mangle] /// pub extern "C" fn my_function(x: u32) -> u32 { /// x /// } /// ``` #[proc_macro_attribute] // Can now be used as `#[my_attribute]` pub fn ffi_function(attr: TokenStream, item: TokenStream) -> TokenStream { let input = proc_macro2::TokenStream::from(item); let attr_args = parse_macro_input!(attr as AttributeArgs); let rval = functions::ffi_function(attr_args, input); rval.into() } /// Enables a `const` to appear in generated bindings. /// /// This will derive [`ConstantInfo`](interoptopus::lang::rust::ConstantInfo) for a helper struct of the /// same name containing the const's name and value. /// /// Constant evaluation is supported. /// /// In order to appear in generated bindings the constant has to be mentioned in the definition /// of the libaries `inventory_function!()`. /// /// # Examples /// /// ``` /// use interoptopus::ffi_constant; /// # const fn double(x: u8) -> u8 { 2 * x } /// /// #[ffi_constant] /// const SOME_CONST: u32 = 314; /// /// #[ffi_constant] /// const COMPUTED_CONST: u8 = double(12); // will export 24 /// /// ``` #[proc_macro_attribute] // Can now be used as `#[my_attribute]` pub fn ffi_constant(attr: TokenStream, item: TokenStream) -> TokenStream { let input = proc_macro2::TokenStream::from(item); let attr_args = parse_macro_input!(attr as AttributeArgs); let rval = constants::ffi_constant(attr_args, input); rval.into() }