use std::fmt::Write;
use std::hash::{Hash, Hasher};
use cairo_lang_filesystem::cfg::CfgSet;
use smol_str::SmolStr;
use crate::compiler::Profile;
use crate::core::{Config, ManifestCompilerConfig, Package, PackageId, Target};
use crate::flock::Filesystem;
use crate::internal::stable_hash::StableHasher;
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct CompilationUnit {
pub main_package_id: PackageId,
pub components: Vec<CompilationUnitComponent>,
pub cairo_plugins: Vec<CompilationUnitCairoPlugin>,
pub profile: Profile,
pub compiler_config: ManifestCompilerConfig,
pub cfg_set: CfgSet,
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct CompilationUnitComponent {
pub package: Package,
pub target: Target,
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct CompilationUnitCairoPlugin {
pub package: Package,
}
impl CompilationUnit {
pub fn main_component(&self) -> &CompilationUnitComponent {
let component = &self.components[0];
assert_eq!(component.package.id, self.main_package_id);
component
}
pub fn core_package_component(&self) -> &CompilationUnitComponent {
let component = &self.components[1];
assert!(component.package.id.is_core());
component
}
pub fn target(&self) -> &Target {
&self.main_component().target
}
pub fn target_dir<'c>(&self, config: &'c Config) -> Filesystem<'c> {
config.target_dir().child(self.profile.as_str())
}
pub fn is_sole_for_package(&self) -> bool {
self.main_component().package.manifest.targets.len() >= 2
}
pub fn has_custom_name(&self) -> bool {
self.main_component().target.kind != self.main_package_id.name.as_str()
}
pub fn id(&self) -> String {
format!("{}-{}", self.main_package_id.name, self.digest())
}
pub fn name(&self) -> String {
let mut string = String::new();
let main_component = self.main_component();
if self.is_sole_for_package() {
write!(&mut string, "{}", main_component.target.kind).unwrap();
if self.has_custom_name() {
write!(&mut string, "({})", main_component.target.name).unwrap();
}
write!(&mut string, " ").unwrap();
}
write!(&mut string, "{}", self.main_package_id).unwrap();
string
}
pub fn digest(&self) -> String {
let mut hasher = StableHasher::new();
self.main_package_id.hash(&mut hasher);
for component in &self.components {
component.hash(&mut hasher);
}
self.profile.hash(&mut hasher);
self.compiler_config.hash(&mut hasher);
hasher.finish_as_short_hash()
}
}
impl CompilationUnitComponent {
pub fn cairo_package_name(&self) -> SmolStr {
self.package.id.name.to_smol_str()
}
fn hash(&self, hasher: &mut impl Hasher) {
self.package.id.hash(hasher);
self.target.hash(hasher);
}
}