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
//! This crate `cpp` only provides a single macro, the `cpp!` macro. This macro //! by itself is not useful, but when combined with the `cpp_build` and //! `cpp_macro` crates it allows embedding arbitrary C++ code. //! //! There are two variants of the `cpp!` macro. The first variant is used for //! raw text inclusion. Text is included into the generated `C++` file in the //! order which they were defined, inlining module declarations. //! //! ```ignore //! cpp! {{ //! #include <stdint.h> //! #include <stdio.h> //! }} //! ``` //! //! The second variant is used to embed C++ code within rust code. A list of //! variable names which should be captured are taken as the first argument, //! with their corresponding C++ type. The body is compiled as a C++ function. //! //! This variant of the macro may only be invoked in expression context, and //! requires an `unsafe` block, as it is performing FFI. //! //! ```ignore //! let y: i32 = 10; //! let mut z: i32 = 20; //! let x: i32 = cpp!([y as "int32_t", mut z as "int32_t"] -> i32 as "int32_t" { //! z++; //! return y + z; //! }); //! ``` //! //! # Usage //! //! This crate must be used in tandem with the `cpp_build` and `cpp_macro` //! crates. A basic Cargo project which uses these projects would have a //! structure like the following: //! //! ```text //! crate //! |-- Cargo.toml //! |-- src //! |-- lib.rs //! |-- build.rs //! ``` //! //! Where the files look like the following: //! //! #### Cargo.toml //! //! ```toml //! [package] //! build = "build.rs" //! //! [dependencies] //! cpp = "0.2" //! cpp_macros = "0.2" //! //! [build-dependencies] //! cpp_build = "0.2" //! ``` //! //! #### build.rs //! //! ```ignore //! extern crate cpp_build; //! //! fn main() { //! cpp_build::build("src/lib.rs"); //! } //! ``` //! //! #### lib.rs //! //! ```ignore //! #[macro_use] //! extern crate cpp; //! #[macro_use] //! extern crate cpp_macros; //! //! cpp!{{ //! #include <stdio.h> //! }} //! //! fn main() { //! unsafe { //! cpp!([] { //! printf("Hello, World!\n"); //! }); //! } //! } //! ``` /// This macro is used to embed arbitrary C++ code. See the module level /// documentation for more details. #[macro_export] macro_rules! cpp { ({$($body:tt)*}) => { /* Raw text inclusion */ }; ([$($captures:tt)*] $($rest:tt)*) => { { #[allow(non_camel_case_types, dead_code)] #[derive(__cpp_internal_closure)] struct __cpp_closure(cpp! { @TYPE [$($captures)*] $($rest)* }); cpp!{@CAPTURES __cpp_closure [] => $($captures)*} } }; {@CAPTURES $name:ident [$($e:expr),*] => } => { $name::run($($e),*) }; {@CAPTURES $name:ident [$($e:expr),*] => mut $i:ident as $cty:expr , $($rest:tt)* } => { cpp!{@CAPTURES $name [$($e ,)* &mut $i] => $($rest)*} }; {@CAPTURES $name:ident [$($e:expr),*] => mut $i:ident as $cty:expr } => { cpp!{@CAPTURES $name [$($e ,)* &mut $i] =>} }; {@CAPTURES $name:ident [$($e:expr),*] => $i:ident as $cty:expr , $($rest:tt)* } => { cpp!{@CAPTURES $name [$($e ,)* &$i] => $($rest)*} }; {@CAPTURES $name:ident [$($e:expr),*] => $i:ident as $cty:expr } => { cpp!{@CAPTURES $name [$($e ,)* &$i] =>} }; (@TYPE $($rest:tt)*) => { () }; }