xref: /third_party/rust/crates/cxx/gen/src/builtin.rs (revision 33d722a9)
1use crate::gen::block::Block;
2use crate::gen::ifndef;
3use crate::gen::out::{Content, OutFile};
4
5#[derive(Default, PartialEq)]
6pub struct Builtins<'a> {
7    pub panic: bool,
8    pub rust_string: bool,
9    pub rust_str: bool,
10    pub rust_slice: bool,
11    pub rust_box: bool,
12    pub rust_vec: bool,
13    pub rust_fn: bool,
14    pub rust_isize: bool,
15    pub opaque: bool,
16    pub layout: bool,
17    pub unsafe_bitcopy: bool,
18    pub unsafe_bitcopy_t: bool,
19    pub rust_error: bool,
20    pub manually_drop: bool,
21    pub maybe_uninit: bool,
22    pub trycatch: bool,
23    pub ptr_len: bool,
24    pub repr_fat: bool,
25    pub rust_str_new_unchecked: bool,
26    pub rust_str_repr: bool,
27    pub rust_slice_new: bool,
28    pub rust_slice_repr: bool,
29    pub relocatable: bool,
30    pub relocatable_or_array: bool,
31    pub friend_impl: bool,
32    pub is_complete: bool,
33    pub destroy: bool,
34    pub deleter_if: bool,
35    pub content: Content<'a>,
36}
37
38impl<'a> Builtins<'a> {
39    pub fn new() -> Self {
40        Builtins::default()
41    }
42}
43
44pub(super) fn write(out: &mut OutFile) {
45    if out.builtin == Default::default() {
46        return;
47    }
48
49    let include = &mut out.include;
50    let builtin = &mut out.builtin;
51    let out = &mut builtin.content;
52
53    if builtin.rust_string {
54        include.array = true;
55        include.cstdint = true;
56        include.string = true;
57    }
58
59    if builtin.rust_str {
60        include.array = true;
61        include.cstdint = true;
62        include.string = true;
63        builtin.friend_impl = true;
64    }
65
66    if builtin.rust_vec {
67        include.algorithm = true;
68        include.array = true;
69        include.cassert = true;
70        include.cstddef = true;
71        include.cstdint = true;
72        include.initializer_list = true;
73        include.iterator = true;
74        include.new = true;
75        include.stdexcept = true;
76        include.type_traits = true;
77        include.utility = true;
78        builtin.panic = true;
79        builtin.rust_slice = true;
80        builtin.unsafe_bitcopy_t = true;
81    }
82
83    if builtin.rust_slice {
84        include.array = true;
85        include.cassert = true;
86        include.cstddef = true;
87        include.cstdint = true;
88        include.iterator = true;
89        include.stdexcept = true;
90        include.type_traits = true;
91        builtin.friend_impl = true;
92        builtin.layout = true;
93        builtin.panic = true;
94    }
95
96    if builtin.rust_box {
97        include.new = true;
98        include.type_traits = true;
99        include.utility = true;
100    }
101
102    if builtin.rust_fn {
103        include.utility = true;
104    }
105
106    if builtin.rust_error {
107        include.exception = true;
108        builtin.friend_impl = true;
109    }
110
111    if builtin.rust_isize {
112        include.basetsd = true;
113        include.sys_types = true;
114    }
115
116    if builtin.relocatable_or_array {
117        include.cstddef = true;
118        builtin.relocatable = true;
119    }
120
121    if builtin.relocatable {
122        include.type_traits = true;
123    }
124
125    if builtin.layout {
126        include.type_traits = true;
127        include.cstddef = true;
128        builtin.is_complete = true;
129    }
130
131    if builtin.is_complete {
132        include.cstddef = true;
133        include.type_traits = true;
134    }
135
136    if builtin.unsafe_bitcopy {
137        builtin.unsafe_bitcopy_t = true;
138    }
139
140    if builtin.trycatch {
141        builtin.ptr_len = true;
142    }
143
144    out.begin_block(Block::Namespace("rust"));
145    out.begin_block(Block::InlineNamespace("cxxbridge1"));
146
147    let cxx_header = include.has_cxx_header();
148    if !cxx_header {
149        writeln!(out, "// #include \"rust/cxx.h\"");
150
151        ifndef::write(out, builtin.panic, "CXXBRIDGE1_PANIC");
152
153        if builtin.rust_string {
154            out.next_section();
155            writeln!(out, "struct unsafe_bitcopy_t;");
156        }
157
158        if builtin.friend_impl {
159            out.begin_block(Block::AnonymousNamespace);
160            writeln!(out, "template <typename T>");
161            writeln!(out, "class impl;");
162            out.end_block(Block::AnonymousNamespace);
163        }
164
165        out.next_section();
166        if builtin.rust_str && !builtin.rust_string {
167            writeln!(out, "class String;");
168        }
169        if builtin.layout && !builtin.opaque {
170            writeln!(out, "class Opaque;");
171        }
172
173        if builtin.rust_slice {
174            out.next_section();
175            writeln!(out, "template <typename T>");
176            writeln!(out, "::std::size_t size_of();");
177            writeln!(out, "template <typename T>");
178            writeln!(out, "::std::size_t align_of();");
179        }
180
181        ifndef::write(out, builtin.rust_string, "CXXBRIDGE1_RUST_STRING");
182        ifndef::write(out, builtin.rust_str, "CXXBRIDGE1_RUST_STR");
183        ifndef::write(out, builtin.rust_slice, "CXXBRIDGE1_RUST_SLICE");
184        ifndef::write(out, builtin.rust_box, "CXXBRIDGE1_RUST_BOX");
185        ifndef::write(out, builtin.unsafe_bitcopy_t, "CXXBRIDGE1_RUST_BITCOPY_T");
186        ifndef::write(out, builtin.unsafe_bitcopy, "CXXBRIDGE1_RUST_BITCOPY");
187        ifndef::write(out, builtin.rust_vec, "CXXBRIDGE1_RUST_VEC");
188        ifndef::write(out, builtin.rust_fn, "CXXBRIDGE1_RUST_FN");
189        ifndef::write(out, builtin.rust_error, "CXXBRIDGE1_RUST_ERROR");
190        ifndef::write(out, builtin.rust_isize, "CXXBRIDGE1_RUST_ISIZE");
191        ifndef::write(out, builtin.opaque, "CXXBRIDGE1_RUST_OPAQUE");
192        ifndef::write(out, builtin.is_complete, "CXXBRIDGE1_IS_COMPLETE");
193        ifndef::write(out, builtin.layout, "CXXBRIDGE1_LAYOUT");
194        ifndef::write(out, builtin.relocatable, "CXXBRIDGE1_RELOCATABLE");
195    }
196
197    if builtin.rust_str_new_unchecked {
198        out.next_section();
199        writeln!(out, "class Str::uninit {{}};");
200        writeln!(out, "inline Str::Str(uninit) noexcept {{}}");
201    }
202
203    if builtin.rust_slice_new {
204        out.next_section();
205        writeln!(out, "template <typename T>");
206        writeln!(out, "class Slice<T>::uninit {{}};");
207        writeln!(out, "template <typename T>");
208        writeln!(out, "inline Slice<T>::Slice(uninit) noexcept {{}}");
209    }
210
211    out.begin_block(Block::Namespace("repr"));
212
213    if builtin.repr_fat {
214        include.array = true;
215        include.cstdint = true;
216        out.next_section();
217        writeln!(out, "using Fat = ::std::array<::std::uintptr_t, 2>;");
218    }
219
220    if builtin.ptr_len {
221        include.cstddef = true;
222        out.next_section();
223        writeln!(out, "struct PtrLen final {{");
224        writeln!(out, "  void *ptr;");
225        writeln!(out, "  ::std::size_t len;");
226        writeln!(out, "}};");
227    }
228
229    out.end_block(Block::Namespace("repr"));
230
231    out.begin_block(Block::Namespace("detail"));
232
233    if builtin.maybe_uninit {
234        include.cstddef = true;
235        include.new = true;
236        out.next_section();
237        writeln!(out, "template <typename T, typename = void *>");
238        writeln!(out, "struct operator_new {{");
239        writeln!(
240            out,
241            "  void *operator()(::std::size_t sz) {{ return ::operator new(sz); }}",
242        );
243        writeln!(out, "}};");
244        out.next_section();
245        writeln!(out, "template <typename T>");
246        writeln!(
247            out,
248            "struct operator_new<T, decltype(T::operator new(sizeof(T)))> {{",
249        );
250        writeln!(
251            out,
252            "  void *operator()(::std::size_t sz) {{ return T::operator new(sz); }}",
253        );
254        writeln!(out, "}};");
255    }
256
257    if builtin.trycatch {
258        include.string = true;
259        out.next_section();
260        writeln!(out, "class Fail final {{");
261        writeln!(out, "  ::rust::repr::PtrLen &throw$;");
262        writeln!(out, "public:");
263        writeln!(
264            out,
265            "  Fail(::rust::repr::PtrLen &throw$) noexcept : throw$(throw$) {{}}",
266        );
267        writeln!(out, "  void operator()(char const *) noexcept;");
268        writeln!(out, "  void operator()(std::string const &) noexcept;");
269        writeln!(out, "}};");
270    }
271
272    out.end_block(Block::Namespace("detail"));
273
274    if builtin.manually_drop {
275        out.next_section();
276        include.utility = true;
277        writeln!(out, "template <typename T>");
278        writeln!(out, "union ManuallyDrop {{");
279        writeln!(out, "  T value;");
280        writeln!(
281            out,
282            "  ManuallyDrop(T &&value) : value(::std::move(value)) {{}}",
283        );
284        writeln!(out, "  ~ManuallyDrop() {{}}");
285        writeln!(out, "}};");
286    }
287
288    if builtin.maybe_uninit {
289        include.cstddef = true;
290        out.next_section();
291        writeln!(out, "template <typename T>");
292        writeln!(out, "union MaybeUninit {{");
293        writeln!(out, "  T value;");
294        writeln!(
295            out,
296            "  void *operator new(::std::size_t sz) {{ return detail::operator_new<T>{{}}(sz); }}",
297        );
298        writeln!(out, "  MaybeUninit() {{}}");
299        writeln!(out, "  ~MaybeUninit() {{}}");
300        writeln!(out, "}};");
301    }
302
303    out.begin_block(Block::AnonymousNamespace);
304
305    if builtin.rust_str_new_unchecked || builtin.rust_str_repr {
306        out.next_section();
307        writeln!(out, "template <>");
308        writeln!(out, "class impl<Str> final {{");
309        writeln!(out, "public:");
310        if builtin.rust_str_new_unchecked {
311            writeln!(
312                out,
313                "  static Str new_unchecked(repr::Fat repr) noexcept {{",
314            );
315            writeln!(out, "    Str str = Str::uninit{{}};");
316            writeln!(out, "    str.repr = repr;");
317            writeln!(out, "    return str;");
318            writeln!(out, "  }}");
319        }
320        if builtin.rust_str_repr {
321            writeln!(out, "  static repr::Fat repr(Str str) noexcept {{");
322            writeln!(out, "    return str.repr;");
323            writeln!(out, "  }}");
324        }
325        writeln!(out, "}};");
326    }
327
328    if builtin.rust_slice_new || builtin.rust_slice_repr {
329        out.next_section();
330        writeln!(out, "template <typename T>");
331        writeln!(out, "class impl<Slice<T>> final {{");
332        writeln!(out, "public:");
333        if builtin.rust_slice_new {
334            writeln!(out, "  static Slice<T> slice(repr::Fat repr) noexcept {{");
335            writeln!(out, "    Slice<T> slice = typename Slice<T>::uninit{{}};");
336            writeln!(out, "    slice.repr = repr;");
337            writeln!(out, "    return slice;");
338            writeln!(out, "  }}");
339        }
340        if builtin.rust_slice_repr {
341            writeln!(out, "  static repr::Fat repr(Slice<T> slice) noexcept {{");
342            writeln!(out, "    return slice.repr;");
343            writeln!(out, "  }}");
344        }
345        writeln!(out, "}};");
346    }
347
348    if builtin.rust_error {
349        out.next_section();
350        writeln!(out, "template <>");
351        writeln!(out, "class impl<Error> final {{");
352        writeln!(out, "public:");
353        writeln!(out, "  static Error error(repr::PtrLen repr) noexcept {{");
354        writeln!(out, "    Error error;");
355        writeln!(out, "    error.msg = static_cast<char const *>(repr.ptr);");
356        writeln!(out, "    error.len = repr.len;");
357        writeln!(out, "    return error;");
358        writeln!(out, "  }}");
359        writeln!(out, "}};");
360    }
361
362    if builtin.destroy {
363        out.next_section();
364        writeln!(out, "template <typename T>");
365        writeln!(out, "void destroy(T *ptr) {{");
366        writeln!(out, "  ptr->~T();");
367        writeln!(out, "}}");
368    }
369
370    if builtin.deleter_if {
371        out.next_section();
372        writeln!(out, "template <bool> struct deleter_if {{");
373        writeln!(out, "  template <typename T> void operator()(T *) {{}}");
374        writeln!(out, "}};");
375        out.next_section();
376        writeln!(out, "template <> struct deleter_if<true> {{");
377        writeln!(
378            out,
379            "  template <typename T> void operator()(T *ptr) {{ ptr->~T(); }}",
380        );
381        writeln!(out, "}};");
382    }
383
384    if builtin.relocatable_or_array {
385        out.next_section();
386        writeln!(out, "template <typename T>");
387        writeln!(out, "struct IsRelocatableOrArray : IsRelocatable<T> {{}};");
388        writeln!(out, "template <typename T, ::std::size_t N>");
389        writeln!(
390            out,
391            "struct IsRelocatableOrArray<T[N]> : IsRelocatableOrArray<T> {{}};",
392        );
393    }
394
395    out.end_block(Block::AnonymousNamespace);
396    out.end_block(Block::InlineNamespace("cxxbridge1"));
397
398    if builtin.trycatch {
399        out.begin_block(Block::Namespace("behavior"));
400        include.exception = true;
401        include.type_traits = true;
402        include.utility = true;
403        writeln!(out, "class missing {{}};");
404        writeln!(out, "missing trycatch(...);");
405        writeln!(out);
406        writeln!(out, "template <typename Try, typename Fail>");
407        writeln!(out, "static typename ::std::enable_if<");
408        writeln!(
409            out,
410            "    ::std::is_same<decltype(trycatch(::std::declval<Try>(), ::std::declval<Fail>())),",
411        );
412        writeln!(out, "                 missing>::value>::type");
413        writeln!(out, "trycatch(Try &&func, Fail &&fail) noexcept try {{");
414        writeln!(out, "  func();");
415        writeln!(out, "}} catch (::std::exception const &e) {{");
416        writeln!(out, "  fail(e.what());");
417        writeln!(out, "}}");
418        out.end_block(Block::Namespace("behavior"));
419    }
420
421    out.end_block(Block::Namespace("rust"));
422}
423