cxx_gen/gen/
include.rs

1use crate::gen::out::{Content, OutFile};
2use crate::syntax::{self, IncludeKind};
3use std::ops::{Deref, DerefMut};
4
5/// The complete contents of the "rust/cxx.h" header.
6pub static HEADER: &str = include_str!("include/cxx.h");
7
8/// A header to #include.
9///
10/// The cxxbridge tool does not parse or even require the given paths to exist;
11/// they simply go into the generated C++ code as #include lines.
12#[derive(Clone, PartialEq, Debug)]
13pub struct Include {
14    /// The header's path, not including the enclosing quotation marks or angle
15    /// brackets.
16    pub path: String,
17    /// Whether to emit `#include "path"` or `#include <path>`.
18    pub kind: IncludeKind,
19}
20
21#[derive(Default, PartialEq)]
22pub(crate) struct Includes<'a> {
23    pub custom: Vec<Include>,
24    pub algorithm: bool,
25    pub array: bool,
26    pub cassert: bool,
27    pub cstddef: bool,
28    pub cstdint: bool,
29    pub cstring: bool,
30    pub exception: bool,
31    pub functional: bool,
32    pub initializer_list: bool,
33    pub iterator: bool,
34    pub memory: bool,
35    pub new: bool,
36    pub ranges: bool,
37    pub stdexcept: bool,
38    pub string: bool,
39    pub type_traits: bool,
40    pub utility: bool,
41    pub vector: bool,
42    pub basetsd: bool,
43    pub sys_types: bool,
44    pub content: Content<'a>,
45}
46
47impl<'a> Includes<'a> {
48    pub(crate) fn new() -> Self {
49        Includes::default()
50    }
51
52    pub(crate) fn insert(&mut self, include: impl Into<Include>) {
53        self.custom.push(include.into());
54    }
55
56    pub(crate) fn has_cxx_header(&self) -> bool {
57        self.custom
58            .iter()
59            .any(|header| header.path == "rust/cxx.h" || header.path == "rust\\cxx.h")
60    }
61}
62
63pub(super) fn write(out: &mut OutFile) {
64    let header = out.header;
65    let include = &mut out.include;
66    let cxx_header = include.has_cxx_header();
67    let out = &mut include.content;
68
69    if header {
70        writeln!(out, "#pragma once");
71    }
72
73    for include in &include.custom {
74        match include.kind {
75            IncludeKind::Quoted => {
76                writeln!(out, "#include \"{}\"", include.path.escape_default());
77            }
78            IncludeKind::Bracketed => {
79                writeln!(out, "#include <{}>", include.path);
80            }
81        }
82    }
83
84    let Includes {
85        custom: _,
86        algorithm,
87        array,
88        cassert,
89        cstddef,
90        cstdint,
91        cstring,
92        exception,
93        functional,
94        initializer_list,
95        iterator,
96        memory,
97        new,
98        ranges,
99        stdexcept,
100        string,
101        type_traits,
102        utility,
103        vector,
104        basetsd,
105        sys_types,
106        content: _,
107    } = *include;
108
109    if algorithm && !cxx_header {
110        writeln!(out, "#include <algorithm>");
111    }
112    if array && !cxx_header {
113        writeln!(out, "#include <array>");
114    }
115    if cassert && !cxx_header {
116        writeln!(out, "#include <cassert>");
117    }
118    if cstddef && !cxx_header {
119        writeln!(out, "#include <cstddef>");
120    }
121    if cstdint && !cxx_header {
122        writeln!(out, "#include <cstdint>");
123    }
124    if cstring {
125        writeln!(out, "#include <cstring>");
126    }
127    if exception && !cxx_header {
128        writeln!(out, "#include <exception>");
129    }
130    if functional {
131        writeln!(out, "#include <functional>");
132    }
133    if initializer_list && !cxx_header {
134        writeln!(out, "#include <initializer_list>");
135    }
136    if iterator && !cxx_header {
137        writeln!(out, "#include <iterator>");
138    }
139    if memory {
140        writeln!(out, "#include <memory>");
141    }
142    if new && !cxx_header {
143        writeln!(out, "#include <new>");
144    }
145    if stdexcept && !cxx_header {
146        writeln!(out, "#include <stdexcept>");
147    }
148    if string && !cxx_header {
149        writeln!(out, "#include <string>");
150    }
151    if type_traits && !cxx_header {
152        writeln!(out, "#include <type_traits>");
153    }
154    if utility && !cxx_header {
155        writeln!(out, "#include <utility>");
156    }
157    if vector && !cxx_header {
158        writeln!(out, "#include <vector>");
159    }
160    if ranges && !cxx_header {
161        writeln!(out, "#if __cplusplus >= 202002L");
162        writeln!(out, "#include <ranges>");
163        writeln!(out, "#endif");
164    }
165    if basetsd && !cxx_header {
166        writeln!(out, "#if defined(_WIN32)");
167        writeln!(out, "#include <basetsd.h>");
168    }
169    if sys_types && !cxx_header {
170        if basetsd {
171            writeln!(out, "#else");
172        } else {
173            writeln!(out, "#if not defined(_WIN32)");
174        }
175    }
176    if sys_types && !cxx_header {
177        writeln!(out, "#include <sys/types.h>");
178    }
179    if (basetsd || sys_types) && !cxx_header {
180        writeln!(out, "#endif");
181    }
182}
183
184impl<'i, 'a> Extend<&'i Include> for Includes<'a> {
185    fn extend<I: IntoIterator<Item = &'i Include>>(&mut self, iter: I) {
186        self.custom.extend(iter.into_iter().cloned());
187    }
188}
189
190impl From<&syntax::Include> for Include {
191    fn from(include: &syntax::Include) -> Self {
192        Include {
193            path: include.path.clone(),
194            kind: include.kind,
195        }
196    }
197}
198
199impl<'a> Deref for Includes<'a> {
200    type Target = Content<'a>;
201
202    fn deref(&self) -> &Self::Target {
203        &self.content
204    }
205}
206
207impl<'a> DerefMut for Includes<'a> {
208    fn deref_mut(&mut self) -> &mut Self::Target {
209        &mut self.content
210    }
211}