• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! [![github]](https://github.com/dtolnay/cxx) [![crates-io]](https://crates.io/crates/cxx) [![docs-rs]](https://docs.rs/cxx)
2 //!
3 //! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
4 //! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
5 //! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
6 //!
7 //! <br>
8 //!
9 //! This library provides a **safe** mechanism for calling C++ code from Rust
10 //! and Rust code from C++, not subject to the many ways that things can go
11 //! wrong when using bindgen or cbindgen to generate unsafe C-style bindings.
12 //!
13 //! This doesn't change the fact that 100% of C++ code is unsafe. When auditing
14 //! a project, you would be on the hook for auditing all the unsafe Rust code
15 //! and *all* the C++ code. The core safety claim under this new model is that
16 //! auditing just the C++ side would be sufficient to catch all problems, i.e.
17 //! the Rust side can be 100% safe.
18 //!
19 //! <br>
20 //!
21 //! *Compiler support: requires rustc 1.60+ and c++11 or newer*<br>
22 //! *[Release notes](https://github.com/dtolnay/cxx/releases)*
23 //!
24 //! <br>
25 //!
26 //! # Guide
27 //!
28 //! Please see **<https://cxx.rs>** for a tutorial, reference material, and
29 //! example code.
30 //!
31 //! <br>
32 //!
33 //! # Overview
34 //!
35 //! The idea is that we define the signatures of both sides of our FFI boundary
36 //! embedded together in one Rust module (the next section shows an example).
37 //! From this, CXX receives a complete picture of the boundary to perform static
38 //! analyses against the types and function signatures to uphold both Rust's and
39 //! C++'s invariants and requirements.
40 //!
41 //! If everything checks out statically, then CXX uses a pair of code generators
42 //! to emit the relevant `extern "C"` signatures on both sides together with any
43 //! necessary static assertions for later in the build process to verify
44 //! correctness. On the Rust side this code generator is simply an attribute
45 //! procedural macro. On the C++ side it can be a small Cargo build script if
46 //! your build is managed by Cargo, or for other build systems like Bazel or
47 //! Buck we provide a command line tool which generates the header and source
48 //! file and should be easy to integrate.
49 //!
50 //! The resulting FFI bridge operates at zero or negligible overhead, i.e. no
51 //! copying, no serialization, no memory allocation, no runtime checks needed.
52 //!
53 //! The FFI signatures are able to use native types from whichever side they
54 //! please, such as Rust's `String` or C++'s `std::string`, Rust's `Box` or
55 //! C++'s `std::unique_ptr`, Rust's `Vec` or C++'s `std::vector`, etc in any
56 //! combination. CXX guarantees an ABI-compatible signature that both sides
57 //! understand, based on builtin bindings for key standard library types to
58 //! expose an idiomatic API on those types to the other language. For example
59 //! when manipulating a C++ string from Rust, its `len()` method becomes a call
60 //! of the `size()` member function defined by C++; when manipulation a Rust
61 //! string from C++, its `size()` member function calls Rust's `len()`.
62 //!
63 //! <br>
64 //!
65 //! # Example
66 //!
67 //! In this example we are writing a Rust application that wishes to take
68 //! advantage of an existing C++ client for a large-file blobstore service. The
69 //! blobstore supports a `put` operation for a discontiguous buffer upload. For
70 //! example we might be uploading snapshots of a circular buffer which would
71 //! tend to consist of 2 chunks, or fragments of a file spread across memory for
72 //! some other reason.
73 //!
74 //! A runnable version of this example is provided under the *demo* directory of
75 //! <https://github.com/dtolnay/cxx>. To try it out, run `cargo run` from that
76 //! directory.
77 //!
78 //! ```no_run
79 //! #[cxx::bridge]
80 //! mod ffi {
81 //!     // Any shared structs, whose fields will be visible to both languages.
82 //!     struct BlobMetadata {
83 //!         size: usize,
84 //!         tags: Vec<String>,
85 //!     }
86 //!
87 //!     extern "Rust" {
88 //!         // Zero or more opaque types which both languages can pass around but
89 //!         // only Rust can see the fields.
90 //!         type MultiBuf;
91 //!
92 //!         // Functions implemented in Rust.
93 //!         fn next_chunk(buf: &mut MultiBuf) -> &[u8];
94 //!     }
95 //!
96 //!     unsafe extern "C++" {
97 //!         // One or more headers with the matching C++ declarations. Our code
98 //!         // generators don't read it but it gets #include'd and used in static
99 //!         // assertions to ensure our picture of the FFI boundary is accurate.
100 //!         include!("demo/include/blobstore.h");
101 //!
102 //!         // Zero or more opaque types which both languages can pass around but
103 //!         // only C++ can see the fields.
104 //!         type BlobstoreClient;
105 //!
106 //!         // Functions implemented in C++.
107 //!         fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
108 //!         fn put(&self, parts: &mut MultiBuf) -> u64;
109 //!         fn tag(&self, blobid: u64, tag: &str);
110 //!         fn metadata(&self, blobid: u64) -> BlobMetadata;
111 //!     }
112 //! }
113 //! #
114 //! # pub struct MultiBuf;
115 //! #
116 //! # fn next_chunk(_buf: &mut MultiBuf) -> &[u8] {
117 //! #     unimplemented!()
118 //! # }
119 //! #
120 //! # fn main() {}
121 //! ```
122 //!
123 //! Now we simply provide Rust definitions of all the things in the `extern
124 //! "Rust"` block and C++ definitions of all the things in the `extern "C++"`
125 //! block, and get to call back and forth safely.
126 //!
127 //! Here are links to the complete set of source files involved in the demo:
128 //!
129 //! - [demo/src/main.rs](https://github.com/dtolnay/cxx/blob/master/demo/src/main.rs)
130 //! - [demo/build.rs](https://github.com/dtolnay/cxx/blob/master/demo/build.rs)
131 //! - [demo/include/blobstore.h](https://github.com/dtolnay/cxx/blob/master/demo/include/blobstore.h)
132 //! - [demo/src/blobstore.cc](https://github.com/dtolnay/cxx/blob/master/demo/src/blobstore.cc)
133 //!
134 //! To look at the code generated in both languages for the example by the CXX
135 //! code generators:
136 //!
137 //! ```console
138 //!    # run Rust code generator and print to stdout
139 //!    # (requires https://github.com/dtolnay/cargo-expand)
140 //! $ cargo expand --manifest-path demo/Cargo.toml
141 //!
142 //!    # run C++ code generator and print to stdout
143 //! $ cargo run --manifest-path gen/cmd/Cargo.toml -- demo/src/main.rs
144 //! ```
145 //!
146 //! <br>
147 //!
148 //! # Details
149 //!
150 //! As seen in the example, the language of the FFI boundary involves 3 kinds of
151 //! items:
152 //!
153 //! - **Shared structs** &mdash; their fields are made visible to both
154 //!   languages. The definition written within cxx::bridge is the single source
155 //!   of truth.
156 //!
157 //! - **Opaque types** &mdash; their fields are secret from the other language.
158 //!   These cannot be passed across the FFI by value but only behind an
159 //!   indirection, such as a reference `&`, a Rust `Box`, or a `UniquePtr`. Can
160 //!   be a type alias for an arbitrarily complicated generic language-specific
161 //!   type depending on your use case.
162 //!
163 //! - **Functions** &mdash; implemented in either language, callable from the
164 //!   other language.
165 //!
166 //! Within the `extern "Rust"` part of the CXX bridge we list the types and
167 //! functions for which Rust is the source of truth. These all implicitly refer
168 //! to the `super` module, the parent module of the CXX bridge. You can think of
169 //! the two items listed in the example above as being like `use
170 //! super::MultiBuf` and `use super::next_chunk` except re-exported to C++. The
171 //! parent module will either contain the definitions directly for simple
172 //! things, or contain the relevant `use` statements to bring them into scope
173 //! from elsewhere.
174 //!
175 //! Within the `extern "C++"` part, we list types and functions for which C++ is
176 //! the source of truth, as well as the header(s) that declare those APIs. In
177 //! the future it's possible that this section could be generated bindgen-style
178 //! from the headers but for now we need the signatures written out; static
179 //! assertions will verify that they are accurate.
180 //!
181 //! Your function implementations themselves, whether in C++ or Rust, *do not*
182 //! need to be defined as `extern "C"` ABI or no\_mangle. CXX will put in the
183 //! right shims where necessary to make it all work.
184 //!
185 //! <br>
186 //!
187 //! # Comparison vs bindgen and cbindgen
188 //!
189 //! Notice that with CXX there is repetition of all the function signatures:
190 //! they are typed out once where the implementation is defined (in C++ or Rust)
191 //! and again inside the cxx::bridge module, though compile-time assertions
192 //! guarantee these are kept in sync. This is different from [bindgen] and
193 //! [cbindgen] where function signatures are typed by a human once and the tool
194 //! consumes them in one language and emits them in the other language.
195 //!
196 //! [bindgen]: https://github.com/rust-lang/rust-bindgen
197 //! [cbindgen]: https://github.com/eqrion/cbindgen/
198 //!
199 //! This is because CXX fills a somewhat different role. It is a lower level
200 //! tool than bindgen or cbindgen in a sense; you can think of it as being a
201 //! replacement for the concept of `extern "C"` signatures as we know them,
202 //! rather than a replacement for a bindgen. It would be reasonable to build a
203 //! higher level bindgen-like tool on top of CXX which consumes a C++ header
204 //! and/or Rust module (and/or IDL like Thrift) as source of truth and generates
205 //! the cxx::bridge, eliminating the repetition while leveraging the static
206 //! analysis safety guarantees of CXX.
207 //!
208 //! But note in other ways CXX is higher level than the bindgens, with rich
209 //! support for common standard library types. Frequently with bindgen when we
210 //! are dealing with an idiomatic C++ API we would end up manually wrapping that
211 //! API in C-style raw pointer functions, applying bindgen to get unsafe raw
212 //! pointer Rust functions, and replicating the API again to expose those
213 //! idiomatically in Rust. That's a much worse form of repetition because it is
214 //! unsafe all the way through.
215 //!
216 //! By using a CXX bridge as the shared understanding between the languages,
217 //! rather than `extern "C"` C-style signatures as the shared understanding,
218 //! common FFI use cases become expressible using 100% safe code.
219 //!
220 //! It would also be reasonable to mix and match, using CXX bridge for the 95%
221 //! of your FFI that is straightforward and doing the remaining few oddball
222 //! signatures the old fashioned way with bindgen and cbindgen, if for some
223 //! reason CXX's static restrictions get in the way. Please file an issue if you
224 //! end up taking this approach so that we know what ways it would be worthwhile
225 //! to make the tool more expressive.
226 //!
227 //! <br>
228 //!
229 //! # Cargo-based setup
230 //!
231 //! For builds that are orchestrated by Cargo, you will use a build script that
232 //! runs CXX's C++ code generator and compiles the resulting C++ code along with
233 //! any other C++ code for your crate.
234 //!
235 //! The canonical build script is as follows. The indicated line returns a
236 //! [`cc::Build`] instance (from the usual widely used `cc` crate) on which you
237 //! can set up any additional source files and compiler flags as normal.
238 //!
239 //! [`cc::Build`]: https://docs.rs/cc/1.0/cc/struct.Build.html
240 //!
241 //! ```toml
242 //! # Cargo.toml
243 //!
244 //! [build-dependencies]
245 //! cxx-build = "1.0"
246 //! ```
247 //!
248 //! ```no_run
249 //! // build.rs
250 //!
251 //! fn main() {
252 //!     cxx_build::bridge("src/main.rs")  // returns a cc::Build
253 //!         .file("src/demo.cc")
254 //!         .flag_if_supported("-std=c++11")
255 //!         .compile("cxxbridge-demo");
256 //!
257 //!     println!("cargo:rerun-if-changed=src/main.rs");
258 //!     println!("cargo:rerun-if-changed=src/demo.cc");
259 //!     println!("cargo:rerun-if-changed=include/demo.h");
260 //! }
261 //! ```
262 //!
263 //! <br><br>
264 //!
265 //! # Non-Cargo setup
266 //!
267 //! For use in non-Cargo builds like Bazel or Buck, CXX provides an alternate
268 //! way of invoking the C++ code generator as a standalone command line tool.
269 //! The tool is packaged as the `cxxbridge-cmd` crate on crates.io or can be
270 //! built from the *gen/cmd* directory of <https://github.com/dtolnay/cxx>.
271 //!
272 //! ```bash
273 //! $ cargo install cxxbridge-cmd
274 //!
275 //! $ cxxbridge src/main.rs --header > path/to/mybridge.h
276 //! $ cxxbridge src/main.rs > path/to/mybridge.cc
277 //! ```
278 //!
279 //! <br>
280 //!
281 //! # Safety
282 //!
283 //! Be aware that the design of this library is intentionally restrictive and
284 //! opinionated! It isn't a goal to be powerful enough to handle arbitrary
285 //! signatures in either language. Instead this project is about carving out a
286 //! reasonably expressive set of functionality about which we can make useful
287 //! safety guarantees today and maybe extend over time. You may find that it
288 //! takes some practice to use CXX bridge effectively as it won't work in all
289 //! the ways that you are used to.
290 //!
291 //! Some of the considerations that go into ensuring safety are:
292 //!
293 //! - By design, our paired code generators work together to control both sides
294 //!   of the FFI boundary. Ordinarily in Rust writing your own `extern "C"`
295 //!   blocks is unsafe because the Rust compiler has no way to know whether the
296 //!   signatures you've written actually match the signatures implemented in the
297 //!   other language. With CXX we achieve that visibility and know what's on the
298 //!   other side.
299 //!
300 //! - Our static analysis detects and prevents passing types by value that
301 //!   shouldn't be passed by value from C++ to Rust, for example because they
302 //!   may contain internal pointers that would be screwed up by Rust's move
303 //!   behavior.
304 //!
305 //! - To many people's surprise, it is possible to have a struct in Rust and a
306 //!   struct in C++ with exactly the same layout / fields / alignment /
307 //!   everything, and still not the same ABI when passed by value. This is a
308 //!   longstanding bindgen bug that leads to segfaults in absolutely
309 //!   correct-looking code ([rust-lang/rust-bindgen#778]). CXX knows about this
310 //!   and can insert the necessary zero-cost workaround transparently where
311 //!   needed, so go ahead and pass your structs by value without worries. This
312 //!   is made possible by owning both sides of the boundary rather than just
313 //!   one.
314 //!
315 //! - Template instantiations: for example in order to expose a UniquePtr\<T\>
316 //!   type in Rust backed by a real C++ unique\_ptr, we have a way of using a
317 //!   Rust trait to connect the behavior back to the template instantiations
318 //!   performed by the other language.
319 //!
320 //! [rust-lang/rust-bindgen#778]: https://github.com/rust-lang/rust-bindgen/issues/778
321 //!
322 //! <br>
323 //!
324 //! # Builtin types
325 //!
326 //! In addition to all the primitive types (i32 &lt;=&gt; int32_t), the
327 //! following common types may be used in the fields of shared structs and the
328 //! arguments and returns of functions.
329 //!
330 //! <table>
331 //! <tr><th>name in Rust</th><th>name in C++</th><th>restrictions</th></tr>
332 //! <tr><td>String</td><td>rust::String</td><td></td></tr>
333 //! <tr><td>&amp;str</td><td>rust::Str</td><td></td></tr>
334 //! <tr><td>&amp;[T]</td><td>rust::Slice&lt;const T&gt;</td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
335 //! <tr><td>&amp;mut [T]</td><td>rust::Slice&lt;T&gt;</td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
336 //! <tr><td><a href="struct.CxxString.html">CxxString</a></td><td>std::string</td><td><sup><i>cannot be passed by value</i></sup></td></tr>
337 //! <tr><td>Box&lt;T&gt;</td><td>rust::Box&lt;T&gt;</td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
338 //! <tr><td><a href="struct.UniquePtr.html">UniquePtr&lt;T&gt;</a></td><td>std::unique_ptr&lt;T&gt;</td><td><sup><i>cannot hold opaque Rust type</i></sup></td></tr>
339 //! <tr><td><a href="struct.SharedPtr.html">SharedPtr&lt;T&gt;</a></td><td>std::shared_ptr&lt;T&gt;</td><td><sup><i>cannot hold opaque Rust type</i></sup></td></tr>
340 //! <tr><td>[T; N]</td><td>std::array&lt;T, N&gt;</td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
341 //! <tr><td>Vec&lt;T&gt;</td><td>rust::Vec&lt;T&gt;</td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
342 //! <tr><td><a href="struct.CxxVector.html">CxxVector&lt;T&gt;</a></td><td>std::vector&lt;T&gt;</td><td><sup><i>cannot be passed by value, cannot hold opaque Rust type</i></sup></td></tr>
343 //! <tr><td>*mut T, *const T</td><td>T*, const T*</td><td><sup><i>fn with a raw pointer argument must be declared unsafe to call</i></sup></td></tr>
344 //! <tr><td>fn(T, U) -&gt; V</td><td>rust::Fn&lt;V(T, U)&gt;</td><td><sup><i>only passing from Rust to C++ is implemented so far</i></sup></td></tr>
345 //! <tr><td>Result&lt;T&gt;</td><td>throw/catch</td><td><sup><i>allowed as return type only</i></sup></td></tr>
346 //! </table>
347 //!
348 //! The C++ API of the `rust` namespace is defined by the *include/cxx.h* file
349 //! in <https://github.com/dtolnay/cxx>. You will need to include this header in
350 //! your C++ code when working with those types.
351 //!
352 //! The following types are intended to be supported "soon" but are just not
353 //! implemented yet. I don't expect any of these to be hard to make work but
354 //! it's a matter of designing a nice API for each in its non-native language.
355 //!
356 //! <table>
357 //! <tr><th>name in Rust</th><th>name in C++</th></tr>
358 //! <tr><td>BTreeMap&lt;K, V&gt;</td><td><sup><i>tbd</i></sup></td></tr>
359 //! <tr><td>HashMap&lt;K, V&gt;</td><td><sup><i>tbd</i></sup></td></tr>
360 //! <tr><td>Arc&lt;T&gt;</td><td><sup><i>tbd</i></sup></td></tr>
361 //! <tr><td>Option&lt;T&gt;</td><td><sup><i>tbd</i></sup></td></tr>
362 //! <tr><td><sup><i>tbd</i></sup></td><td>std::map&lt;K, V&gt;</td></tr>
363 //! <tr><td><sup><i>tbd</i></sup></td><td>std::unordered_map&lt;K, V&gt;</td></tr>
364 //! </table>
365 
366 #![no_std]
367 #![doc(html_root_url = "https://docs.rs/cxx/1.0.91")]
368 #![deny(
369     improper_ctypes,
370     improper_ctypes_definitions,
371     missing_docs,
372     unsafe_op_in_unsafe_fn
373 )]
374 #![cfg_attr(doc_cfg, feature(doc_cfg))]
375 #![allow(non_camel_case_types)]
376 #![allow(
377     clippy::cognitive_complexity,
378     clippy::declare_interior_mutable_const,
379     clippy::doc_markdown,
380     clippy::empty_enum,
381     clippy::extra_unused_type_parameters,
382     clippy::inherent_to_string,
383     clippy::items_after_statements,
384     clippy::large_enum_variant,
385     clippy::len_without_is_empty,
386     clippy::missing_errors_doc,
387     clippy::missing_safety_doc,
388     clippy::module_inception,
389     clippy::module_name_repetitions,
390     clippy::must_use_candidate,
391     clippy::needless_doctest_main,
392     clippy::new_without_default,
393     clippy::or_fun_call,
394     clippy::ptr_arg,
395     clippy::toplevel_ref_arg,
396     clippy::transmute_undefined_repr, // clippy bug: https://github.com/rust-lang/rust-clippy/issues/8417
397     clippy::useless_let_if_seq,
398     clippy::wrong_self_convention
399 )]
400 
401 #[cfg(built_with_cargo)]
402 extern crate link_cplusplus;
403 
404 extern crate self as cxx;
405 
406 #[doc(hidden)]
407 pub extern crate core;
408 
409 #[cfg(feature = "alloc")]
410 #[doc(hidden)]
411 pub extern crate alloc;
412 
413 #[cfg(not(feature = "alloc"))]
414 extern crate core as alloc;
415 
416 #[cfg(feature = "std")]
417 #[doc(hidden)]
418 pub extern crate std;
419 
420 // Block inadvertent use of items from libstd, which does not otherwise produce
421 // a compile-time error on edition 2018+.
422 #[cfg(not(feature = "std"))]
423 extern crate core as std;
424 
425 #[cfg(not(any(feature = "alloc", cxx_experimental_no_alloc)))]
426 compile_error! {
427     r#"cxx support for no_alloc is incomplete and semver exempt; you must build with at least one of feature="std", feature="alloc", or RUSTFLAGS='--cfg cxx_experimental_no_alloc'"#
428 }
429 
430 #[cfg(all(compile_error_if_alloc, feature = "alloc"))]
431 compile_error! {
432     r#"feature="alloc" is unexpectedly enabled"#
433 }
434 
435 #[cfg(all(compile_error_if_std, feature = "std"))]
436 compile_error! {
437     r#"feature="std" is unexpectedly enabled"#
438 }
439 
440 #[macro_use]
441 mod macros;
442 
443 mod c_char;
444 mod cxx_vector;
445 mod exception;
446 mod extern_type;
447 mod fmt;
448 mod function;
449 mod hash;
450 mod lossy;
451 pub mod memory;
452 mod opaque;
453 mod result;
454 mod rust_slice;
455 mod rust_str;
456 mod rust_string;
457 mod rust_type;
458 mod rust_vec;
459 mod shared_ptr;
460 mod sip;
461 #[path = "cxx_string.rs"]
462 mod string;
463 mod symbols;
464 mod type_id;
465 mod unique_ptr;
466 mod unwind;
467 pub mod vector;
468 mod weak_ptr;
469 
470 pub use crate::cxx_vector::CxxVector;
471 #[cfg(feature = "alloc")]
472 pub use crate::exception::Exception;
473 pub use crate::extern_type::{kind, ExternType};
474 pub use crate::shared_ptr::SharedPtr;
475 pub use crate::string::CxxString;
476 pub use crate::unique_ptr::UniquePtr;
477 pub use crate::weak_ptr::WeakPtr;
478 pub use cxxbridge_macro::bridge;
479 
480 /// Synonym for `CxxString`.
481 ///
482 /// To avoid confusion with Rust's standard library string you probably
483 /// shouldn't import this type with `use`. Instead, write `cxx::String`, or
484 /// import and use `CxxString`.
485 pub type String = CxxString;
486 
487 /// Synonym for `CxxVector`.
488 ///
489 /// To avoid confusion with Rust's standard library vector you probably
490 /// shouldn't import this type with `use`. Instead, write `cxx::Vector<T>`, or
491 /// import and use `CxxVector`.
492 pub type Vector<T> = CxxVector<T>;
493 
494 // Not public API.
495 #[doc(hidden)]
496 pub mod private {
497     pub use crate::c_char::c_char;
498     pub use crate::cxx_vector::VectorElement;
499     pub use crate::extern_type::{verify_extern_kind, verify_extern_type};
500     pub use crate::function::FatFunction;
501     pub use crate::hash::hash;
502     pub use crate::opaque::Opaque;
503     #[cfg(feature = "alloc")]
504     pub use crate::result::{r#try, Result};
505     pub use crate::rust_slice::RustSlice;
506     pub use crate::rust_str::RustStr;
507     #[cfg(feature = "alloc")]
508     pub use crate::rust_string::RustString;
509     pub use crate::rust_type::{ImplBox, ImplVec, RustType};
510     #[cfg(feature = "alloc")]
511     pub use crate::rust_vec::RustVec;
512     pub use crate::shared_ptr::SharedPtrTarget;
513     pub use crate::string::StackString;
514     pub use crate::unique_ptr::UniquePtrTarget;
515     pub use crate::unwind::prevent_unwind;
516     pub use crate::weak_ptr::WeakPtrTarget;
517     pub use core::{concat, module_path};
518     pub use cxxbridge_macro::type_id;
519 }
520 
521 mod actually_private {
522     pub trait Private {}
523 }
524 
525 macro_rules! chars {
526     ($($ch:ident)*) => {
527         $(
528             #[doc(hidden)]
529             pub enum $ch {}
530         )*
531     };
532 }
533 
534 chars! {
535     _0 _1 _2 _3 _4 _5 _6 _7 _8 _9
536     A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
537     a b c d e f g h i j k l m n o p q r s t u v w x y z
538     __ // underscore
539 }
540 
541 #[repr(transparent)]
542 struct void(core::ffi::c_void);
543