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 #[allow(clippy::forget_copy, clippy::forget_ref)]
147 #[doc(hidden)]
148 $($a)* unsafe extern "C" fn $i($($an : *const $at),*) {
149 $(let $an : $at = unsafe { $an.read() };)*
150 (|| { $($body)* })();
151 $(::core::mem::forget($an);)*
152
153 }
154 };
155 (@expand_rust_macro [$($a:tt)*] $i:ident [$($an:ident : $at:ty as $ac:tt),*] -> $rt:ty as $rc:tt {$($body:tt)*}) => {
156 #[allow(non_snake_case)]
157 #[allow(unused_unsafe)]
158 #[allow(clippy::forget_copy, clippy::forget_ref)]
159 #[doc(hidden)]
160 $($a)* unsafe extern "C" fn $i($($an : *const $at, )* rt : *mut $rt) -> *mut $rt {
161
162 $(let $an : $at = unsafe { $an.read() };)*
163 {
164 #[allow(unused_mut)]
165 let mut lambda = || {$($body)*};
166 unsafe { ::core::ptr::write(rt, lambda()) };
167 }
168 $(::core::mem::forget($an);)*
169 rt
170 }
171 };
172
173 (@expand_rust_macro $($invalid:tt)*) => {
174 compile_error!(concat!( "Cannot parse rust! macro: ", stringify!([ $($invalid)* ]) ))
175 };
176}
177
178/// This macro is used to embed arbitrary C++ code.
179///
180/// There are two variants of the `cpp!` macro. The first variant is used for
181/// raw text inclusion. Text is included into the generated `C++` file in the
182/// order which they were defined, inlining module declarations.
183///
184/// ```ignore
185/// cpp! {{
186/// #include <stdint.h>
187/// #include <stdio.h>
188/// }}
189/// ```
190///
191/// The second variant is used to embed C++ code within Rust code. A list of
192/// variable names which should be captured are taken as the first argument,
193/// with their corresponding C++ type. The body is compiled as a C++ function.
194///
195/// This variant of the macro may only be invoked in expression context, and
196/// requires an `unsafe` block, as it is performing FFI.
197///
198/// ```ignore
199/// let y: i32 = 10;
200/// let mut z: i32 = 20;
201/// let x: i32 = unsafe { cpp!([y as "int32_t", mut z as "int32_t"] -> i32 as "int32_t" {
202/// z++;
203/// return y + z;
204/// })};
205/// ```
206///
207/// You can also put the unsafe keyword as the first keyword of the `cpp!` macro, which
208/// has the same effect as putting the whole macro in an `unsafe` block:
209///
210/// ```ignore
211/// let x: i32 = cpp!(unsafe [y as "int32_t", mut z as "int32_t"] -> i32 as "int32_t" {
212/// z++;
213/// return y + z;
214/// });
215/// ```
216///
217/// ## rust! pseudo-macro
218///
219/// The `cpp!` macro can contain, in the C++ code, a `rust!` sub-macro, which allows
220/// the inclusion of Rust code in C++ code. This is useful to
221/// implement callback or override virtual functions. Example:
222///
223/// ```ignore
224/// trait MyTrait {
225/// fn compute_value(&self, x : i32) -> i32;
226/// }
227///
228/// cpp!{{
229/// struct TraitPtr { void *a,*b; };
230/// class MyClassImpl : public MyClass {
231/// public:
232/// TraitPtr m_trait;
233/// int computeValue(int x) const override {
234/// return rust!(MCI_computeValue [m_trait : &MyTrait as "TraitPtr", x : i32 as "int"]
235/// -> i32 as "int" {
236/// m_trait.compute_value(x)
237/// });
238/// }
239/// }
240/// }}
241/// ```
242///
243/// The syntax for the `rust!` macro is:
244/// ```ignore
245/// rust!($uniq_ident:ident [$($arg_name:ident : $arg_rust_type:ty as $arg_c_type:tt),*]
246/// $(-> $ret_rust_type:ty as $rust_c_type:tt)* {$($body:tt)*})
247/// ```
248/// `uniq_ident` is a unique identifier which will be used to name the `extern` function
249#[macro_export]
250macro_rules! cpp {
251 // raw text inclusion
252 ({$($body:tt)*}) => { $crate::__cpp_internal!{ @find_rust_macro [#[no_mangle] pub] $($body)*} };
253
254 // inline closure
255 ([$($captures:tt)*] $($rest:tt)*) => {
256 {
257 $crate::__cpp_internal!{ @find_rust_macro [] $($rest)*}
258 #[allow(unused)]
259 #[derive($crate::__cpp_internal_closure)]
260 enum CppClosureInput {
261 Input = (stringify!([$($captures)*] $($rest)*), 0).1
262 }
263 __cpp_closure_impl![$($captures)*]
264 }
265 };
266
267 // wrap unsafe
268 (unsafe $($tail:tt)*) => { unsafe { cpp!($($tail)*) } };
269}
270
271#[doc(hidden)]
272pub trait CppTrait {
273 type BaseType;
274 const ARRAY_SIZE: usize;
275 const CPP_TYPE: &'static str;
276}
277
278/// This macro allows wrapping a relocatable C++ struct or class that might have
279/// a destructor or copy constructor, implementing the `Drop` and `Clone` trait
280/// appropriately.
281///
282/// ```ignore
283/// cpp_class!(pub unsafe struct MyClass as "MyClass");
284/// impl MyClass {
285/// fn new() -> Self {
286/// unsafe { cpp!([] -> MyClass as "MyClass" { return MyClass(); }) }
287/// }
288/// fn member_function(&self, param : i32) -> i32 {
289/// unsafe { cpp!([self as "const MyClass*", param as "int"] -> i32 as "int" {
290/// return self->member_function(param);
291/// }) }
292/// }
293/// }
294/// ```
295///
296/// This will create a Rust struct `MyClass`, which has the same size and
297/// alignment as the C++ class `MyClass`. It will also implement the `Drop` trait
298/// calling the destructor, the `Clone` trait calling the copy constructor, if the
299/// class is copyable (or `Copy` if it is trivially copyable), and `Default` if the class
300/// is default constructible
301///
302/// ## Derived Traits
303///
304/// The `Default`, `Clone` and `Copy` traits are implicitly implemented if the C++
305/// type has the corresponding constructors.
306///
307/// You can add the `#[derive(...)]` attribute in the macro in order to get automatic
308/// implementation of the following traits:
309///
310/// * The trait `PartialEq` will call the C++ `operator==`.
311/// * You can add the trait `Eq` if the semantics of the C++ operator are those of `Eq`
312/// * The trait `PartialOrd` need the C++ `operator<` for that type. `lt`, `le`, `gt` and
313/// `ge` will use the corresponding C++ operator if it is defined, otherwise it will
314/// fallback to the less than operator. For PartialOrd::partial_cmp, the `operator<` will
315/// be called twice. Note that it will never return `None`.
316/// * The trait `Ord` can also be specified when the semantics of the `operator<` corresponds
317/// to a total order
318///
319/// ## Safety Warning
320///
321/// Use of this macro is highly unsafe. Only certain C++ classes can be bound
322/// to, C++ classes may perform arbitrary unsafe operations, and invariants are
323/// easy to break.
324///
325/// A notable restriction is that this macro only works if the C++ class is
326/// relocatable.
327///
328/// ## Relocatable classes
329///
330/// In order to be able to we wrapped the C++ class must be relocatable. That means
331/// that it can be moved in memory using `memcpy`. This restriction exists because
332/// safe Rust is allowed to move your types around.
333///
334/// Most C++ types which do not contain self-references will be compatible,
335/// although this property cannot be statically checked by `rust-cpp`.
336/// All types that satisfy `std::is_trivially_copyable` are compatible.
337/// Maybe future version of the C++ standard would allow a compile-time check:
338/// [P1144](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1144r4.html)
339///
340/// Unfortunately, as the STL often uses internal self-references for
341/// optimization purposes, such as the small-string optimization, this disallows
342/// most std:: classes.
343/// But `std::unique_ptr<T>` and `std::shared_ptr<T>` works.
344///
345#[macro_export]
346macro_rules! cpp_class {
347 ($(#[$($attrs:tt)*])* unsafe struct $name:ident as $type:expr) => {
348 $crate::__cpp_class_internal!{@parse [ $(#[$($attrs)*])* ] [] [unsafe struct $name as $type] }
349 };
350 ($(#[$($attrs:tt)*])* pub unsafe struct $name:ident as $type:expr) => {
351 $crate::__cpp_class_internal!{@parse [ $(#[$($attrs)*])* ] [pub] [unsafe struct $name as $type] }
352 };
353 ($(#[$($attrs:tt)*])* pub($($pub:tt)*) unsafe struct $name:ident as $type:expr) => {
354 $crate::__cpp_class_internal!{@parse [ $(#[$($attrs)*])* ] [pub($($pub)*)] [unsafe struct $name as $type] }
355 };
356}
357
358/// Implementation details for cpp_class!
359#[doc(hidden)]
360#[macro_export]
361macro_rules! __cpp_class_internal {
362 (@parse [$($attrs:tt)*] [$($vis:tt)*] [unsafe struct $name:ident as $type:expr]) => {
363 $crate::__cpp_class_internal!{@parse_attributes [ $($attrs)* ] [] [
364 #[derive($crate::__cpp_internal_class)]
365 #[repr(C)]
366 $($vis)* struct $name {
367 _opaque : [<$name as $crate::CppTrait>::BaseType ; <$name as $crate::CppTrait>::ARRAY_SIZE
368 + (stringify!($($attrs)* $($vis)* unsafe struct $name as $type), 0).1]
369 }
370 ]}
371 };
372
373 (@parse_attributes [] [$($attributes:tt)*] [$($result:tt)*]) => ( $($attributes)* $($result)* );
374 (@parse_attributes [#[derive($($der:ident),*)] $($tail:tt)* ] [$($attributes:tt)*] [$($result:tt)*] )
375 => ($crate::__cpp_class_internal!{@parse_derive [$($der),*] @parse_attributes [$($tail)*] [ $($attributes)* ] [ $($result)* ] } );
376 (@parse_attributes [ #[$m:meta] $($tail:tt)* ] [$($attributes:tt)*] [$($result:tt)*])
377 => ($crate::__cpp_class_internal!{@parse_attributes [$($tail)*] [$($attributes)* #[$m] ] [ $($result)* ] } );
378
379 (@parse_derive [] @parse_attributes $($result:tt)*) => ($crate::__cpp_class_internal!{@parse_attributes $($result)*} );
380 (@parse_derive [PartialEq $(,$tail:ident)*] $($result:tt)*)
381 => ( $crate::__cpp_class_internal!{@parse_derive [$($tail),*] $($result)*} );
382 (@parse_derive [PartialOrd $(,$tail:ident)*] $($result:tt)*)
383 => ( $crate::__cpp_class_internal!{@parse_derive [$($tail),*] $($result)*} );
384 (@parse_derive [Ord $(,$tail:ident)*] $($result:tt)*)
385 => ( $crate::__cpp_class_internal!{@parse_derive [$($tail),*] $($result)*} );
386 (@parse_derive [Default $(,$tail:ident)*] $($result:tt)*)
387 => ( $crate::__cpp_class_internal!{@parse_derive [$($tail),*] $($result)*} );
388 (@parse_derive [Clone $(,$tail:ident)*] $($result:tt)*)
389 => ( $crate::__cpp_class_internal!{@parse_derive [$($tail),*] $($result)*} );
390 (@parse_derive [Copy $(,$tail:ident)*] $($result:tt)*)
391 => ( $crate::__cpp_class_internal!{@parse_derive [$($tail),*] $($result)*} );
392 (@parse_derive [$i:ident $(,$tail:ident)*] @parse_attributes [$($attr:tt)*] [$($attributes:tt)*] [$($result:tt)*] )
393 => ( $crate::__cpp_class_internal!{@parse_derive [$($tail),*] @parse_attributes [$($attr)*] [$($attributes)* #[derive($i)] ] [ $($result)* ] } );
394}
395