1 | #![allow (clippy::needless_doctest_main)] |
2 | //! This crate `cpp` provides macros that allow embedding arbitrary C++ code. |
3 | //! |
4 | //! # Usage |
5 | //! |
6 | //! This crate must be used in tandem with the [`cpp_build`](https://docs.rs/cpp_build) crate. A basic Cargo |
7 | //! project which uses these projects would have a structure like the following: |
8 | //! |
9 | //! ```text |
10 | //! crate |
11 | //! |-- Cargo.toml |
12 | //! |-- src |
13 | //! |-- main.rs |
14 | //! |-- build.rs |
15 | //! ``` |
16 | //! |
17 | //! Where the files look like the following: |
18 | //! |
19 | //! #### Cargo.toml |
20 | //! |
21 | //! ```toml |
22 | //! [package] |
23 | //! build = "build.rs" |
24 | //! |
25 | //! [dependencies] |
26 | //! cpp = "0.5" |
27 | //! |
28 | //! [build-dependencies] |
29 | //! cpp_build = "0.5" |
30 | //! ``` |
31 | //! |
32 | //! #### build.rs |
33 | //! |
34 | //! ```no_run |
35 | //! extern crate cpp_build; |
36 | //! fn main() { |
37 | //! cpp_build::build("src/main.rs" ); |
38 | //! } |
39 | //! ``` |
40 | //! |
41 | //! #### main.rs |
42 | //! |
43 | //! ```ignore |
44 | //! # // tested in test/src/examples.rs |
45 | //! use cpp::cpp; |
46 | //! |
47 | //! cpp!{{ |
48 | //! #include <iostream> |
49 | //! }} |
50 | //! |
51 | //! fn main() { |
52 | //! let name = std::ffi::CString::new("World" ).unwrap(); |
53 | //! let name_ptr = name.as_ptr(); |
54 | //! let r = unsafe { |
55 | //! cpp!([name_ptr as "const char *" ] -> u32 as "int32_t" { |
56 | //! std::cout << "Hello, " << name_ptr << std::endl; |
57 | //! return 42; |
58 | //! }) |
59 | //! }; |
60 | //! assert_eq!(r, 42) |
61 | //! } |
62 | //! ``` |
63 | //! |
64 | //! # Build script |
65 | //! |
66 | //! Use the `cpp_build` crates from your `build.rs` script. |
67 | //! The same version of `cpp_build` and `cpp` crates should be used. |
68 | //! You can simply use the `cpp_build::build` function, or the `cpp_build::Config` |
69 | //! struct if you want more option. |
70 | //! |
71 | //! Behind the scene, it uses the `cc` crate. |
72 | //! |
73 | //! ## Using external libraries |
74 | //! |
75 | //! Most likely you will want to link against external libraries. You need to tell cpp_build |
76 | //! about the include path and other flags via `cpp_build::Config` and you need to let cargo |
77 | //! know about the link. More info in the [cargo docs](https://doc.rust-lang.org/cargo/reference/build-scripts.html). |
78 | //! |
79 | //! Your `build.rs` could look like this: |
80 | //! |
81 | //! ```no_run |
82 | //! fn main() { |
83 | //! let include_path = "/usr/include/myexternallib" ; |
84 | //! let lib_path = "/usr/lib/myexternallib" ; |
85 | //! cpp_build::Config::new().include(include_path).build("src/lib.rs" ); |
86 | //! println!("cargo:rustc-link-search={}" , lib_path); |
87 | //! println!("cargo:rustc-link-lib=myexternallib" ); |
88 | //! } |
89 | //! ``` |
90 | //! |
91 | //! (But you probably want to allow to configure the path via environment variables or |
92 | //! find them using some external tool such as the `pkg-config` crate, instead of hardcoding |
93 | //! them in the source) |
94 | //! |
95 | //! # Limitations |
96 | //! |
97 | //! As with all procedure macro crates we also need to parse Rust source files to |
98 | //! extract C++ code. That leads to the fact that some of the language features |
99 | //! might not be supported in full. One example is the attributes. Only a limited |
100 | //! number of attributes is supported, namely: `#[path = "..."]` for `mod` |
101 | //! declarations to specify an alternative path to the module file and |
102 | //! `#[cfg(feature = "...")]` for `mod` declarations to conditionally include the |
103 | //! module into the parsing process. Please note that the latter is only supported |
104 | //! in its simplest form: straight-forward `feature = "..."` without any |
105 | //! additional conditions, `cfg!` macros are also not supported at the moment. |
106 | //! |
107 | //! Since the C++ code is included within a rust file, the C++ code must obey both |
108 | //! the Rust and the C++ lexing rules. For example, Rust supports nested block comments |
109 | //! (`/* ... /* ... */ ... */`) while C++ does not, so nested comments not be used in the |
110 | //! `cpp!` macro. Also the Rust lexer will not understand the C++ raw literal, nor all |
111 | //! the C++ escape sequences within literal, so only string literals that are both valid |
112 | //! in Rust and in C++ should be used. The same applies for group separators in numbers. |
113 | //! Be careful to properly use `#if` / `#else` / `#endif`, and not have unbalanced delimiters. |
114 | |
115 | #![no_std ] |
116 | |
117 | #[macro_use ] |
118 | #[allow (unused_imports)] |
119 | extern crate cpp_macros; |
120 | #[doc (hidden)] |
121 | pub use cpp_macros::*; |
122 | |
123 | /// Internal macro which is used to locate the `rust!` invocations in the |
124 | /// C++ code embedded in `cpp!` invocation, to translate them into `extern` |
125 | /// functions |
126 | #[doc (hidden)] |
127 | #[macro_export ] |
128 | macro_rules! __cpp_internal { |
129 | (@find_rust_macro [$($a:tt)*] rust!($($rust_body:tt)*) $($rest:tt)*) => { |
130 | $crate::__cpp_internal!{ @expand_rust_macro [$($a)*] $($rust_body)* } |
131 | $crate::__cpp_internal!{ @find_rust_macro [$($a)*] $($rest)* } |
132 | }; |
133 | (@find_rust_macro [$($a:tt)*] ( $($in:tt)* ) $($rest:tt)* ) => |
134 | { $crate::__cpp_internal!{ @find_rust_macro [$($a)*] $($in)* $($rest)* } }; |
135 | (@find_rust_macro [$($a:tt)*] [ $($in:tt)* ] $($rest:tt)* ) => |
136 | { $crate::__cpp_internal!{ @find_rust_macro [$($a)*] $($in)* $($rest)* } }; |
137 | (@find_rust_macro [$($a:tt)*] { $($in:tt)* } $($rest:tt)* ) => |
138 | { $crate::__cpp_internal!{ @find_rust_macro [$($a)*] $($in)* $($rest)* } }; |
139 | (@find_rust_macro [$($a:tt)*] $t:tt $($rest:tt)*) => |
140 | { $crate::__cpp_internal!{ @find_rust_macro [$($a)*] $($rest)* } }; |
141 | (@find_rust_macro [$($a:tt)*]) => {}; |
142 | |
143 | (@expand_rust_macro [$($a:tt)*] $i:ident [$($an:ident : $at:ty as $ac:tt),*] {$($body:tt)*}) => { |
144 | #[allow(non_snake_case)] |
145 | #[allow(unused_unsafe)] |
146 | #[cfg_attr(feature = "cargo-clippy" , allow(clippy::forget_copy))] |
147 | #[cfg_attr(feature = "cargo-clippy" , allow(clippy::forget_ref))] |
148 | #[doc(hidden)] |
149 | $($a)* unsafe extern "C" fn $i($($an : *const $at),*) { |
150 | $(let $an : $at = unsafe { $an.read() };)* |
151 | (|| { $($body)* })(); |
152 | $(::core::mem::forget($an);)* |
153 | |
154 | } |
155 | }; |
156 | (@expand_rust_macro [$($a:tt)*] $i:ident [$($an:ident : $at:ty as $ac:tt),*] -> $rt:ty as $rc:tt {$($body:tt)*}) => { |
157 | #[allow(non_snake_case)] |
158 | #[allow(unused_unsafe)] |
159 | #[cfg_attr(feature = "cargo-clippy" , allow(clippy::forget_copy))] |
160 | #[cfg_attr(feature = "cargo-clippy" , allow(clippy::forget_ref))] |
161 | #[doc(hidden)] |
162 | $($a)* unsafe extern "C" fn $i($($an : *const $at, )* rt : *mut $rt) -> *mut $rt { |
163 | |
164 | $(let $an : $at = unsafe { $an.read() };)* |
165 | { |
166 | #[allow(unused_mut)] |
167 | let mut lambda = || {$($body)*}; |
168 | unsafe { ::core::ptr::write(rt, lambda()) }; |
169 | } |
170 | $(::core::mem::forget($an);)* |
171 | rt |
172 | } |
173 | }; |
174 | |
175 | (@expand_rust_macro $($invalid:tt)*) => { |
176 | compile_error!(concat!( "Cannot parse rust! macro: " , stringify!([ $($invalid)* ]) )) |
177 | }; |
178 | } |
179 | |
180 | /// This macro is used to embed arbitrary C++ code. |
181 | /// |
182 | /// There are two variants of the `cpp!` macro. The first variant is used for |
183 | /// raw text inclusion. Text is included into the generated `C++` file in the |
184 | /// order which they were defined, inlining module declarations. |
185 | /// |
186 | /// ```ignore |
187 | /// cpp! {{ |
188 | /// #include <stdint.h> |
189 | /// #include <stdio.h> |
190 | /// }} |
191 | /// ``` |
192 | /// |
193 | /// The second variant is used to embed C++ code within Rust code. A list of |
194 | /// variable names which should be captured are taken as the first argument, |
195 | /// with their corresponding C++ type. The body is compiled as a C++ function. |
196 | /// |
197 | /// This variant of the macro may only be invoked in expression context, and |
198 | /// requires an `unsafe` block, as it is performing FFI. |
199 | /// |
200 | /// ```ignore |
201 | /// let y: i32 = 10; |
202 | /// let mut z: i32 = 20; |
203 | /// let x: i32 = unsafe { cpp!([y as "int32_t" , mut z as "int32_t" ] -> i32 as "int32_t" { |
204 | /// z++; |
205 | /// return y + z; |
206 | /// })}; |
207 | /// ``` |
208 | /// |
209 | /// You can also put the unsafe keyword as the first keyword of the `cpp!` macro, which |
210 | /// has the same effect as putting the whole macro in an `unsafe` block: |
211 | /// |
212 | /// ```ignore |
213 | /// let x: i32 = cpp!(unsafe [y as "int32_t" , mut z as "int32_t" ] -> i32 as "int32_t" { |
214 | /// z++; |
215 | /// return y + z; |
216 | /// }); |
217 | /// ``` |
218 | /// |
219 | /// ## rust! pseudo-macro |
220 | /// |
221 | /// The `cpp!` macro can contain, in the C++ code, a `rust!` sub-macro, which allows |
222 | /// the inclusion of Rust code in C++ code. This is useful to |
223 | /// implement callback or override virtual functions. Example: |
224 | /// |
225 | /// ```ignore |
226 | /// trait MyTrait { |
227 | /// fn compute_value(&self, x : i32) -> i32; |
228 | /// } |
229 | /// |
230 | /// cpp!{{ |
231 | /// struct TraitPtr { void *a,*b; }; |
232 | /// class MyClassImpl : public MyClass { |
233 | /// public: |
234 | /// TraitPtr m_trait; |
235 | /// int computeValue(int x) const override { |
236 | /// return rust!(MCI_computeValue [m_trait : &MyTrait as "TraitPtr" , x : i32 as "int" ] |
237 | /// -> i32 as "int" { |
238 | /// m_trait.compute_value(x) |
239 | /// }); |
240 | /// } |
241 | /// } |
242 | /// }} |
243 | /// ``` |
244 | /// |
245 | /// The syntax for the `rust!` macro is: |
246 | /// ```ignore |
247 | /// rust!($uniq_ident:ident [$($arg_name:ident : $arg_rust_type:ty as $arg_c_type:tt),*] |
248 | /// $(-> $ret_rust_type:ty as $rust_c_type:tt)* {$($body:tt)*}) |
249 | /// ``` |
250 | /// `uniq_ident` is a unique identifier which will be used to name the `extern` function |
251 | #[macro_export ] |
252 | macro_rules! cpp { |
253 | // raw text inclusion |
254 | ({$($body:tt)*}) => { $crate::__cpp_internal!{ @find_rust_macro [#[no_mangle] pub] $($body)*} }; |
255 | |
256 | // inline closure |
257 | ([$($captures:tt)*] $($rest:tt)*) => { |
258 | { |
259 | $crate::__cpp_internal!{ @find_rust_macro [] $($rest)*} |
260 | #[allow(unused)] |
261 | #[derive($crate::__cpp_internal_closure)] |
262 | enum CppClosureInput { |
263 | Input = (stringify!([$($captures)*] $($rest)*), 0).1 |
264 | } |
265 | __cpp_closure_impl![$($captures)*] |
266 | } |
267 | }; |
268 | |
269 | // wrap unsafe |
270 | (unsafe $($tail:tt)*) => { unsafe { cpp!($($tail)*) } }; |
271 | } |
272 | |
273 | #[doc (hidden)] |
274 | pub trait CppTrait { |
275 | type BaseType; |
276 | const ARRAY_SIZE: usize; |
277 | const CPP_TYPE: &'static str; |
278 | } |
279 | |
280 | /// This macro allows wrapping a relocatable C++ struct or class that might have |
281 | /// a destructor or copy constructor, implementing the `Drop` and `Clone` trait |
282 | /// appropriately. |
283 | /// |
284 | /// ```ignore |
285 | /// cpp_class!(pub unsafe struct MyClass as "MyClass" ); |
286 | /// impl MyClass { |
287 | /// fn new() -> Self { |
288 | /// unsafe { cpp!([] -> MyClass as "MyClass" { return MyClass(); }) } |
289 | /// } |
290 | /// fn member_function(&self, param : i32) -> i32 { |
291 | /// unsafe { cpp!([self as "const MyClass*" , param as "int" ] -> i32 as "int" { |
292 | /// return self->member_function(param); |
293 | /// }) } |
294 | /// } |
295 | /// } |
296 | /// ``` |
297 | /// |
298 | /// This will create a Rust struct `MyClass`, which has the same size and |
299 | /// alignment as the C++ class `MyClass`. It will also implement the `Drop` trait |
300 | /// calling the destructor, the `Clone` trait calling the copy constructor, if the |
301 | /// class is copyable (or `Copy` if it is trivially copyable), and `Default` if the class |
302 | /// is default constructible |
303 | /// |
304 | /// ## Derived Traits |
305 | /// |
306 | /// The `Default`, `Clone` and `Copy` traits are implicitly implemented if the C++ |
307 | /// type has the corresponding constructors. |
308 | /// |
309 | /// You can add the `#[derive(...)]` attribute in the macro in order to get automatic |
310 | /// implementation of the following traits: |
311 | /// |
312 | /// * The trait `PartialEq` will call the C++ `operator==`. |
313 | /// * You can add the trait `Eq` if the semantics of the C++ operator are those of `Eq` |
314 | /// * The trait `PartialOrd` need the C++ `operator<` for that type. `lt`, `le`, `gt` and |
315 | /// `ge` will use the corresponding C++ operator if it is defined, otherwise it will |
316 | /// fallback to the less than operator. For PartialOrd::partial_cmp, the `operator<` will |
317 | /// be called twice. Note that it will never return `None`. |
318 | /// * The trait `Ord` can also be specified when the semantics of the `operator<` corresponds |
319 | /// to a total order |
320 | /// |
321 | /// ## Safety Warning |
322 | /// |
323 | /// Use of this macro is highly unsafe. Only certain C++ classes can be bound |
324 | /// to, C++ classes may perform arbitrary unsafe operations, and invariants are |
325 | /// easy to break. |
326 | /// |
327 | /// A notable restriction is that this macro only works if the C++ class is |
328 | /// relocatable. |
329 | /// |
330 | /// ## Relocatable classes |
331 | /// |
332 | /// In order to be able to we wrapped the C++ class must be relocatable. That means |
333 | /// that it can be moved in memory using `memcpy`. This restriction exists because |
334 | /// safe Rust is allowed to move your types around. |
335 | /// |
336 | /// Most C++ types which do not contain self-references will be compatible, |
337 | /// although this property cannot be statically checked by `rust-cpp`. |
338 | /// All types that satisfy `std::is_trivially_copyable` are compatible. |
339 | /// Maybe future version of the C++ standard would allow a compile-time check: |
340 | /// [P1144](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1144r4.html) |
341 | /// |
342 | /// Unfortunately, as the STL often uses internal self-references for |
343 | /// optimization purposes, such as the small-string optimization, this disallows |
344 | /// most std:: classes. |
345 | /// But `std::unique_ptr<T>` and `std::shared_ptr<T>` works. |
346 | /// |
347 | #[macro_export ] |
348 | macro_rules! cpp_class { |
349 | ($(#[$($attrs:tt)*])* unsafe struct $name:ident as $type:expr) => { |
350 | $crate::__cpp_class_internal!{@parse [ $(#[$($attrs)*])* ] [] [unsafe struct $name as $type] } |
351 | }; |
352 | ($(#[$($attrs:tt)*])* pub unsafe struct $name:ident as $type:expr) => { |
353 | $crate::__cpp_class_internal!{@parse [ $(#[$($attrs)*])* ] [pub] [unsafe struct $name as $type] } |
354 | }; |
355 | ($(#[$($attrs:tt)*])* pub($($pub:tt)*) unsafe struct $name:ident as $type:expr) => { |
356 | $crate::__cpp_class_internal!{@parse [ $(#[$($attrs)*])* ] [pub($($pub)*)] [unsafe struct $name as $type] } |
357 | }; |
358 | } |
359 | |
360 | /// Implementation details for cpp_class! |
361 | #[doc (hidden)] |
362 | #[macro_export ] |
363 | macro_rules! __cpp_class_internal { |
364 | (@parse [$($attrs:tt)*] [$($vis:tt)*] [unsafe struct $name:ident as $type:expr]) => { |
365 | $crate::__cpp_class_internal!{@parse_attributes [ $($attrs)* ] [] [ |
366 | #[derive($crate::__cpp_internal_class)] |
367 | #[repr(C)] |
368 | $($vis)* struct $name { |
369 | _opaque : [<$name as $crate::CppTrait>::BaseType ; <$name as $crate::CppTrait>::ARRAY_SIZE |
370 | + (stringify!($($attrs)* $($vis)* unsafe struct $name as $type), 0).1] |
371 | } |
372 | ]} |
373 | }; |
374 | |
375 | (@parse_attributes [] [$($attributes:tt)*] [$($result:tt)*]) => ( $($attributes)* $($result)* ); |
376 | (@parse_attributes [#[derive($($der:ident),*)] $($tail:tt)* ] [$($attributes:tt)*] [$($result:tt)*] ) |
377 | => ($crate::__cpp_class_internal!{@parse_derive [$($der),*] @parse_attributes [$($tail)*] [ $($attributes)* ] [ $($result)* ] } ); |
378 | (@parse_attributes [ #[$m:meta] $($tail:tt)* ] [$($attributes:tt)*] [$($result:tt)*]) |
379 | => ($crate::__cpp_class_internal!{@parse_attributes [$($tail)*] [$($attributes)* #[$m] ] [ $($result)* ] } ); |
380 | |
381 | (@parse_derive [] @parse_attributes $($result:tt)*) => ($crate::__cpp_class_internal!{@parse_attributes $($result)*} ); |
382 | (@parse_derive [PartialEq $(,$tail:ident)*] $($result:tt)*) |
383 | => ( $crate::__cpp_class_internal!{@parse_derive [$($tail),*] $($result)*} ); |
384 | (@parse_derive [PartialOrd $(,$tail:ident)*] $($result:tt)*) |
385 | => ( $crate::__cpp_class_internal!{@parse_derive [$($tail),*] $($result)*} ); |
386 | (@parse_derive [Ord $(,$tail:ident)*] $($result:tt)*) |
387 | => ( $crate::__cpp_class_internal!{@parse_derive [$($tail),*] $($result)*} ); |
388 | (@parse_derive [Default $(,$tail:ident)*] $($result:tt)*) |
389 | => ( $crate::__cpp_class_internal!{@parse_derive [$($tail),*] $($result)*} ); |
390 | (@parse_derive [Clone $(,$tail:ident)*] $($result:tt)*) |
391 | => ( $crate::__cpp_class_internal!{@parse_derive [$($tail),*] $($result)*} ); |
392 | (@parse_derive [Copy $(,$tail:ident)*] $($result:tt)*) |
393 | => ( $crate::__cpp_class_internal!{@parse_derive [$($tail),*] $($result)*} ); |
394 | (@parse_derive [$i:ident $(,$tail:ident)*] @parse_attributes [$($attr:tt)*] [$($attributes:tt)*] [$($result:tt)*] ) |
395 | => ( $crate::__cpp_class_internal!{@parse_derive [$($tail),*] @parse_attributes [$($attr)*] [$($attributes)* #[derive($i)] ] [ $($result)* ] } ); |
396 | } |
397 | |