#pragma once #include #include #include #include #include #include #include #include #include #include #include #if defined(_WIN32) #include #endif namespace rust { inline namespace cxxbridge1 { struct unsafe_bitcopy_t; namespace { template class impl; } #ifndef CXXBRIDGE1_RUST_STRING #define CXXBRIDGE1_RUST_STRING class String final { public: String() noexcept; String(const String &) noexcept; String(String &&) noexcept; ~String() noexcept; String(const std::string &); String(const char *); String(const char *, size_t); String &operator=(const String &) noexcept; String &operator=(String &&) noexcept; explicit operator std::string() const; // Note: no null terminator. const char *data() const noexcept; size_t size() const noexcept; size_t length() const noexcept; // Internal API only intended for the cxxbridge code generator. String(unsafe_bitcopy_t, const String &) noexcept; private: // Size and alignment statically verified by rust_string.rs. std::array repr; }; #endif // CXXBRIDGE1_RUST_STRING #ifndef CXXBRIDGE1_RUST_STR class Str final { public: Str() noexcept; Str(const std::string &); Str(const char *); Str(const char *, size_t); Str &operator=(const Str &) noexcept = default; explicit operator std::string() const; // Note: no null terminator. const char *data() const noexcept; size_t size() const noexcept; size_t length() const noexcept; // Important in order for System V ABI to pass in registers. Str(const Str &) noexcept = default; ~Str() noexcept = default; private: friend impl; // Not necessarily ABI compatible with &str. Codegen will translate to // cxx::rust_str::RustStr which matches this layout. const char *ptr; size_t len; }; #endif // CXXBRIDGE1_RUST_STR #ifndef CXXBRIDGE1_RUST_SLICE namespace detail { template struct copy_assignable_if {}; template <> struct copy_assignable_if { copy_assignable_if() noexcept = default; copy_assignable_if(const copy_assignable_if &) noexcept = default; copy_assignable_if &operator=(const copy_assignable_if &) noexcept = delete; copy_assignable_if &operator=(copy_assignable_if &&) noexcept = default; }; } // namespace detail template class Slice final : private detail::copy_assignable_if::value> { public: Slice() noexcept; Slice(T *, size_t count) noexcept; Slice &operator=(const Slice &) noexcept = default; Slice &operator=(Slice &&) noexcept = default; T *data() const noexcept; size_t size() const noexcept; size_t length() const noexcept; // Important in order for System V ABI to pass in registers. Slice(const Slice &) noexcept = default; ~Slice() noexcept = default; class iterator; iterator begin() const noexcept; iterator end() const noexcept; private: friend impl; // Not necessarily ABI compatible with &[T]. Codegen will translate to // cxx::rust_slice::RustSlice which matches this layout. T *ptr; size_t len; }; template class Slice::iterator final { public: using difference_type = ptrdiff_t; using value_type = T; using pointer = typename std::add_pointer::type; using reference = typename std::add_lvalue_reference::type; using iterator_category = std::forward_iterator_tag; T &operator*() const noexcept; T *operator->() const noexcept; iterator &operator++() noexcept; iterator operator++(int) noexcept; bool operator==(const iterator &) const noexcept; bool operator!=(const iterator &) const noexcept; private: friend class Slice; T *pos; }; #endif // CXXBRIDGE1_RUST_SLICE #ifndef CXXBRIDGE1_RUST_BOX template class Box final { public: using value_type = T; using const_pointer = typename std::add_pointer::type>::type; using pointer = typename std::add_pointer::type; Box(const Box &); Box(Box &&) noexcept; ~Box() noexcept; explicit Box(const T &); explicit Box(T &&); Box &operator=(const Box &); Box &operator=(Box &&) noexcept; const T *operator->() const noexcept; const T &operator*() const noexcept; T *operator->() noexcept; T &operator*() noexcept; template static Box in_place(Fields &&...); // Important: requires that `raw` came from an into_raw call. Do not pass a // pointer from `new` or any other source. static Box from_raw(T *) noexcept; T *into_raw() noexcept; private: Box() noexcept; void uninit() noexcept; void drop() noexcept; T *ptr; }; #endif // CXXBRIDGE1_RUST_BOX #ifndef CXXBRIDGE1_RUST_VEC template class Vec final { public: using value_type = T; Vec() noexcept; Vec(Vec &&) noexcept; ~Vec() noexcept; Vec &operator=(Vec &&) noexcept; size_t size() const noexcept; bool empty() const noexcept; const T *data() const noexcept; T *data() noexcept; const T &operator[](size_t n) const noexcept; const T &at(size_t n) const; const T &front() const; const T &back() const; void reserve(size_t new_cap); void push_back(const T &value); void push_back(T &&value); template void emplace_back(Args &&... args); class iterator; iterator begin() noexcept; iterator end() noexcept; using const_iterator = typename Vec::iterator; const_iterator begin() const noexcept; const_iterator end() const noexcept; const_iterator cbegin() const noexcept; const_iterator cend() const noexcept; // Internal API only intended for the cxxbridge code generator. Vec(unsafe_bitcopy_t, const Vec &) noexcept; private: static size_t stride() noexcept; void reserve_total(size_t cap) noexcept; void set_len(size_t len) noexcept; void drop() noexcept; // Size and alignment statically verified by rust_vec.rs. std::array repr; }; template class Vec::iterator final { public: using difference_type = ptrdiff_t; using value_type = T; using pointer = typename std::add_pointer::type; using reference = typename std::add_lvalue_reference::type; using iterator_category = std::forward_iterator_tag; T &operator*() const noexcept; T *operator->() const noexcept; iterator &operator++() noexcept; iterator operator++(int) noexcept; bool operator==(const iterator &) const noexcept; bool operator!=(const iterator &) const noexcept; private: friend class Vec; friend class Vec::type>; void *pos; size_t stride; }; #endif // CXXBRIDGE1_RUST_VEC #ifndef CXXBRIDGE1_RUST_FN template class Fn; template class Fn final { public: Ret operator()(Args... args) const noexcept(!Throws); Fn operator*() const noexcept; private: Ret (*trampoline)(Args..., void *fn) noexcept(!Throws); void *fn; }; template using TryFn = Fn; #endif // CXXBRIDGE1_RUST_FN #ifndef CXXBRIDGE1_RUST_ERROR #define CXXBRIDGE1_RUST_ERROR class Error final : public std::exception { public: Error(const Error &); Error(Error &&) noexcept; ~Error() noexcept override; Error &operator=(const Error &); Error &operator=(Error &&) noexcept; const char *what() const noexcept override; private: Error() noexcept = default; friend impl; const char *msg; size_t len; }; #endif // CXXBRIDGE1_RUST_ERROR #ifndef CXXBRIDGE1_RUST_ISIZE #define CXXBRIDGE1_RUST_ISIZE #if defined(_WIN32) using isize = SSIZE_T; #else using isize = ssize_t; #endif #endif // CXXBRIDGE1_RUST_ISIZE std::ostream &operator<<(std::ostream &, const String &); std::ostream &operator<<(std::ostream &, const Str &); #ifndef CXXBRIDGE1_RUST_OPAQUE #define CXXBRIDGE1_RUST_OPAQUE // Base class of generated opaque Rust types. class Opaque { public: Opaque() = delete; Opaque(const Opaque &) = delete; ~Opaque() = delete; }; #endif // CXXBRIDGE1_RUST_OPAQUE // IsRelocatable is used in assertions that a C++ type passed by value // between Rust and C++ is soundly relocatable by Rust. // // There may be legitimate reasons to opt out of the check for support of types // that the programmer knows are soundly Rust-movable despite not being // recognized as such by the C++ type system due to a move constructor or // destructor. To opt out of the relocatability check, do either of the // following things in any header used by `include!` in the bridge. // // --- if you define the type: // struct MyType { // ... // + using IsRelocatable = std::true_type; // }; // // --- otherwise: // + template <> // + struct rust::IsRelocatable : std::true_type {}; template struct IsRelocatable; // Snake case aliases for use in code that uses this style for type names. using string = String; using str = Str; template using slice = Slice; template using box = Box; template using vec = Vec; using error = Error; template using fn = Fn; template using try_fn = TryFn; template using is_relocatable = IsRelocatable; //////////////////////////////////////////////////////////////////////////////// /// end public API, begin implementation details #ifndef CXXBRIDGE1_PANIC #define CXXBRIDGE1_PANIC template void panic [[noreturn]] (const char *msg); #endif // CXXBRIDGE1_PANIC #ifndef CXXBRIDGE1_RUST_FN #define CXXBRIDGE1_RUST_FN template Ret Fn::operator()(Args... args) const noexcept(!Throws) { return (*this->trampoline)(std::move(args)..., this->fn); } template Fn Fn::operator*() const noexcept { return *this; } #endif // CXXBRIDGE1_RUST_FN #ifndef CXXBRIDGE1_RUST_BITCOPY #define CXXBRIDGE1_RUST_BITCOPY struct unsafe_bitcopy_t final { explicit unsafe_bitcopy_t() = default; }; constexpr unsafe_bitcopy_t unsafe_bitcopy{}; #endif // CXXBRIDGE1_RUST_BITCOPY #ifndef CXXBRIDGE1_RUST_STR #define CXXBRIDGE1_RUST_STR inline const char *Str::data() const noexcept { return this->ptr; } inline size_t Str::size() const noexcept { return this->len; } inline size_t Str::length() const noexcept { return this->len; } #endif // CXXBRIDGE1_RUST_STR #ifndef CXXBRIDGE1_RUST_SLICE #define CXXBRIDGE1_RUST_SLICE template Slice::Slice() noexcept : ptr(reinterpret_cast(alignof(T))), len(0) {} template Slice::Slice(T *s, size_t count) noexcept : ptr(s), len(count) {} template T *Slice::data() const noexcept { return this->ptr; } template size_t Slice::size() const noexcept { return this->len; } template size_t Slice::length() const noexcept { return this->len; } template T &Slice::iterator::operator*() const noexcept { return *this->pos; } template T *Slice::iterator::operator->() const noexcept { return this->pos; } template typename Slice::iterator &Slice::iterator::operator++() noexcept { ++this->pos; return *this; } template typename Slice::iterator Slice::iterator::operator++(int) noexcept { auto ret = iterator(*this); ++this->pos; return ret; } template bool Slice::iterator::operator==(const iterator &other) const noexcept { return this->pos == other.pos; } template bool Slice::iterator::operator!=(const iterator &other) const noexcept { return this->pos != other.pos; } template typename Slice::iterator Slice::begin() const noexcept { iterator it; it.pos = this->ptr; return it; } template typename Slice::iterator Slice::end() const noexcept { iterator it = this->begin(); it.pos += this->len; return it; } #endif // CXXBRIDGE1_RUST_SLICE #ifndef CXXBRIDGE1_RUST_BOX #define CXXBRIDGE1_RUST_BOX template Box::Box(const Box &other) : Box(*other) {} template Box::Box(Box &&other) noexcept : ptr(other.ptr) { other.ptr = nullptr; } template Box::Box(const T &val) { this->uninit(); ::new (this->ptr) T(val); } template Box::Box(T &&val) { this->uninit(); ::new (this->ptr) T(std::move(val)); } template Box::~Box() noexcept { if (this->ptr) { this->drop(); } } template Box &Box::operator=(const Box &other) { if (this != &other) { if (this->ptr) { **this = *other; } else { this->uninit(); ::new (this->ptr) T(*other); } } return *this; } template Box &Box::operator=(Box &&other) noexcept { if (this->ptr) { this->drop(); } this->ptr = other.ptr; other.ptr = nullptr; return *this; } template const T *Box::operator->() const noexcept { return this->ptr; } template const T &Box::operator*() const noexcept { return *this->ptr; } template T *Box::operator->() noexcept { return this->ptr; } template T &Box::operator*() noexcept { return *this->ptr; } template template Box Box::in_place(Fields &&... fields) { Box box; box.uninit(); ::new (box.ptr) T{std::forward(fields)...}; return box; } template Box Box::from_raw(T *raw) noexcept { Box box; box.ptr = raw; return box; } template T *Box::into_raw() noexcept { T *raw = this->ptr; this->ptr = nullptr; return raw; } template Box::Box() noexcept = default; #endif // CXXBRIDGE1_RUST_BOX #ifndef CXXBRIDGE1_RUST_VEC #define CXXBRIDGE1_RUST_VEC template Vec::Vec(Vec &&other) noexcept : repr(other.repr) { new (&other) Vec(); } template Vec::~Vec() noexcept { this->drop(); } template Vec &Vec::operator=(Vec &&other) noexcept { if (this != &other) { this->drop(); this->repr = other.repr; new (&other) Vec(); } return *this; } template bool Vec::empty() const noexcept { return size() == 0; } template T *Vec::data() noexcept { return const_cast(const_cast *>(this)->data()); } template const T &Vec::operator[](size_t n) const noexcept { auto data = reinterpret_cast(this->data()); return *reinterpret_cast(data + n * this->stride()); } template const T &Vec::at(size_t n) const { if (n >= this->size()) { panic("rust::Vec index out of range"); } return (*this)[n]; } template const T &Vec::front() const { return (*this)[0]; } template const T &Vec::back() const { return (*this)[this->size() - 1]; } template void Vec::reserve(size_t new_cap) { this->reserve_total(new_cap); } template void Vec::push_back(const T &value) { this->emplace_back(value); } template void Vec::push_back(T &&value) { this->emplace_back(std::move(value)); } template template void Vec::emplace_back(Args &&... args) { auto size = this->size(); this->reserve_total(size + 1); ::new (reinterpret_cast(reinterpret_cast(this->data()) + size * this->stride())) T(std::forward(args)...); this->set_len(size + 1); } template T &Vec::iterator::operator*() const noexcept { return *static_cast(this->pos); } template T *Vec::iterator::operator->() const noexcept { return static_cast(this->pos); } template typename Vec::iterator &Vec::iterator::operator++() noexcept { this->pos = static_cast(this->pos) + this->stride; return *this; } template typename Vec::iterator Vec::iterator::operator++(int) noexcept { auto ret = iterator(*this); this->pos = static_cast(this->pos) + this->stride; return ret; } template bool Vec::iterator::operator==(const iterator &other) const noexcept { return this->pos == other.pos; } template bool Vec::iterator::operator!=(const iterator &other) const noexcept { return this->pos != other.pos; } template typename Vec::iterator Vec::begin() noexcept { iterator it; it.pos = const_cast::type *>(this->data()); it.stride = this->stride(); return it; } template typename Vec::iterator Vec::end() noexcept { iterator it = this->begin(); it.pos = static_cast(it.pos) + it.stride * this->size(); return it; } template typename Vec::const_iterator Vec::begin() const noexcept { return this->cbegin(); } template typename Vec::const_iterator Vec::end() const noexcept { return this->cend(); } template typename Vec::const_iterator Vec::cbegin() const noexcept { const_iterator it; it.pos = const_cast::type *>(this->data()); it.stride = this->stride(); return it; } template typename Vec::const_iterator Vec::cend() const noexcept { const_iterator it = this->cbegin(); it.pos = static_cast(it.pos) + it.stride * this->size(); return it; } // Internal API only intended for the cxxbridge code generator. template Vec::Vec(unsafe_bitcopy_t, const Vec &bits) noexcept : repr(bits.repr) {} #endif // CXXBRIDGE1_RUST_VEC #ifndef CXXBRIDGE1_RELOCATABLE #define CXXBRIDGE1_RELOCATABLE namespace detail { template struct make_void { using type = void; }; template using void_t = typename make_void::type; template class, typename...> struct detect : std::false_type {}; template