1
use core::fmt;
2
use std::{borrow::Cow, path::Path};
3

            
4
use crate::domain::commands::arguments::Argument;
5
use serde::{Deserialize, Serialize};
6

            
7
use crate::domain::target::ExtraArgs;
8

            
9
4
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
10
pub struct CompilerModel<'a> {
11
1
    pub cpp_compiler: CppCompiler,
12
1
    pub driver_path: Cow<'a, str>,
13
1
    pub cpp_standard: LanguageLevel,
14
1
    pub std_lib: Option<StdLib>,
15
1
    pub std_lib_installed_dir: Option<Cow<'a, Path>>,
16
1
    pub extra_args: Vec<Argument<'a>>,
17
}
18

            
19
impl<'a> CompilerModel<'a> {
20
2
    pub fn language_level(&self) -> Cow<'static, str> {
21
4
        match self.cpp_compiler {
22
2
            CppCompiler::CLANG | CppCompiler::GCC => format!("-std=c++{}", self.cpp_standard),
23
            CppCompiler::MSVC => format!("/std:c++{}", self.cpp_standard),
24
        }
25
        .into()
26
2
    }
27

            
28
2
    pub fn language_level_arg(&self) -> Argument {
29
2
        Argument::from(self.language_level())
30
2
    }
31

            
32
1
    pub fn stdlib_arg(&self) -> Option<Argument> {
33
1
        self.std_lib
34
            .as_ref()
35
1
            .map(|lib| Argument::from(format!("-stdlib={lib}")))
36
1
    }
37
}
38

            
39
impl<'a> ExtraArgs<'a> for CompilerModel<'a> {
40
    fn extra_args(&'a self) -> &'a [Argument] {
41
        &self.extra_args
42
    }
43
}
44

            
45
17
#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize, Default)]
46
pub enum CppCompiler {
47
    #[default]
48
    CLANG,
49
    MSVC,
50
    GCC,
51
}
52

            
53
impl fmt::Display for CppCompiler {
54
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55
        write!(f, "{}", self.as_ref())
56
    }
57
}
58

            
59
impl AsRef<str> for CppCompiler {
60
37
    fn as_ref(&self) -> &str {
61
37
        match *self {
62
21
            CppCompiler::CLANG => "clang",
63
            CppCompiler::MSVC => "msvc",
64
16
            CppCompiler::GCC => "gcc",
65
        }
66
37
    }
67
}
68

            
69
impl CppCompiler {
70
    /// Returns an &str representing the compiler driver that will be called
71
    /// in the command line to generate the build events
72
18
    pub fn get_driver<'a>(&self, compiler_model: &'a CompilerModel) -> Cow<'a, str> {
73
36
        if !compiler_model.driver_path.is_empty() {
74
            Cow::Borrowed(&compiler_model.driver_path)
75
        } else {
76
36
            Cow::Borrowed(match *self {
77
9
                CppCompiler::CLANG => "clang++",
78
                CppCompiler::MSVC => "cl",
79
9
                CppCompiler::GCC => "g++",
80
            })
81
        }
82
18
    }
83

            
84
    pub fn default_module_extension<'a>(&self) -> Cow<'a, str> {
85
        Cow::Borrowed(match *self {
86
            CppCompiler::CLANG => "cppm",
87
            CppCompiler::MSVC => "ixx",
88
            CppCompiler::GCC => "cc",
89
        })
90
    }
91
2
    pub fn get_default_module_extension<'a>(&self) -> Cow<'a, str> {
92
4
        Cow::Borrowed(match *self {
93
1
            CppCompiler::CLANG => "cppm",
94
            CppCompiler::MSVC => "ixx",
95
1
            CppCompiler::GCC => "cc",
96
        })
97
2
    }
98

            
99
    pub fn typical_bmi_extension(&self) -> Cow<'_, str> {
100
        Cow::Borrowed(match *self {
101
            CppCompiler::CLANG => "pcm",
102
            CppCompiler::MSVC => "ifc",
103
            CppCompiler::GCC => "o",
104
        })
105
    }
106

            
107
7
    pub fn get_typical_bmi_extension(&self) -> &str {
108
7
        match *self {
109
5
            CppCompiler::CLANG => "pcm",
110
            CppCompiler::MSVC => "ifc",
111
2
            CppCompiler::GCC => "o",
112
        }
113
7
    }
114

            
115
    #[inline(always)]
116
    pub fn obj_file_extension(&self) -> Cow<'_, str> {
117
        Cow::Borrowed(match *self {
118
            CppCompiler::CLANG | CppCompiler::GCC => "o",
119
            CppCompiler::MSVC => "obj",
120
        })
121
    }
122

            
123
    #[inline(always)]
124
8
    pub fn get_obj_file_extension(&self) -> &str {
125
8
        match *self {
126
8
            CppCompiler::CLANG | CppCompiler::GCC => "o",
127
            CppCompiler::MSVC => "obj",
128
        }
129
8
    }
130
}
131

            
132
3
#[derive(Serialize, Deserialize, Default, Debug, PartialEq, Eq, Clone, Copy)]
133
pub enum LanguageLevel {
134
    CPP20,
135
    #[default]
136
    CPP23,
137
    CPP2A,
138
    CPP2B,
139
    LATEST,
140
}
141

            
142
impl fmt::Display for LanguageLevel {
143
2
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144
2
        write!(f, "{}", self.as_ref())
145
2
    }
146
}
147

            
148
impl AsRef<str> for LanguageLevel {
149
2
    fn as_ref(&self) -> &'static str {
150
2
        match *self {
151
            LanguageLevel::CPP20 => "20",
152
1
            LanguageLevel::CPP23 => "23",
153
            LanguageLevel::CPP2A => "2a",
154
1
            LanguageLevel::CPP2B => "2b",
155
            LanguageLevel::LATEST => "latest",
156
        }
157
2
    }
158
}
159

            
160
2
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
161
pub enum StdLib {
162
    STDLIBCPP,
163
    #[default]
164
    LIBCPP,
165
}
166

            
167
impl StdLib {
168
    pub fn as_arg(&self) -> Argument {
169
        Argument::from(match *self {
170
            StdLib::STDLIBCPP => "-stdlib=libstdc++",
171
            StdLib::LIBCPP => "-stdlib=libc++",
172
        })
173
    }
174
}
175

            
176
impl fmt::Display for StdLib {
177
1
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178
1
        write!(f, "{}", self.as_ref())
179
1
    }
180
}
181

            
182
impl AsRef<str> for StdLib {
183
1
    fn as_ref(&self) -> &str {
184
1
        match *self {
185
            StdLib::STDLIBCPP => "libstdc++",
186
1
            StdLib::LIBCPP => "libc++",
187
        }
188
1
    }
189
}
190

            
191
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
192
pub enum StdLibMode {
193
    Cpp,     //< The C++ STD library implemented for every vendor
194
    CCompat, //< Same, but extending it with the C ISO standard library
195
}
196

            
197
impl StdLibMode {
198
    pub fn printable_info(&self) -> &str {
199
        match self {
200
            StdLibMode::Cpp => "C++ standard library implementation",
201
            StdLibMode::CCompat => "C++ C compat standard library implementation",
202
        }
203
    }
204
}
205

            
206
impl fmt::Display for StdLibMode {
207
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208
        write!(f, "{}", self.printable_info())
209
    }
210
}