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