use crate::error::{BuildError, Result};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::path::Path;
#[derive(Deserialize, Serialize)]
pub struct ManifestConfig {
pub project: ProjectSection,
pub build: BuildSection,
pub dependencies: BTreeMap<String, DependencySpec>,
}
#[derive(Deserialize, Serialize)]
pub struct ProjectSection {
pub name: String,
pub version: String,
#[serde(rename = "type")]
pub project_type: ProjectType,
#[serde(default)]
pub c_standard: CStandard,
pub authors: Vec<String>,
pub authors_email: Vec<String>,
pub description: Option<String>,
pub license: Option<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, clap::ValueEnum)]
pub enum ProjectType {
#[default]
#[serde(rename = "bin")]
#[value(name = "bin")]
Binary,
#[serde(rename = "static")]
#[value(name = "static")]
StaticLibrary,
#[serde(rename = "dynamic")]
#[value(name = "dynamic")]
SharedLibrary,
}
#[derive(Debug, Clone, clap::ValueEnum, Default, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum CStandard {
C89,
C90,
C99,
C11,
#[default]
C17,
C23,
Gnu99,
Gnu11,
Gnu17,
}
#[derive(Deserialize, Serialize)]
pub struct BuildSection {
pub compiler: CompilerKind,
pub warnings: WarningLevel,
pub cflags: Vec<String>,
}
#[derive(Deserialize, Serialize)]
pub struct DependencySpec {
pub git: Option<String>,
pub path: Option<String>,
pub tag: Option<String>,
pub build_system: BuildSystemKind,
#[serde(default)]
pub build_commands: Vec<String>,
#[serde(default)]
pub extra_includes: Vec<String>,
#[serde(default)]
pub libs: Vec<String>,
}
#[derive(Debug, Deserialize, Serialize, Default, PartialEq, Eq)]
pub enum BuildSystemKind {
#[default]
Auto,
Cmake,
Meson,
Make,
Custom,
}
#[derive(Deserialize, Serialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum CompilerKind {
#[default]
Auto,
Gcc,
Tcc,
Clang,
}
#[derive(Deserialize, Serialize, Default)]
pub enum WarningLevel {
None,
#[default]
Standard,
Strict,
}
impl ManifestConfig {
pub fn load(project_dir: &Path) -> Result<Self> {
let manifest_path = project_dir.join("Smidr.toml");
if !manifest_path.exists() {
return Err(BuildError::ManifestNotFound(manifest_path));
}
let text = std::fs::read_to_string(&manifest_path)?;
let config: ManifestConfig = toml::from_str(&text)?;
Ok(config)
}
pub fn to_toml_string(&self) -> Result<String> {
Ok(toml::to_string_pretty(self)?)
}
}
impl std::fmt::Display for CStandard {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
CStandard::C89 => "c89",
CStandard::C90 => "c90",
CStandard::C99 => "c99",
CStandard::C11 => "c11",
CStandard::C17 => "c17",
CStandard::C23 => "c23",
CStandard::Gnu99 => "gnu99",
CStandard::Gnu11 => "gnu11",
CStandard::Gnu17 => "gnu17",
};
write!(f, "{}", s)
}
}