ctplt 0.0.1

A package manager + build system for C and C++
Documentation
use core::fmt;
use std::{
	path::PathBuf,
	sync::{Arc, Weak},
};

use starlark::values::OwnedFrozenValue;

use crate::{
	link_type::LinkPtr,
	misc::{SourcePath, Sources},
	project::Project,
	target::{LinkTarget, Target},
};

#[derive(Debug)]
pub struct Executable {
	pub parent_project: Weak<Project>,

	pub name: String,
	pub sources: Sources,
	pub links: Vec<LinkPtr>,
	pub include_dirs: Vec<SourcePath>,
	pub defines: Vec<String>,
	pub link_flags: Vec<String>,

	pub generator_vars: Option<OwnedFrozenValue>,

	pub output_name: Option<String>,
}

impl fmt::Display for Executable {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
		write!(
			f,
			r#"Executable{{
   name: {},
   sources: [{}],
   links: [{}],
   include_dirs: [{}],
   defines: [{}],
   link_flags: [{}],
   output_name: {},
}}"#,
			self.name,
			self.sources
				.iter()
				.map(|x| &x.name)
				.fold(String::new(), |acc, x| acc + ", " + x),
			self.links.iter().map(|x| x.name()).collect::<Vec<_>>().join(", "),
			self.include_dirs
				.iter()
				.map(|x| &x.name)
				.fold(String::new(), |acc, x| acc + ", " + x),
			self.defines.join(", "),
			self.link_flags.join(", "),
			self.output_name.clone().unwrap_or("None".to_owned())
		)
	}
}

impl Target for Executable {
	fn name(&self) -> &str {
		&self.name
	}
	fn output_name(&self) -> &str {
		match &self.output_name {
			Some(output_name) => output_name,
			None => &self.name,
		}
	}
	fn project(&self) -> Arc<Project> {
		self.parent_project.upgrade().unwrap()
	}
}

impl Executable {
	pub(crate) fn public_includes_recursive(&self) -> Vec<PathBuf> {
		let mut includes = Vec::new();
		for link in &self.links {
			for include in link.public_includes_recursive() {
				if !includes.contains(&include) {
					includes.push(include);
				}
			}
		}

		for include in self.include_dirs.iter().map(|x| &x.full) {
			if !includes.contains(include) {
				includes.push(include.to_owned());
			}
		}
		includes
	}
	pub(crate) fn public_defines_recursive(&self) -> Vec<String> {
		let mut defines = Vec::new();
		for link in &self.links {
			for def in link.public_defines_recursive() {
				if !defines.contains(&def) {
					defines.push(def);
				}
			}
		}
		for def in &self.defines {
			if !defines.contains(def) {
				defines.push(def.clone());
			}
		}
		defines
	}
	pub(crate) fn link_flags_recursive(&self) -> Vec<String> {
		let mut flags = Vec::new();
		for link in &self.links {
			for flag in link.public_link_flags_recursive() {
				if !flags.contains(&flag) {
					flags.push(flag);
				}
			}
		}
		for flag in &self.link_flags {
			if !flags.contains(flag) {
				flags.push(flag.clone());
			}
		}
		flags
	}
	pub(crate) fn set_parent(&mut self, parent: Weak<Project>) {
		self.parent_project = parent;
	}
}