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