| 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 | #[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 ] |
| 250 | macro_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)] |
| 272 | pub 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 ] |
| 346 | macro_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 ] |
| 361 | macro_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 | |