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)]
119extern crate cpp_macros;
120#[doc(hidden)]
121pub 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]
128macro_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]
252macro_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)]
274pub 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]
348macro_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]
363macro_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