use crate::gen::out::{Content, OutFile};
use crate::syntax::{self, IncludeKind};
use std::ops::{Deref, DerefMut};
pub static HEADER: &str = include_str!("include/cxx.h");
#[derive(Clone, PartialEq, Debug)]
pub struct Include {
pub path: String,
pub kind: IncludeKind,
}
#[derive(Default, PartialEq)]
pub(crate) struct Includes<'a> {
pub custom: Vec<Include>,
pub algorithm: bool,
pub array: bool,
pub cassert: bool,
pub cstddef: bool,
pub cstdint: bool,
pub cstring: bool,
pub exception: bool,
pub functional: bool,
pub initializer_list: bool,
pub iterator: bool,
pub memory: bool,
pub new: bool,
pub stdexcept: bool,
pub string: bool,
pub type_traits: bool,
pub utility: bool,
pub vector: bool,
pub basetsd: bool,
pub sys_types: bool,
pub content: Content<'a>,
}
impl<'a> Includes<'a> {
pub(crate) fn new() -> Self {
Includes::default()
}
pub(crate) fn insert(&mut self, include: impl Into<Include>) {
self.custom.push(include.into());
}
pub(crate) fn has_cxx_header(&self) -> bool {
self.custom
.iter()
.any(|header| header.path == "rust/cxx.h" || header.path == "rust\\cxx.h")
}
}
pub(super) fn write(out: &mut OutFile) {
let header = out.header;
let include = &mut out.include;
let cxx_header = include.has_cxx_header();
let out = &mut include.content;
if header {
writeln!(out, "#pragma once");
}
for include in &include.custom {
match include.kind {
IncludeKind::Quoted => {
writeln!(out, "#include \"{}\"", include.path.escape_default());
}
IncludeKind::Bracketed => {
writeln!(out, "#include <{}>", include.path);
}
}
}
let Includes {
custom: _,
algorithm,
array,
cassert,
cstddef,
cstdint,
cstring,
exception,
functional,
initializer_list,
iterator,
memory,
new,
stdexcept,
string,
type_traits,
utility,
vector,
basetsd,
sys_types,
content: _,
} = *include;
if algorithm && !cxx_header {
writeln!(out, "#include <algorithm>");
}
if array && !cxx_header {
writeln!(out, "#include <array>");
}
if cassert && !cxx_header {
writeln!(out, "#include <cassert>");
}
if cstddef && !cxx_header {
writeln!(out, "#include <cstddef>");
}
if cstdint && !cxx_header {
writeln!(out, "#include <cstdint>");
}
if cstring {
writeln!(out, "#include <cstring>");
}
if exception && !cxx_header {
writeln!(out, "#include <exception>");
}
if functional {
writeln!(out, "#include <functional>");
}
if initializer_list && !cxx_header {
writeln!(out, "#include <initializer_list>");
}
if iterator && !cxx_header {
writeln!(out, "#include <iterator>");
}
if memory {
writeln!(out, "#include <memory>");
}
if new && !cxx_header {
writeln!(out, "#include <new>");
}
if stdexcept && !cxx_header {
writeln!(out, "#include <stdexcept>");
}
if string && !cxx_header {
writeln!(out, "#include <string>");
}
if type_traits && !cxx_header {
writeln!(out, "#include <type_traits>");
}
if utility && !cxx_header {
writeln!(out, "#include <utility>");
}
if vector && !cxx_header {
writeln!(out, "#include <vector>");
}
if basetsd && !cxx_header {
writeln!(out, "#if defined(_WIN32)");
writeln!(out, "#include <basetsd.h>");
}
if sys_types && !cxx_header {
if basetsd {
writeln!(out, "#else");
} else {
writeln!(out, "#if not defined(_WIN32)");
}
}
if sys_types && !cxx_header {
writeln!(out, "#include <sys/types.h>");
}
if (basetsd || sys_types) && !cxx_header {
writeln!(out, "#endif");
}
}
impl<'i, 'a> Extend<&'i Include> for Includes<'a> {
fn extend<I: IntoIterator<Item = &'i Include>>(&mut self, iter: I) {
self.custom.extend(iter.into_iter().cloned());
}
}
impl From<&syntax::Include> for Include {
fn from(include: &syntax::Include) -> Self {
Include {
path: include.path.clone(),
kind: include.kind,
}
}
}
impl<'a> Deref for Includes<'a> {
type Target = Content<'a>;
fn deref(&self) -> &Self::Target {
&self.content
}
}
impl<'a> DerefMut for Includes<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.content
}
}