blob: 31350927936bfe624227c59c9afd1f7edc42b8f7 [file] [log] [blame]
David Tolnay7db73692019-10-20 14:51:12 -04001#pragma once
2#include <array>
3#include <cstdint>
4#include <iostream>
5#include <string>
6
7namespace cxxbridge00 {
8
9class RustString final {
10public:
11 RustString() noexcept;
12 RustString(const RustString &other) noexcept;
13 RustString(RustString &&other) noexcept;
14 RustString(const char *s);
15 RustString(const std::string &s);
16 RustString &operator=(const RustString &other) noexcept;
17 RustString &operator=(RustString &&other) noexcept;
18 ~RustString() noexcept;
19 operator std::string() const;
20
21 // Note: no null terminator.
22 const char *data() const noexcept;
23 size_t size() const noexcept;
24 size_t length() const noexcept;
25
26private:
27 // Size and alignment statically verified by rust_string.rs.
28 std::array<uintptr_t, 3> repr;
29};
30
31class RustStr final {
32public:
33 RustStr() noexcept;
34 RustStr(const char *s);
35 RustStr(const std::string &s);
36 RustStr(std::string &&s) = delete;
37 RustStr(const RustStr &other) noexcept;
38 RustStr &operator=(RustStr other) noexcept;
39 operator std::string() const;
40
41 // Note: no null terminator.
42 const char *data() const noexcept;
43 size_t size() const noexcept;
44 size_t length() const noexcept;
45
46 // Repr is PRIVATE; must not be used other than by our generated code.
47 //
48 // Not necessarily ABI compatible with &str. Codegen will translate to
49 // cxx::rust_str::RustStr which matches this layout.
50 struct Repr {
51 const char *ptr;
52 size_t len;
53 };
54 RustStr(Repr repr) noexcept;
55 operator Repr() noexcept;
56
57private:
58 Repr repr;
59};
60
61#ifndef CXXBRIDGE00_RUST_BOX
62#define CXXBRIDGE00_RUST_BOX
63template <typename T> class RustBox final {
64public:
65 RustBox(const RustBox &other) : RustBox(*other) {}
66 RustBox(RustBox &&other) noexcept : repr(other.repr) { other.repr = 0; }
67 RustBox(const T &val) {
68 this->uninit();
69 new (this->deref_mut()) T(val);
70 }
71 RustBox &operator=(const RustBox &other) {
72 if (this != &other) {
73 if (this->repr) {
74 **this = *other;
75 } else {
76 this->uninit();
77 new (this->deref_mut()) T(*other);
78 }
79 }
80 return *this;
81 }
82 RustBox &operator=(RustBox &&other) noexcept {
83 if (this->repr) {
84 this->drop();
85 }
86 this->repr = other.repr;
87 other.repr = 0;
88 return *this;
89 }
90 ~RustBox() noexcept {
91 if (this->repr) {
92 this->drop();
93 }
94 }
95
96 const T *operator->() const noexcept { return this->deref(); }
97 const T &operator*() const noexcept { return *this->deref(); }
98 T *operator->() noexcept { return this->deref_mut(); }
99 T &operator*() noexcept { return *this->deref_mut(); }
100
101 // Important: requires that `raw` came from an into_raw call. Do not pass a
102 // pointer from `new` or any other source.
103 static RustBox from_raw(T *raw) noexcept {
104 RustBox box;
105 box.set_raw(raw);
106 return box;
107 }
108
109 T *into_raw() noexcept {
110 T *raw = this->deref_mut();
111 this->repr = 0;
112 return raw;
113 }
114
115private:
116 RustBox() noexcept {}
117 void uninit() noexcept;
118 void set_raw(T *) noexcept;
119 T *get_raw() noexcept;
120 void drop() noexcept;
121 const T *deref() const noexcept;
122 T *deref_mut() noexcept;
123 uintptr_t repr;
124};
125#endif // CXXBRIDGE00_RUST_BOX
126
127std::ostream &operator<<(std::ostream &os, const RustString &s);
128std::ostream &operator<<(std::ostream &os, const RustStr &s);
129
130} // namespace cxxbridge00
131
132namespace cxxbridge = cxxbridge00;