use alloc::boxed::Box;
use alloc::string::String;
use core::fmt::{Display, Formatter, Result};
use core::ops::Deref;
use crate::stmt::{Stmt, StmtRef};
use crate::util::{AddOnlyVec, Indented, RefCounted};
use crate::{Build, BuildRef, Ninja, Pool, ToArg, Variable, Variables};
#[derive(Debug)]
pub struct Rule {
pub name: RefCounted<String>,
pub variables: AddOnlyVec<Variable>,
}
pub trait RuleVariables: Variables {
#[inline]
fn depfile(self, depfile: impl ToArg) -> Self {
self.variable("depfile", depfile)
}
#[inline]
fn deps_gcc(self) -> Self {
self.variable("deps", "gcc")
}
fn deps_msvc_prefix(self, msvc_deps_prefix: impl ToArg) -> Self {
self.deps_msvc()
.variable("msvc_deps_prefix", msvc_deps_prefix)
}
#[inline]
fn deps_msvc(self) -> Self {
self.variable("deps", "msvc")
}
#[inline]
fn description(self, desc: impl ToArg) -> Self {
self.variable("description", desc)
}
#[inline]
fn generator(self) -> Self {
self.variable("generator", "1")
}
#[inline]
fn restat(self) -> Self {
self.variable("restat", "1")
}
fn rspfile(self, rspfile: impl ToArg, rspfile_content: impl ToArg) -> Self {
self.variable("rspfile", rspfile)
.variable("rspfile_content", rspfile_content)
}
fn pool_console(self) -> Self {
self.variable("pool", "console")
}
#[inline]
fn pool(self, pool: impl AsRef<Pool>) -> Self {
self.variable("pool", &pool.as_ref().name)
}
}
#[derive(Debug, Clone)]
pub struct RuleRef(pub(crate) StmtRef);
impl Deref for RuleRef {
type Target = Rule;
fn deref(&self) -> &Self::Target {
match self.0.deref().deref() {
Stmt::Rule(r) => r,
_ => unreachable!(),
}
}
}
impl AsRef<Rule> for RuleRef {
fn as_ref(&self) -> &Rule {
self.deref()
}
}
impl RuleRef {
pub fn build(&self, outputs: impl IntoIterator<Item = impl ToArg>) -> BuildRef {
let build = Build::new(self.deref(), outputs);
BuildRef(self.0.add(Stmt::Build(Box::new(build))))
}
}
impl Rule {
pub fn new(name: impl ToArg, command: impl ToArg) -> Self {
let s = Self {
name: RefCounted::new(name.to_arg()),
variables: AddOnlyVec::new(),
};
s.variable("command", command)
}
pub fn add_to(self, ninja: &Ninja) -> RuleRef {
RuleRef(ninja.add_stmt(Stmt::Rule(self)))
}
}
impl Variables for Rule {
#[inline]
fn add_variable_internal(&self, v: Variable) {
self.variables.add(v);
}
}
impl RuleVariables for Rule {}
impl Variables for RuleRef {
fn add_variable_internal(&self, v: Variable) {
self.deref().add_variable_internal(v)
}
}
impl RuleVariables for RuleRef {}
impl Display for Rule {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
writeln!(f, "rule {}", self.name)?;
for variable in self.variables.inner().iter() {
Indented(variable).fmt(f)?;
writeln!(f)?;
}
Ok(())
}
}