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