1use crate::gen::block::Block;
2use crate::gen::ifndef;
3use crate::gen::include::Includes;
4use crate::gen::out::{Content, OutFile};
5use crate::gen::pragma::Pragma;
6
7#[derive(Default, PartialEq)]
8pub(crate) struct Builtins<'a> {
9 pub panic: bool,
10 pub rust_string: bool,
11 pub rust_str: bool,
12 pub rust_slice: bool,
13 pub rust_box: bool,
14 pub rust_vec: bool,
15 pub rust_fn: bool,
16 pub rust_isize: bool,
17 pub opaque: bool,
18 pub layout: bool,
19 pub unsafe_bitcopy: bool,
20 pub unsafe_bitcopy_t: bool,
21 pub rust_error: bool,
22 pub manually_drop: bool,
23 pub maybe_uninit: bool,
24 pub trycatch: bool,
25 pub ptr_len: bool,
26 pub repr_fat: bool,
27 pub rust_str_new_unchecked: bool,
28 pub rust_str_repr: bool,
29 pub rust_slice_new: bool,
30 pub rust_slice_repr: bool,
31 pub relocatable: bool,
32 pub relocatable_or_array: bool,
33 pub friend_impl: bool,
34 pub is_complete: bool,
35 pub destroy: bool,
36 pub deleter_if: bool,
37 pub shared_ptr: bool,
38 pub alignmax: bool,
39 pub content: Content<'a>,
40}
41
42impl<'a> Builtins<'a> {
43 pub(crate) fn new() -> Self {
44 Builtins::default()
45 }
46}
47
48pub(super) fn write(out: &mut OutFile) {
49 if out.builtin == Default::default() {
50 return;
51 }
52
53 let include = &mut out.include;
54 let pragma = &mut out.pragma;
55 let builtin = &mut out.builtin;
56 let out = &mut builtin.content;
57
58 if builtin.rust_string {
59 include.array = true;
60 include.cstdint = true;
61 include.string = true;
62 }
63
64 if builtin.rust_str {
65 include.array = true;
66 include.cstdint = true;
67 include.string = true;
68 include.string_view = true;
69 builtin.friend_impl = true;
70 }
71
72 if builtin.rust_vec {
73 include.algorithm = true;
74 include.array = true;
75 include.cassert = true;
76 include.cstddef = true;
77 include.cstdint = true;
78 include.initializer_list = true;
79 include.iterator = true;
80 include.new = true;
81 include.stdexcept = true;
82 include.type_traits = true;
83 include.utility = true;
84 builtin.panic = true;
85 builtin.rust_slice = true;
86 builtin.unsafe_bitcopy_t = true;
87 }
88
89 if builtin.rust_slice {
90 include.array = true;
91 include.cassert = true;
92 include.cstddef = true;
93 include.cstdint = true;
94 include.iterator = true;
95 include.ranges = true;
96 include.stdexcept = true;
97 include.type_traits = true;
98 builtin.friend_impl = true;
99 builtin.layout = true;
100 builtin.panic = true;
101 }
102
103 if builtin.rust_box {
104 include.new = true;
105 include.type_traits = true;
106 include.utility = true;
107 }
108
109 if builtin.rust_fn {
110 include.utility = true;
111 }
112
113 if builtin.rust_error {
114 include.exception = true;
115 builtin.friend_impl = true;
116 }
117
118 if builtin.rust_isize {
119 include.basetsd = true;
120 include.sys_types = true;
121 }
122
123 if builtin.relocatable_or_array {
124 include.cstddef = true;
125 builtin.relocatable = true;
126 }
127
128 if builtin.relocatable {
129 include.type_traits = true;
130 }
131
132 if builtin.layout {
133 include.type_traits = true;
134 include.cstddef = true;
135 builtin.is_complete = true;
136 }
137
138 if builtin.shared_ptr {
139 include.memory = true;
140 include.type_traits = true;
141 builtin.is_complete = true;
142 }
143
144 if builtin.is_complete {
145 include.cstddef = true;
146 include.type_traits = true;
147 }
148
149 if builtin.unsafe_bitcopy {
150 builtin.unsafe_bitcopy_t = true;
151 }
152
153 if builtin.trycatch {
154 builtin.ptr_len = true;
155 }
156
157 out.begin_block(Block::Namespace("rust"));
158 out.begin_block(Block::InlineNamespace("cxxbridge1"));
159
160 let cxx_header = include.has_cxx_header();
161 if !cxx_header {
162 writeln!(out, "// #include \"rust/cxx.h\"");
163
164 ifndef::write(out, builtin.panic, "CXXBRIDGE1_PANIC");
165
166 if builtin.rust_string {
167 out.next_section();
168 writeln!(out, "struct unsafe_bitcopy_t;");
169 }
170
171 if builtin.friend_impl {
172 out.begin_block(Block::AnonymousNamespace);
173 writeln!(out, "template <typename T>");
174 writeln!(out, "class impl;");
175 out.end_block(Block::AnonymousNamespace);
176 }
177
178 out.next_section();
179 if builtin.rust_str && !builtin.rust_string {
180 writeln!(out, "class String;");
181 }
182 if builtin.layout && !builtin.opaque {
183 writeln!(out, "class Opaque;");
184 }
185
186 if builtin.rust_slice {
187 out.next_section();
188 writeln!(out, "template <typename T>");
189 writeln!(out, "::std::size_t size_of();");
190 writeln!(out, "template <typename T>");
191 writeln!(out, "::std::size_t align_of();");
192 }
193
194 ifndef::write(out, builtin.rust_string, "CXXBRIDGE1_RUST_STRING");
195 ifndef::write(out, builtin.rust_str, "CXXBRIDGE1_RUST_STR");
196 ifndef::write(out, builtin.rust_slice, "CXXBRIDGE1_RUST_SLICE");
197 ifndef::write(out, builtin.rust_box, "CXXBRIDGE1_RUST_BOX");
198 ifndef::write(out, builtin.unsafe_bitcopy_t, "CXXBRIDGE1_RUST_BITCOPY_T");
199 ifndef::write(out, builtin.unsafe_bitcopy, "CXXBRIDGE1_RUST_BITCOPY");
200 ifndef::write(out, builtin.rust_vec, "CXXBRIDGE1_RUST_VEC");
201 ifndef::write(out, builtin.rust_fn, "CXXBRIDGE1_RUST_FN");
202 ifndef::write(out, builtin.rust_error, "CXXBRIDGE1_RUST_ERROR");
203 ifndef::write(out, builtin.rust_isize, "CXXBRIDGE1_RUST_ISIZE");
204 ifndef::write(out, builtin.opaque, "CXXBRIDGE1_RUST_OPAQUE");
205 ifndef::write(out, builtin.is_complete, "CXXBRIDGE1_IS_COMPLETE");
206 ifndef::write(out, builtin.layout, "CXXBRIDGE1_LAYOUT");
207 ifndef::write(out, builtin.relocatable, "CXXBRIDGE1_RELOCATABLE");
208 }
209
210 out.end_block(Block::InlineNamespace("cxxbridge1"));
211 out.end_block(Block::Namespace("rust"));
212
213 macro_rules! write_builtin {
214 ($path:literal) => {
215 write_builtin(out, include, pragma, include_str!($path));
216 };
217 }
218
219 if builtin.rust_str_new_unchecked {
222 write_builtin!("builtin/rust_str_uninit.h");
223 }
224
225 if builtin.rust_slice_new {
226 write_builtin!("builtin/rust_slice_uninit.h");
227 }
228
229 if builtin.repr_fat {
232 write_builtin!("builtin/repr_fat.h");
233 }
234
235 if builtin.ptr_len {
236 write_builtin!("builtin/ptr_len.h");
237 }
238
239 if builtin.alignmax {
240 write_builtin!("builtin/alignmax.h");
241 }
242
243 if builtin.maybe_uninit {
246 write_builtin!("builtin/maybe_uninit_detail.h");
247 }
248
249 if builtin.trycatch {
250 write_builtin!("builtin/trycatch_detail.h");
251 }
252
253 if builtin.manually_drop {
256 write_builtin!("builtin/manually_drop.h");
257 }
258
259 if builtin.maybe_uninit {
260 write_builtin!("builtin/maybe_uninit.h");
261 }
262
263 out.begin_block(Block::Namespace("rust"));
264 out.begin_block(Block::InlineNamespace("cxxbridge1"));
265 out.begin_block(Block::AnonymousNamespace);
266
267 if builtin.rust_str_new_unchecked || builtin.rust_str_repr {
268 out.next_section();
269 writeln!(out, "template <>");
270 writeln!(out, "class impl<Str> final {{");
271 writeln!(out, "public:");
272 if builtin.rust_str_new_unchecked {
273 writeln!(
274 out,
275 " static Str new_unchecked(repr::Fat repr) noexcept {{",
276 );
277 writeln!(out, " Str str = Str::uninit{{}};");
278 writeln!(out, " str.repr = repr;");
279 writeln!(out, " return str;");
280 writeln!(out, " }}");
281 }
282 if builtin.rust_str_repr {
283 writeln!(out, " static repr::Fat repr(Str str) noexcept {{");
284 writeln!(out, " return str.repr;");
285 writeln!(out, " }}");
286 }
287 writeln!(out, "}};");
288 }
289
290 if builtin.rust_slice_new || builtin.rust_slice_repr {
291 out.next_section();
292 writeln!(out, "template <typename T>");
293 writeln!(out, "class impl<Slice<T>> final {{");
294 writeln!(out, "public:");
295 if builtin.rust_slice_new {
296 writeln!(out, " static Slice<T> slice(repr::Fat repr) noexcept {{");
297 writeln!(out, " Slice<T> slice = typename Slice<T>::uninit{{}};");
298 writeln!(out, " slice.repr = repr;");
299 writeln!(out, " return slice;");
300 writeln!(out, " }}");
301 }
302 if builtin.rust_slice_repr {
303 writeln!(out, " static repr::Fat repr(Slice<T> slice) noexcept {{");
304 writeln!(out, " return slice.repr;");
305 writeln!(out, " }}");
306 }
307 writeln!(out, "}};");
308 }
309
310 out.end_block(Block::AnonymousNamespace);
311 out.end_block(Block::InlineNamespace("cxxbridge1"));
312 out.end_block(Block::Namespace("rust"));
313
314 if builtin.rust_error {
317 write_builtin!("builtin/rust_error.h");
318 }
319
320 if builtin.destroy {
321 write_builtin!("builtin/destroy.h");
322 }
323
324 if builtin.deleter_if {
325 write_builtin!("builtin/deleter_if.h");
326 }
327
328 if builtin.shared_ptr {
329 write_builtin!("builtin/shared_ptr.h");
330 }
331
332 if builtin.relocatable_or_array {
333 write_builtin!("builtin/relocatable_or_array.h");
334 }
335
336 if builtin.trycatch {
339 write_builtin!("builtin/trycatch.h");
340 }
341}
342
343fn write_builtin<'a>(
344 out: &mut Content<'a>,
345 include: &mut Includes,
346 pragma: &mut Pragma<'a>,
347 src: &'a str,
348) {
349 let mut namespace = Vec::new();
350 let mut ready = false;
351
352 for line in src.lines() {
353 if line == "#pragma once" || line.starts_with("#include \".") {
354 continue;
355 } else if let Some(rest) = line.strip_prefix("#include <") {
356 let Includes {
357 custom: _,
358 algorithm,
359 array,
360 cassert,
361 cstddef,
362 cstdint,
363 cstring,
364 exception,
365 functional,
366 initializer_list,
367 iterator,
368 memory,
369 new,
370 ranges,
371 stdexcept,
372 string,
373 string_view,
374 type_traits,
375 utility,
376 vector,
377 basetsd: _,
378 sys_types: _,
379 content: _,
380 } = include;
381 match rest.strip_suffix(">").unwrap() {
382 "algorithm" => *algorithm = true,
383 "array" => *array = true,
384 "cassert" => *cassert = true,
385 "cstddef" => *cstddef = true,
386 "cstdint" => *cstdint = true,
387 "cstring" => *cstring = true,
388 "exception" => *exception = true,
389 "functional" => *functional = true,
390 "initializer_list" => *initializer_list = true,
391 "iterator" => *iterator = true,
392 "memory" => *memory = true,
393 "new" => *new = true,
394 "ranges" => *ranges = true,
395 "stdexcept" => *stdexcept = true,
396 "string" => *string = true,
397 "string_view" => *string_view = true,
398 "type_traits" => *type_traits = true,
399 "utility" => *utility = true,
400 "vector" => *vector = true,
401 _ => unimplemented!("{}", line),
402 }
403 } else if let Some(rest) = line.strip_prefix("#pragma GCC diagnostic ignored \"") {
404 let diagnostic = rest.strip_suffix('"').unwrap();
405 pragma.gnu_diagnostic_ignore.insert(diagnostic);
406 ready = false;
407 } else if let Some(rest) = line.strip_prefix("#pragma clang diagnostic ignored \"") {
408 let diagnostic = rest.strip_suffix('"').unwrap();
409 pragma.clang_diagnostic_ignore.insert(diagnostic);
410 ready = false;
411 } else if line == "namespace {" {
412 namespace.push(Block::AnonymousNamespace);
413 out.begin_block(Block::AnonymousNamespace);
414 } else if let Some(rest) = line.strip_prefix("namespace ") {
415 let name = rest.strip_suffix(" {").unwrap();
416 namespace.push(Block::Namespace(name));
417 out.begin_block(Block::Namespace(name));
418 } else if let Some(rest) = line.strip_prefix("inline namespace ") {
419 let name = rest.strip_suffix(" {").unwrap();
420 namespace.push(Block::InlineNamespace(name));
421 out.begin_block(Block::InlineNamespace(name));
422 } else if line.starts_with("} // namespace") {
423 out.end_block(namespace.pop().unwrap());
424 } else if line.is_empty() && !ready {
425 out.next_section();
426 ready = true;
427 } else if !line.trim_start_matches(' ').starts_with("//") {
428 assert!(ready);
429 writeln!(out, "{}", line);
430 }
431 }
432
433 assert!(namespace.is_empty());
434 assert!(ready);
435}
436
437#[cfg(test)]
438mod tests {
439 use crate::gen::include::Includes;
440 use crate::gen::out::Content;
441 use crate::gen::pragma::Pragma;
442 use std::fs;
443
444 #[test]
445 fn test_write_builtin() {
446 let mut builtin_src = Vec::new();
447
448 for entry in fs::read_dir("src/gen/builtin").unwrap() {
449 let path = entry.unwrap().path();
450 let src = fs::read_to_string(path).unwrap();
451 builtin_src.push(src);
452 }
453
454 assert_ne!(builtin_src.len(), 0);
455 builtin_src.sort();
456
457 let mut content = Content::new();
458 let mut include = Includes::new();
459 let mut pragma = Pragma::new();
460 for src in &builtin_src {
461 super::write_builtin(&mut content, &mut include, &mut pragma, src);
462 }
463 }
464}