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 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}