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