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}