cxx_enumext/
lib.rs

1/*
2 * Copyright (c) Rachel Powers.
3 *
4 * This source code is licensed under both the MIT license found in the
5 * LICENSE-MIT file in the root directory of this source tree and the Apache
6 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
7 * of this source tree.
8 */
9
10//! `cxx-enumext` is a Rust crate that extends the [`cxx`](http://cxx.rs/) library to provide
11//! a mapping between Rust variant enums and c++ standards like `std::variant`, `std::optional`
12//! and `std::expected`. Unfortunately the memory modal and null pointer optimisations in play
13//! make direct mappings between the two extremely difficult. As such, `cxx-enumext` provides
14//! analogs which should be identical in usage.
15//!
16//! `rust::enm::variant` is a analog for `std::variant` which can fully map a `#[repr(c)]` Rust
17//! Enum. The `#[cxx_enumext::extern_type]` macro will transform yur enums apropreatly as well as
18//! provide some sanity check static assertions about their contents for the current limitations of cxx
19//! ffi.
20//!
21//! `rust::enum::optional` is a derivation from `rust::enm::variant` which provides the interface of
22//! `std::optional`
23//!
24//! `rust::enum::expected` is a derivation from `rust::enm::variant` which provides the interface of
25//! `std::expected`
26//!
27//! ## Quick tutorial
28//!
29//! To use `cxx-enumext`, first start by adding `cxx` to your project. Then add the following to your
30//! `Cargo.toml`:
31//!
32//! ```toml
33//! [dependencies]
34//! cxx-enumext = "0.1"
35//! ```
36//!
37//! If your going to put other extern(d) types or shared types inside your enums declare them
38//! in a seperate module so that you don't deal with the c++ compiler complaing
39//! about incompleate types
40//!
41//! ```rust
42//! //! my_crate/src/data.rs
43//!
44//! #[cxx::bridge]
45//! pub mod ffi {
46//!
47//!     #[derive(Debug)]
48//!     struct SharedData {
49//!         size: i64,
50//!         tags: Vec<String>,
51//!     }
52//!
53//!     extern "Rust" {
54//!         type RustValue;
55//!         fn read(&self) -> &String;
56//!
57//!         fn new_rust_value() -> Box<RustValue>;
58//!     }
59//! }
60//!
61//! fn new_rust_value() -> Box<RustValue> {
62//!     Box::new(RustValue {
63//!         value: "A Hidden Rust String".into(),
64//!     })
65//! }
66//!
67//! #[derive(Default, Debug, Clone)]
68//! pub struct RustValue {
69//!     value: String,
70//! }
71//!
72//! impl RustValue {
73//!     pub fn read(&self) -> &String {
74//!         &self.value
75//!     }
76//!     pub fn new(val: &str) -> Self {
77//!         RustValue {
78//!             value: val.to_string(),
79//!         }
80//!     }
81//! }
82//! ```
83//!
84//! Now, simply declare your enum, optional, or expected
85//!
86//! ```rust
87//! //! my_crate/src/enum.rs
88//!
89//! use data::{RustValue, ffi::SharedData};
90//!
91//! // enums -> variants are declared as is
92//! // all variant types are supported
93//! // (Unnamed struct, named structs, unit, single type wrappers)
94//! #[derive(Debug)]
95//! #[cxx_enumext::extern_type]
96//! pub enum RustEnum<'a> {
97//!     Empty,
98//!     Num(i64),
99//!     String(String),
100//!     Bool(bool),
101//!     Shared(SharedData),
102//!     SharedRef(&'a SharedData),
103//!     Opaque(Box<RustValue>),
104//!     OpaqueRef(&'a RustValue),
105//!     Tuple(i32, i32),
106//!     Struct { val: i32, str: String },
107//!     Unit1,
108//!     Unit2,
109//! }
110//!
111//! // Declare type aliases for an Optional, "alias" can be for `Optional<T>` or
112//! // `cxx_enumext::Optional<T>`, neither type truely exists but the name will be
113//! // used to determine the enum variants to generate
114//!
115//! // `cxx_name` and `namespace` are supported and function identically to `cxx`
116//! #[cxx_enumext::extern_type(cxx_name = "OptionalInt32")]
117//! #[derive(Debug)]
118//! pub type OptionalI32 = Optional<i32>;
119//!
120//!
121//! // Declare type aliases for an Expected, "alias" can be for `Expected<T,E>` or
122//! // `cxx_enumext::Expected<T,E>`, neither type truely exists but the name will be
123//! // used to determine the enum variants to generate
124//! #[cxx_enumext::extern_type]
125//! #[derive(Debug)]
126//! pub type I32StringResult = cxx_enumext::Expected<i32, String>;
127//!
128//!
129//! #[cxx::bridge]
130//! pub mod ffi {
131//!
132//!     unsafe extern "C++" {
133//!         include!("my_crate/src/enum.h");
134//!
135//!         type RustEnum<'a> = super::RustEnum<'a>;
136//!         type I32StringResult = super::I32StringResult;
137//!         type OptionalInt32 = super::OptionalI32;
138//!     }
139//! }
140//! ```
141//!
142//! This will generate the `cxx::ExternType` impl as well as some non-exhaustive
143//! static assertions to check that contained types are at least externable.
144//!
145//! for `Optional` and `Expected` types some `std::convert::From<T>` impls will be cenerated
146//! to convert from and to `Option` and `Result` types
147//!
148//! Now, in your C++ file, make sure to `#include` the right headers:
149//!
150//! ```cpp
151//! #include "rust/cxx.h"
152//! #include "rust/cxx_enumext.h"
153//! #include "rust/cxx_enumext_macros.h"
154//! ```
155//!
156//! And add a call to the `CXX_DEFINE_VARIANT`, `CXXASYNC_DEFINE_OPTIONAL`,
157//! and or `CXXASYNC_DEFINE_EXPECTED` macro as apropreate to define the C++ side of the types:
158//!
159//! ```cpp
160//! // my_crate/src/enum.h
161//!
162//! #include "rust/cxx.h"
163//! #include "rust/cxx_enumext.h"
164//! #include "rust/cxx_enumext_macros.h"
165//!
166//! #include "my_crate/src/data.rs.h"
167//!
168//! // The first argument is the name of the C++ type, and the second argument is a parentheses
169//! // enclosed list of variant directives to devine the inner variants.
170//! // They must be declared in the same order as the rust enum and specify the appropriate C++ type.
171//! // An optional third (actualy variadic) argument is placed verbatim in the resulting struct body.
172//! //
173//! // This macro must be invoked in the correct namespace to define the type.
174//! CXX_DEFINE_VARIANT(
175//!     RustEnum,
176//!     (UNIT(Empty) /*(Alias name)*/, TYPE(Num, int64_t) /*(Alias name, type)*/,
177//!      TYPE(String, rust::string) /*by value rust type*/,
178//!      TYPE(Bool, bool) /*primative type*/,
179//!      TYPE(Shared, SharedData) /*shared type*/,
180//!      TYPE(
181//!          SharedRef,
182//!          std::reference_wrapper<SharedData>) /* if your using a refrence wrap is
183//!                                                 in a `std::reference_wrapper`*/
184//!      ,
185//!      TYPE(Opaque, rust::box<RustValue>) /* boxed opaque rust type*/,
186//!      TYPE(OpaqueRef,
187//!           std::reference_wrapper<RustValue>) /*refren to opaque rust type*/,
188//!      TUPLE(Tuple, int32_t, int32_t) /*(Alias name, [list, of, types]) => struct
189//!                                        aliast_t{ T1 _0; T2 _1; ...};*/
190//!      ,
191//!      STRUCT(Struct, int32_t val;
192//!             rust::string str;) /*(Alias name, body of struct for members) struct
193//!                                   alist_t{body}; */
194//!      ,
195//!      UNIT(Unit1) /*More the one unit type supported, each is just a `struct
196//!                     alias_t {};`*/
197//!      ,
198//!      UNIT(Unit2) /*NO TRAILING COMMA*/
199//!      ),
200//!     /* optional section injected into the type body (for declareing member
201//!        function etc.) */
202//!     /* DO NOT DECLARE EXTRA MEMBER VARIABLES, THIS WILL MAKE THE TYPE HAVE */
203//!     /* AN INCORRECT MEMORY LAYOUT */
204//! )
205//!
206//!
207//! // The first argument is the name of the C++ type, and the second contained type
208//! // An optional third (actualy variadic) argument is placed verbatim in the resulting struct body.
209//! CXX_DEFINE_OPTIONAL(OptionalInt32, int32_t)
210//!
211//! // The first argument is the name of the C++ type, and the second and third
212//! // are the expected and unexpected types respectively.
213//! // An optional forth (actualy variadic) argument is placed verbatim in the resulting struct body.
214//! CXX_DEFINE_EXPECTED(I32StringResult, int32_t, rust::string)
215//!
216//! ```
217//!
218//! You're all set! Now you can use the enum types on either side of your ffi.
219//!
220//! ## Installation notes
221//!
222//! You will need a C++ compiler that implements c++17
223//!
224//! ## Refrence
225//!
226//! ### `rust::enm::variant`
227//!
228//! Simplicited declaration
229//!
230//! ```c++
231//!
232//! namespace rust {
233//! namespace enm {
234//!
235//! /// @brief The getf method which returns a pointer to T if the variant
236//! // contains T, otherwise throws `bad_rust_variant_access`
237//! template <std::size_t I, typename... Ts>
238//! constexpr decltype(auto) get(variant_base<Ts...> &);
239//!
240//! template <std::size_t I, typename... Ts>
241//! constexpr decltype(auto) get(const variant_base<Ts...> &);
242//!
243//! /// @brief The get_if method which returns a pointer to T if the variant
244//! /// contains T other wise `nullptr`.
245//! template <std::size_t I, typename... Ts>
246//! constexpr std::add_pointer_t<variant_alternative_t<I, Ts...>>
247//! get_if(variant_base<Ts...> *variant);
248//!
249//! template <std::size_t I, typename... Ts>
250//! constexpr const std::add_pointer_t<variant_alternative_t<I, Ts...>>
251//! get_if(const variant_base<Ts...> *variant);
252//!
253//! /// @brief The visit method which will pick the right type depending on the
254//! /// `index` value.
255//! template <typename Visitor, typename... Ts>
256//! constexpr decltype(auto) visit(Visitor &&visitor, variant_base<Ts...> &);
257//!
258//! template <typename Visitor, typename... Ts>
259//! constexpr decltype(auto) visit(Visitor &&visitor, const variant_base<Ts...> &);
260//!
261//!
262//! /// @brief The holds_alternative method which will return true if the
263//! /// variant contains the type at index I
264//! template <std::size_t I, typename... Ts>
265//! constexpr bool holds_alternative(const variant_base<Ts...> &variant);
266//!
267//! /// @brief The holds_alternative method which will return true if the
268//! /// variant contains T
269//! template <typename T, typename... Ts,
270//!           typename = std::enable_if_t<
271//!               exactly_once<std::is_same_v<Ts, std::decay_t<T>>...>::value>>
272//! constexpr bool holds_alternative(const variant_base<Ts...> &variant);
273//!
274//! template <typename... Ts> struct variant {
275//!   /// @brief Converting constructor. Corresponds to (4) constructor of
276//!   /// std::variant.
277//!   template <typename T, typename D = std::decay_t<T>,
278//!             typename = std::enable_if_t<is_unique_v<T> &&
279//!                                         std::is_constructible_v<D, T>>>
280//!   variant(T &&other) noexcept(std::is_nothrow_constructible_v<D, T>);
281//!
282//!   /// @brief Participates in the resolution only if we can construct T from
283//!   /// Args and if T is unique in Ts. Corresponds to (5) constructor of
284//!   /// std::variant.
285//!   template <typename T, typename... Args,
286//!             typename = std::enable_if_t<is_unique_v<T>>,
287//!             typename = std::enable_if_t<std::is_constructible_v<T, Args...>>>
288//!   explicit variant(std::in_place_type_t<T> type, Args &&...args) noexcept(
289//!       std::is_nothrow_constructible_v<T, Args...>);
290//!
291//!   /// @brief Participates in the resolution only if the index is within range
292//!   /// and if the type can be constructor from Args. Corresponds to (7) of
293//!   /// std::variant.
294//!   template <std::size_t I, typename... Args, typename T = type_from_index_t<I>,
295//!             typename = std::enable_if_t<std::is_constructible_v<T, Args...>>>
296//!   explicit variant(
297//!       [[maybe_unused]] std::in_place_index_t<I> index,
298//!       Args &&...args) noexcept(std::is_nothrow_constructible_v<T, Args...>);
299//!
300//!   /// @brief Converts the std::variant to our variant. Participates only in
301//!   /// the resolution if all types in Ts are copy constructable.
302//!   template <typename... Rs, typename = std::enable_if_t<
303//!                                 all_same_v<Rs...> && all_copy_constructible_v>>
304//!   variant(const std::variant<Rs...> &other);
305//!
306//!   /// @brief Converts the std::variant to our variant. Participates only in
307//!   /// the resolution if all types in Ts are move constructable.
308//!   template <typename... Rs, typename = std::enable_if_t<
309//!                                 all_same_v<Rs...> && all_move_constructible_v>>
310//!   variant(std::variant<Rs...> &&other);
311//!
312//!   /// @brief Copy assignment. Statically fails if not every type in Ts is copy
313//!   /// constructable. Corresponds to (1) assignment of std::variant.
314//!   variant_base &operator=(const variant_base &other);
315//!
316//!   /// @brief Deleted move assignment. Same as for the move constructor.
317//!   /// Would correspond to (2) assignment of std::variant.
318//!   variant_base &operator=(variant_base &&other) = delete;
319//!
320//!   /// @brief Converting assignment. Corresponds to (3) assignment of
321//!   /// std::variant.
322//!   template <typename T, typename = std::enable_if_t<
323//!                             is_unique_v<T> && std::is_constructible_v<T &&, T>>>
324//!   variant_base &operator=(T &&other);
325//!
326//!   /// @brief Converting assignment from std::variant. Participates only in the
327//!   /// resolution if all types in Ts are copy constructable.
328//!   template <typename... Rs, typename = std::enable_if_t<
329//!                                 all_same_v<Rs...> && all_copy_constructible_v>>
330//!   variant_base &operator=(const std::variant<Rs...> &other);
331//!
332//!   /// @brief Converting assignment from std::variant. Participates only in the
333//!   /// resolution if all types in Ts are move constructable.
334//!   template <typename... Rs, typename = std::enable_if_t<
335//!                                 all_same_v<Rs...> && all_move_constructible_v>>
336//!   variant_base &operator=(std::variant<Rs...> &&other);
337//!
338//!   /// @brief Emplace function. Participates in the resolution only if T is
339//!   /// unique in Ts and if T can be constructed from Args. Offers strong
340//!   /// exception guarantee. Corresponds to the (1) emplace function of
341//!   /// std::variant.
342//!   template <typename T, typename... Args,
343//!             typename = std::enable_if_t<is_unique_v<T>>,
344//!             typename = std::enable_if_t<std::is_constructible_v<T, Args...>>>
345//!   T &emplace(Args &&...args);
346//!
347//!   /// @brief Emplace function. Participates in the resolution only if T can be
348//!   /// constructed from Args. Offers strong exception guarantee. Corresponds to
349//!   /// the (2) emplace function of std::variant.
350//!   ///
351//!   /// The std::variant can have no valid state if the type throws during the
352//!   /// construction. This is represented by the `valueless_by_exception` flag.
353//!   /// The same approach is also used in absl::variant [2].
354//!   /// In our case we can't accept valueless enums since we can't represent
355//!   /// this in Rust. We must therefore provide a strong exception guarantee for
356//!   /// all operations using `emplace`. Two famous implementations of never
357//!   /// valueless variants are Boost/variant [3] and Boost/variant2 [4].
358//!   /// Boost/variant2 uses two memory buffers - which would be not compatible
359//!   /// with Rust Enum's memory layout. The Boost/variant backs up the old
360//!   /// object and calls its d'tor before constructing the new object; It then
361//!   /// copies the old data back to the buffer if the construction fails - which
362//!   /// might contain garbage (since) the d'tor was already called.
363//!   ///
364//!   ///
365//!   /// We take a similar approach to Boost/variant. Assuming that constructing
366//!   /// or moving the new type can throw, we backup the old data, try to
367//!   /// construct the new object in the final buffer, swap the buffers, such
368//!   /// that the old object is back in its original place, destroy it and move
369//!   /// the new object from the old buffer back to the final place.
370//!   ///
371//!   /// Sources
372//!   ///
373//!   /// [1]
374//!   /// https://en.cppreference.com/w/cpp/utility/variant/valueless_by_exception
375//!   /// [2]
376//!   /// https://github.com/abseil/abseil-cpp/blob/master/absl/types/variant.h
377//!   /// [3]
378//!   /// https://www.boost.org/doc/libs/1_84_0/libs/variant2/doc/html/variant2.html
379//!   /// [4]
380//!   /// https://www.boost.org/doc/libs/1_84_0/doc/html/variant/design.html#variant.design.never-empty
381//!   template <std::size_t I, typename... Args, typename T = type_from_index_t<I>,
382//!             typename = std::enable_if_t<std::is_constructible_v<T, Args...>>>
383//!   T &emplace(Args &&...args);
384//!
385//!   constexpr std::size_t index() const noexcept;
386//!
387//!   void swap(variant_base &other);
388//!
389//!
390//!   struct bad_rust_variant_access : std::runtime_error {
391//!     bad_rust_variant_access(std::size_t index)
392//!         : std::runtime_error{"The index should be " + std::to_string(index)} {}
393//!   };
394//! }
395//!
396//! } // namespace enm
397//! } // namespace rust
398//! ```
399//!
400//! ### `rust::enm::Optional`
401//!
402//! Simplicited declaration
403//!
404//! ```c++
405//!
406//! namespace rust {
407//! namespace enm {
408//!
409//! struct bad_rust_optional_access : std::runtime_error {
410//!   bad_rust_optional_access() : std::runtime_error{"Optional has no value"} {}
411//! };
412//!
413//! template <typename T> struct optional : public variant<monostate, T> {
414//!   using base = variant<monostate, T>;
415//!
416//!   optional() : base(monostate{}) {};
417//!   optional(std::nullopt_t) : base(monostate{}) {};
418//!   optional(const optional &) = default;
419//!   optional(optional &&) = delete;
420//!
421//!   using base::base;
422//!   using base::operator=;
423//!
424//!   using Some = T;
425//!   using None = monostate;
426//!
427//!   constexpr explicit operator bool() { return this->m_Index == 1; }
428//!   constexpr bool has_value() const noexcept { return this->m_Index == 1; }
429//!   constexpr bool is_some() const noexcept { return this->m_Index == 1; }
430//!   constexpr bool is_none() const noexcept { return this->m_Index == 0; }
431//!
432//!   /// @brief returns the contined value
433//!   ///
434//!   /// if `*this` contains a value returns a refrence. Otherwise throws
435//!   /// bad_rust_optional_access
436//!   /// @throws bad_rust_optional_access
437//!   constexpr T &value() &;
438//!
439//!   /// @brief returns the contined value
440//!   ///
441//!   /// if `*this` contains a value returns a refrence. Otherwise throws
442//!   /// bad_rust_optional_access
443//!   /// @throws bad_rust_optional_access
444//!   constexpr const T &value() const &;
445//!
446//!   /// @brief resets the optional to an empty state
447//!   ///
448//!   /// if `has_value()` is true first calls the deconstructor
449//!   constexpr void reset() noexcept;
450//!
451//!   constexpr const T *operator->() const noexcept;
452//!   constexpr T *operator->() noexcept;
453//!
454//!   constexpr const T &operator*() const & noexcept;
455//!   constexpr T &operator*() & noexcept;
456//!
457//!   template <class U = std::remove_cv_t<T>>
458//!   constexpr T value_or(U &&default_value) const &;
459//!
460//!   template <class F> constexpr auto and_then(F &&f) &;
461//!   template <class F> constexpr auto and_then(F &&f) const &;
462//!   template <class F> constexpr auto transform(F &&f) &;
463//!
464//!   template <class F> constexpr auto transform(F &&f) const &;
465//!
466//!   template <class F> constexpr T &or_else(F &&f) &;
467//!   template <class F> constexpr const T &or_else(F &&f) const &;
468//! };
469//!
470//!
471//! /// Compares two optional objects
472//! template <class T, class U>
473//! inline constexpr bool operator==(const optional<T> &lhs,
474//!                                  const optional<U> &rhs);
475//! template <class T, class U>
476//! inline constexpr bool operator!=(const optional<T> &lhs,
477//!                                  const optional<U> &rhs);
478//! template <class T, class U>
479//! inline constexpr bool operator<(const optional<T> &lhs,
480//!                                 const optional<U> &rhs)
481//! // ... and many more compare operators
482//! ```
483//!
484//! ### `rust::enm::expected`
485//!
486//! Simplicited declaration
487//!
488//! ```c++
489//!
490//! namespace rust {
491//! namespace enm {
492//!
493//! template <typename E> struct bad_rust_expected_access : std::runtime_error {
494//!   bad_rust_expected_access(const E &err)
495//!       : std::runtime_error{"Expected is the unexpected value"}, error(err) {}
496//!   E error;
497//! };
498//!
499//! template <typename T, typename E> struct expected : public variant<T, E> {
500//!   using base = variant<T, E>;
501//!
502//!   expected() = delete;
503//!   expected(const expected &) = default;
504//!   expected(expected &&) = delete;
505//!
506//!   using base::base;
507//!   using base::operator=;
508//!
509//!   using Ok = T;
510//!   using Err = E;
511//!
512//!   constexpr explicit operator bool() { return this->m_Index == 0; }
513//!   constexpr bool has_value() const noexcept { return this->m_Index == 0; }
514//!
515//!   /// @brief returns the expected value
516//!   ///
517//!   /// @throws bad_rust_expected_access<E> with a copy of the unexpected value
518//!   constexpr T &value() &;
519//!
520//!   /// @brief returns the expected value
521//!   ///
522//!   /// @throws bad_rust_expected_access<E> with a copy of the unexpected value
523//!   constexpr const T &value() const &;
524//!
525//!   /// @brief returns the unexpected value
526//!   ///
527//!   /// if has_value() is `true`, the behavior is undefined
528//!   constexpr E &error() &;
529//!
530//!   /// @brief returns the unexpected value
531//!   ///
532//!   /// if has_value() is `true`, the behavior is undefined
533//!   constexpr const E &error() const &;
534//!
535//!   constexpr const T *operator->() const noexcept;
536//!   constexpr T *operator->() noexcept;
537//!
538//!   constexpr const T &operator*() const & noexcept;
539//!   constexpr T &operator*() & noexcept;
540//!
541//!   /// @brief Returns the expected value if it exists, otherwise returns
542//!   /// `default_value`
543//!   template <class U = std::remove_cv_t<T>>
544//!   constexpr T value_or(U &&default_value) const &;
545//!
546//!   /// @brief Returns the unexpected value if it exists, otherwise returns
547//!   /// `default_value`
548//!   template <class G = E> constexpr E error_or(G &&default_value) const &;
549//!
550//!   template <class F> constexpr auto and_then(F &&f) &;
551//!   template <class F> constexpr auto and_then(F &&f) const &;
552//!
553//!   template <class F> constexpr auto transform(F &&f) &;
554//!   template <class F> constexpr auto transform(F &&f) const &;
555//!
556//!   template <class F> constexpr T &or_else(F &&f) &;
557//!   template <class F> constexpr const T &or_else(F &&f) const &;
558//!
559//!   template <class F> constexpr auto transform_error(F &&f) &;
560//!   template <class F> constexpr auto transform_error(F &&f) const &;
561//!
562//! };
563//!
564//! } // namespace enm
565//! } // namespace rust
566//! ```
567//!
568
569pub use cxx_enumext_macro::extern_type;
570
571/// Private assert helpers
572pub mod private {
573
574    #[allow(dead_code)]
575    pub trait NotCxxExternType {
576        const IS_CXX_EXTERN_TYPE: bool = false;
577    }
578    impl<T: ?Sized> NotCxxExternType for T {}
579    pub struct IsCxxExternType<T: ?Sized>(std::marker::PhantomData<T>);
580    #[allow(dead_code)]
581    impl<T: ?Sized + ::cxx::ExternType> IsCxxExternType<T> {
582        pub const IS_CXX_EXTERN_TYPE: bool = true;
583    }
584
585    #[allow(dead_code)]
586    pub trait NotCxxExternTrivial {
587        const IS_CXX_EXTERN_TRIVIAL: bool = false;
588    }
589    impl<T: ?Sized> NotCxxExternTrivial for T {}
590    pub struct IsCxxExternTrivial<T: ?Sized>(std::marker::PhantomData<T>);
591    #[allow(dead_code)]
592    impl<T: ?Sized + ::cxx::ExternType<Kind = ::cxx::kind::Trivial>> IsCxxExternTrivial<T> {
593        pub const IS_CXX_EXTERN_TRIVIAL: bool = true;
594    }
595
596    #[allow(dead_code)]
597    pub trait NotCxxExternOpaque {
598        const IS_CXX_EXTERN_OPAQUE: bool = false;
599    }
600    impl<T: ?Sized> NotCxxExternOpaque for T {}
601    pub struct IsCxxExternOpaque<T: ?Sized>(std::marker::PhantomData<T>);
602    #[allow(dead_code)]
603    impl<T: ?Sized + ::cxx::ExternType<Kind = ::cxx::kind::Trivial>> IsCxxExternOpaque<T> {
604        pub const IS_CXX_EXTERN_OPAQUE: bool = true;
605    }
606
607    #[allow(dead_code)]
608    pub trait NotCxxImplVec {
609        const IS_CXX_IMPL_VEC: bool = false;
610    }
611    impl<T: ?Sized> NotCxxImplVec for T {}
612    pub struct IsCxxImplVec<T: ?Sized>(std::marker::PhantomData<T>);
613    #[allow(dead_code)]
614    impl<T: ?Sized + ::cxx::private::ImplVec> IsCxxImplVec<T> {
615        pub const IS_CXX_IMPL_VEC: bool = true;
616    }
617
618    #[allow(dead_code)]
619    pub trait NotCxxImplBox {
620        const IS_CXX_IMPL_BOX: bool = false;
621    }
622    impl<T: ?Sized> NotCxxImplBox for T {}
623    pub struct IsCxxImplBox<T: ?Sized>(std::marker::PhantomData<T>);
624    #[allow(dead_code)]
625    impl<T: ?Sized + ::cxx::private::ImplBox> IsCxxImplBox<T> {
626        pub const IS_CXX_IMPL_BOX: bool = true;
627    }
628}