use std::fmt;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum CompilerKind {
Clang,
AppleClang,
ClangCl,
Gcc,
Msvc,
Unknown,
}
impl CompilerKind {
pub fn as_key(self) -> &'static str {
match self {
CompilerKind::Clang => "clang",
CompilerKind::AppleClang => "apple-clang",
CompilerKind::ClangCl => "clang-cl",
CompilerKind::Gcc => "gcc",
CompilerKind::Msvc => "msvc",
CompilerKind::Unknown => "unknown",
}
}
pub fn is_clang_like(self) -> bool {
matches!(
self,
CompilerKind::Clang | CompilerKind::AppleClang | CompilerKind::ClangCl
)
}
pub fn supports_gcc_style_command_line(self) -> bool {
matches!(
self,
CompilerKind::Clang | CompilerKind::AppleClang | CompilerKind::Gcc
)
}
pub fn speaks_msvc_dialect(self) -> bool {
matches!(self, CompilerKind::Msvc | CompilerKind::ClangCl)
}
}
impl fmt::Display for CompilerKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_key())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum ArchiverKind {
Ar,
LlvmAr,
Lib,
Unknown,
}
impl ArchiverKind {
pub fn as_key(self) -> &'static str {
match self {
ArchiverKind::Ar => "ar",
ArchiverKind::LlvmAr => "llvm-ar",
ArchiverKind::Lib => "lib",
ArchiverKind::Unknown => "unknown",
}
}
pub fn supports_ar_crs(self) -> bool {
matches!(self, ArchiverKind::Ar | ArchiverKind::LlvmAr)
}
pub fn produces_static_library(self) -> bool {
matches!(
self,
ArchiverKind::Ar | ArchiverKind::LlvmAr | ArchiverKind::Lib
)
}
}
impl fmt::Display for ArchiverKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_key())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CompilerVersion {
pub major: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub minor: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub patch: Option<u32>,
pub raw: String,
}
impl CompilerVersion {
pub fn parse(raw: &str) -> Option<Self> {
let mut parts = raw.split('.');
let major: u32 = parts.next()?.parse().ok()?;
let minor = parts.next().and_then(|s| s.parse().ok());
let patch = parts.next().and_then(|s| s.parse().ok());
Some(Self {
major,
minor,
patch,
raw: raw.to_owned(),
})
}
pub fn to_display_string(&self) -> String {
match (self.minor, self.patch) {
(Some(min), Some(pat)) => format!("{}.{}.{}", self.major, min, pat),
(Some(min), None) => format!("{}.{}", self.major, min),
_ => self.major.to_string(),
}
}
}
impl fmt::Display for CompilerVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.to_display_string())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CompilerIdentity {
pub kind: CompilerKind,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub version: Option<CompilerVersion>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub target: Option<String>,
pub raw_version_line: String,
}
impl CompilerIdentity {
pub fn unknown(raw_version_line: impl Into<String>) -> Self {
Self {
kind: CompilerKind::Unknown,
version: None,
target: None,
raw_version_line: raw_version_line.into(),
}
}
pub fn as_json(&self) -> serde_json::Value {
let mut obj = serde_json::Map::new();
obj.insert(
"kind".to_owned(),
serde_json::Value::String(self.kind.as_key().to_owned()),
);
if let Some(v) = &self.version {
obj.insert(
"version".to_owned(),
serde_json::Value::String(v.to_display_string()),
);
}
if let Some(t) = &self.target {
obj.insert("target".to_owned(), serde_json::Value::String(t.clone()));
}
obj.insert(
"raw_version_line".to_owned(),
serde_json::Value::String(self.raw_version_line.clone()),
);
serde_json::Value::Object(obj)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ArchiverIdentity {
pub kind: ArchiverKind,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub version: Option<CompilerVersion>,
pub raw_version_line: String,
}
impl ArchiverIdentity {
pub fn unknown(raw_version_line: impl Into<String>) -> Self {
Self {
kind: ArchiverKind::Unknown,
version: None,
raw_version_line: raw_version_line.into(),
}
}
pub fn as_json(&self) -> serde_json::Value {
let mut obj = serde_json::Map::new();
obj.insert(
"kind".to_owned(),
serde_json::Value::String(self.kind.as_key().to_owned()),
);
if let Some(v) = &self.version {
obj.insert(
"version".to_owned(),
serde_json::Value::String(v.to_display_string()),
);
}
obj.insert(
"raw_version_line".to_owned(),
serde_json::Value::String(self.raw_version_line.clone()),
);
serde_json::Value::Object(obj)
}
}