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