cxx_gen/gen/
builtin.rs

1use crate::gen::block::Block;
2use crate::gen::ifndef;
3use crate::gen::out::{Content, OutFile};
4
5#[derive(Default, PartialEq)]
6pub(crate) 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 shared_ptr: bool,
36    pub alignmax: bool,
37    pub content: Content<'a>,
38}
39
40impl<'a> Builtins<'a> {
41    pub(crate) fn new() -> Self {
42        Builtins::default()
43    }
44}
45
46pub(super) fn write(out: &mut OutFile) {
47    if out.builtin == Default::default() {
48        return;
49    }
50
51    let include = &mut out.include;
52    let builtin = &mut out.builtin;
53    let out = &mut builtin.content;
54
55    if builtin.rust_string {
56        include.array = true;
57        include.cstdint = true;
58        include.string = true;
59    }
60
61    if builtin.rust_str {
62        include.array = true;
63        include.cstdint = true;
64        include.string = true;
65        include.string_view = true;
66        builtin.friend_impl = true;
67    }
68
69    if builtin.rust_vec {
70        include.algorithm = true;
71        include.array = true;
72        include.cassert = true;
73        include.cstddef = true;
74        include.cstdint = true;
75        include.initializer_list = true;
76        include.iterator = true;
77        include.new = true;
78        include.stdexcept = true;
79        include.type_traits = true;
80        include.utility = true;
81        builtin.panic = true;
82        builtin.rust_slice = true;
83        builtin.unsafe_bitcopy_t = true;
84    }
85
86    if builtin.rust_slice {
87        include.array = true;
88        include.cassert = true;
89        include.cstddef = true;
90        include.cstdint = true;
91        include.iterator = true;
92        include.ranges = true;
93        include.stdexcept = true;
94        include.type_traits = true;
95        builtin.friend_impl = true;
96        builtin.layout = true;
97        builtin.panic = true;
98    }
99
100    if builtin.rust_box {
101        include.new = true;
102        include.type_traits = true;
103        include.utility = true;
104    }
105
106    if builtin.rust_fn {
107        include.utility = true;
108    }
109
110    if builtin.rust_error {
111        include.exception = true;
112        builtin.friend_impl = true;
113    }
114
115    if builtin.rust_isize {
116        include.basetsd = true;
117        include.sys_types = true;
118    }
119
120    if builtin.relocatable_or_array {
121        include.cstddef = true;
122        builtin.relocatable = true;
123    }
124
125    if builtin.relocatable {
126        include.type_traits = true;
127    }
128
129    if builtin.layout {
130        include.type_traits = true;
131        include.cstddef = true;
132        builtin.is_complete = true;
133    }
134
135    if builtin.shared_ptr {
136        include.memory = true;
137        include.type_traits = true;
138        builtin.is_complete = true;
139    }
140
141    if builtin.is_complete {
142        include.cstddef = true;
143        include.type_traits = true;
144    }
145
146    if builtin.unsafe_bitcopy {
147        builtin.unsafe_bitcopy_t = true;
148    }
149
150    if builtin.trycatch {
151        builtin.ptr_len = true;
152    }
153
154    out.begin_block(Block::Namespace("rust"));
155    out.begin_block(Block::InlineNamespace("cxxbridge1"));
156
157    let cxx_header = include.has_cxx_header();
158    if !cxx_header {
159        writeln!(out, "// #include \"rust/cxx.h\"");
160
161        ifndef::write(out, builtin.panic, "CXXBRIDGE1_PANIC");
162
163        if builtin.rust_string {
164            out.next_section();
165            writeln!(out, "struct unsafe_bitcopy_t;");
166        }
167
168        if builtin.friend_impl {
169            out.begin_block(Block::AnonymousNamespace);
170            writeln!(out, "template <typename T>");
171            writeln!(out, "class impl;");
172            out.end_block(Block::AnonymousNamespace);
173        }
174
175        out.next_section();
176        if builtin.rust_str && !builtin.rust_string {
177            writeln!(out, "class String;");
178        }
179        if builtin.layout && !builtin.opaque {
180            writeln!(out, "class Opaque;");
181        }
182
183        if builtin.rust_slice {
184            out.next_section();
185            writeln!(out, "template <typename T>");
186            writeln!(out, "::std::size_t size_of();");
187            writeln!(out, "template <typename T>");
188            writeln!(out, "::std::size_t align_of();");
189        }
190
191        ifndef::write(out, builtin.rust_string, "CXXBRIDGE1_RUST_STRING");
192        ifndef::write(out, builtin.rust_str, "CXXBRIDGE1_RUST_STR");
193        ifndef::write(out, builtin.rust_slice, "CXXBRIDGE1_RUST_SLICE");
194        ifndef::write(out, builtin.rust_box, "CXXBRIDGE1_RUST_BOX");
195        ifndef::write(out, builtin.unsafe_bitcopy_t, "CXXBRIDGE1_RUST_BITCOPY_T");
196        ifndef::write(out, builtin.unsafe_bitcopy, "CXXBRIDGE1_RUST_BITCOPY");
197        ifndef::write(out, builtin.rust_vec, "CXXBRIDGE1_RUST_VEC");
198        ifndef::write(out, builtin.rust_fn, "CXXBRIDGE1_RUST_FN");
199        ifndef::write(out, builtin.rust_error, "CXXBRIDGE1_RUST_ERROR");
200        ifndef::write(out, builtin.rust_isize, "CXXBRIDGE1_RUST_ISIZE");
201        ifndef::write(out, builtin.opaque, "CXXBRIDGE1_RUST_OPAQUE");
202        ifndef::write(out, builtin.is_complete, "CXXBRIDGE1_IS_COMPLETE");
203        ifndef::write(out, builtin.layout, "CXXBRIDGE1_LAYOUT");
204        ifndef::write(out, builtin.relocatable, "CXXBRIDGE1_RELOCATABLE");
205    }
206
207    if builtin.rust_str_new_unchecked {
208        out.next_section();
209        writeln!(out, "class Str::uninit {{}};");
210        writeln!(out, "inline Str::Str(uninit) noexcept {{}}");
211    }
212
213    if builtin.rust_slice_new {
214        out.next_section();
215        writeln!(out, "template <typename T>");
216        writeln!(out, "class Slice<T>::uninit {{}};");
217        writeln!(out, "template <typename T>");
218        writeln!(out, "inline Slice<T>::Slice(uninit) noexcept {{}}");
219    }
220
221    out.begin_block(Block::Namespace("repr"));
222
223    if builtin.repr_fat {
224        include.array = true;
225        include.cstdint = true;
226        out.next_section();
227        writeln!(out, "using Fat = ::std::array<::std::uintptr_t, 2>;");
228    }
229
230    if builtin.ptr_len {
231        include.cstddef = true;
232        out.next_section();
233        writeln!(out, "struct PtrLen final {{");
234        writeln!(out, "  void *ptr;");
235        writeln!(out, "  ::std::size_t len;");
236        writeln!(out, "}};");
237    }
238
239    if builtin.alignmax {
240        include.cstddef = true;
241        out.next_section();
242        writeln!(out, "#ifndef CXXBRIDGE_ALIGNMAX");
243        writeln!(out, "#define CXXBRIDGE_ALIGNMAX");
244        // This would be cleaner as the following, but GCC does not implement
245        // that correctly. <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64236>
246        //
247        //     template <::std::size_t... N>
248        //     class alignas(N...) alignmax {};
249        //
250        // Next, it could be this, but MSVC does not implement this correctly.
251        //
252        //     template <::std::size_t... N>
253        //     class alignmax { alignas(N...) union {} members; };
254        //
255        writeln!(out, "template <::std::size_t N>");
256        writeln!(out, "class alignas(N) aligned {{}};");
257        writeln!(out, "template <typename... T>");
258        writeln!(
259            out,
260            "class alignmax_t {{ alignas(T...) union {{}} members; }};",
261        );
262        writeln!(out, "template <::std::size_t... N>");
263        writeln!(out, "using alignmax = alignmax_t<aligned<N>...>;");
264        writeln!(out, "#endif // CXXBRIDGE_ALIGNMAX");
265    }
266
267    out.end_block(Block::Namespace("repr"));
268
269    out.begin_block(Block::Namespace("detail"));
270
271    if builtin.maybe_uninit {
272        include.cstddef = true;
273        include.new = true;
274        out.next_section();
275        writeln!(out, "template <typename T, typename = void *>");
276        writeln!(out, "struct operator_new {{");
277        writeln!(
278            out,
279            "  void *operator()(::std::size_t sz) {{ return ::operator new(sz); }}",
280        );
281        writeln!(out, "}};");
282        out.next_section();
283        writeln!(out, "template <typename T>");
284        writeln!(
285            out,
286            "struct operator_new<T, decltype(T::operator new(sizeof(T)))> {{",
287        );
288        writeln!(
289            out,
290            "  void *operator()(::std::size_t sz) {{ return T::operator new(sz); }}",
291        );
292        writeln!(out, "}};");
293    }
294
295    if builtin.trycatch {
296        include.string = true;
297        out.next_section();
298        writeln!(out, "class Fail final {{");
299        writeln!(out, "  ::rust::repr::PtrLen &throw$;");
300        writeln!(out, "public:");
301        writeln!(
302            out,
303            "  Fail(::rust::repr::PtrLen &throw$) noexcept : throw$(throw$) {{}}",
304        );
305        writeln!(out, "  void operator()(char const *) noexcept;");
306        writeln!(out, "  void operator()(std::string const &) noexcept;");
307        writeln!(out, "}};");
308    }
309
310    out.end_block(Block::Namespace("detail"));
311
312    if builtin.manually_drop {
313        out.next_section();
314        include.utility = true;
315        writeln!(out, "template <typename T>");
316        writeln!(out, "union ManuallyDrop {{");
317        writeln!(out, "  T value;");
318        writeln!(
319            out,
320            "  ManuallyDrop(T &&value) : value(::std::move(value)) {{}}",
321        );
322        writeln!(out, "  ~ManuallyDrop() {{}}");
323        writeln!(out, "}};");
324    }
325
326    if builtin.maybe_uninit {
327        include.cstddef = true;
328        out.next_section();
329        writeln!(out, "template <typename T>");
330        writeln!(out, "union MaybeUninit {{");
331        writeln!(out, "  T value;");
332        writeln!(
333            out,
334            "  void *operator new(::std::size_t sz) {{ return detail::operator_new<T>{{}}(sz); }}",
335        );
336        writeln!(out, "  MaybeUninit() {{}}");
337        writeln!(out, "  ~MaybeUninit() {{}}");
338        writeln!(out, "}};");
339    }
340
341    out.begin_block(Block::AnonymousNamespace);
342
343    if builtin.rust_str_new_unchecked || builtin.rust_str_repr {
344        out.next_section();
345        writeln!(out, "template <>");
346        writeln!(out, "class impl<Str> final {{");
347        writeln!(out, "public:");
348        if builtin.rust_str_new_unchecked {
349            writeln!(
350                out,
351                "  static Str new_unchecked(repr::Fat repr) noexcept {{",
352            );
353            writeln!(out, "    Str str = Str::uninit{{}};");
354            writeln!(out, "    str.repr = repr;");
355            writeln!(out, "    return str;");
356            writeln!(out, "  }}");
357        }
358        if builtin.rust_str_repr {
359            writeln!(out, "  static repr::Fat repr(Str str) noexcept {{");
360            writeln!(out, "    return str.repr;");
361            writeln!(out, "  }}");
362        }
363        writeln!(out, "}};");
364    }
365
366    if builtin.rust_slice_new || builtin.rust_slice_repr {
367        out.next_section();
368        writeln!(out, "template <typename T>");
369        writeln!(out, "class impl<Slice<T>> final {{");
370        writeln!(out, "public:");
371        if builtin.rust_slice_new {
372            writeln!(out, "  static Slice<T> slice(repr::Fat repr) noexcept {{");
373            writeln!(out, "    Slice<T> slice = typename Slice<T>::uninit{{}};");
374            writeln!(out, "    slice.repr = repr;");
375            writeln!(out, "    return slice;");
376            writeln!(out, "  }}");
377        }
378        if builtin.rust_slice_repr {
379            writeln!(out, "  static repr::Fat repr(Slice<T> slice) noexcept {{");
380            writeln!(out, "    return slice.repr;");
381            writeln!(out, "  }}");
382        }
383        writeln!(out, "}};");
384    }
385
386    if builtin.rust_error {
387        out.next_section();
388        writeln!(out, "template <>");
389        writeln!(out, "class impl<Error> final {{");
390        writeln!(out, "public:");
391        writeln!(out, "  static Error error(repr::PtrLen repr) noexcept {{");
392        writeln!(out, "    Error error;");
393        writeln!(out, "    error.msg = static_cast<char const *>(repr.ptr);");
394        writeln!(out, "    error.len = repr.len;");
395        writeln!(out, "    return error;");
396        writeln!(out, "  }}");
397        writeln!(out, "}};");
398    }
399
400    if builtin.destroy {
401        out.next_section();
402        writeln!(out, "template <typename T>");
403        writeln!(out, "void destroy(T *ptr) {{");
404        writeln!(out, "  ptr->~T();");
405        writeln!(out, "}}");
406    }
407
408    if builtin.deleter_if {
409        out.next_section();
410        writeln!(out, "template <bool> struct deleter_if {{");
411        writeln!(out, "  template <typename T> void operator()(T *) {{}}");
412        writeln!(out, "}};");
413        out.next_section();
414        writeln!(out, "template <> struct deleter_if<true> {{");
415        writeln!(
416            out,
417            "  template <typename T> void operator()(T *ptr) {{ ptr->~T(); }}",
418        );
419        writeln!(out, "}};");
420    }
421
422    if builtin.shared_ptr {
423        out.next_section();
424        writeln!(
425            out,
426            "template <typename T, bool = ::rust::detail::is_complete<T>::value>",
427        );
428        writeln!(out, "struct is_destructible : ::std::false_type {{}};");
429        writeln!(out, "template <typename T>");
430        writeln!(
431            out,
432            "struct is_destructible<T, true> : ::std::is_destructible<T> {{}};",
433        );
434        writeln!(
435            out,
436            "template <typename T, bool = ::rust::is_destructible<T>::value>",
437        );
438        writeln!(out, "struct shared_ptr_if_destructible {{");
439        writeln!(out, "  explicit shared_ptr_if_destructible(T *) {{}}");
440        writeln!(out, "}};");
441        writeln!(out, "template <typename T>");
442        writeln!(
443            out,
444            "struct shared_ptr_if_destructible<T, true> : ::std::shared_ptr<T> {{",
445        );
446        writeln!(out, "  using ::std::shared_ptr<T>::shared_ptr;");
447        writeln!(out, "}};");
448    }
449
450    if builtin.relocatable_or_array {
451        out.next_section();
452        writeln!(out, "template <typename T>");
453        writeln!(out, "struct IsRelocatableOrArray : IsRelocatable<T> {{}};");
454        writeln!(out, "template <typename T, ::std::size_t N>");
455        writeln!(
456            out,
457            "struct IsRelocatableOrArray<T[N]> : IsRelocatableOrArray<T> {{}};",
458        );
459    }
460
461    out.end_block(Block::AnonymousNamespace);
462    out.end_block(Block::InlineNamespace("cxxbridge1"));
463
464    if builtin.trycatch {
465        out.begin_block(Block::Namespace("behavior"));
466        include.exception = true;
467        include.type_traits = true;
468        include.utility = true;
469        writeln!(out, "class missing {{}};");
470        writeln!(out, "missing trycatch(...);");
471        writeln!(out);
472        writeln!(out, "template <typename Try, typename Fail>");
473        writeln!(out, "static typename ::std::enable_if<");
474        writeln!(
475            out,
476            "    ::std::is_same<decltype(trycatch(::std::declval<Try>(), ::std::declval<Fail>())),",
477        );
478        writeln!(out, "                 missing>::value>::type");
479        writeln!(out, "trycatch(Try &&func, Fail &&fail) noexcept try {{");
480        writeln!(out, "  func();");
481        writeln!(out, "}} catch (::std::exception const &e) {{");
482        writeln!(out, "  fail(e.what());");
483        writeln!(out, "}}");
484        out.end_block(Block::Namespace("behavior"));
485    }
486
487    out.end_block(Block::Namespace("rust"));
488}