use crate::core::compiler::{CompileKind, CompileMode};
use crate::core::{profiles::Profile, InternedString, Package, Target};
use crate::util::hex::short_hash;
use std::cell::RefCell;
use std::collections::HashSet;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
#[derive(Clone, Copy, PartialOrd, Ord)]
pub struct Unit<'a> {
inner: &'a UnitInner<'a>,
}
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct UnitInner<'a> {
pub pkg: &'a Package,
pub target: &'a Target,
pub profile: Profile,
pub kind: CompileKind,
pub mode: CompileMode,
pub features: Vec<InternedString>,
pub is_std: bool,
}
impl UnitInner<'_> {
pub fn requires_upstream_objects(&self) -> bool {
self.mode.is_any_test() || self.target.kind().requires_upstream_objects()
}
}
impl<'a> Unit<'a> {
pub fn buildkey(&self) -> String {
format!("{}-{}", self.pkg.name(), short_hash(self))
}
}
impl<'a> Hash for Unit<'a> {
fn hash<H: Hasher>(&self, hasher: &mut H) {
(self.inner as *const UnitInner<'a>).hash(hasher)
}
}
impl<'a> PartialEq for Unit<'a> {
fn eq(&self, other: &Unit<'a>) -> bool {
self.inner as *const UnitInner<'a> == other.inner as *const UnitInner<'a>
}
}
impl<'a> Eq for Unit<'a> {}
impl<'a> Deref for Unit<'a> {
type Target = UnitInner<'a>;
fn deref(&self) -> &UnitInner<'a> {
self.inner
}
}
impl<'a> fmt::Debug for Unit<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Unit")
.field("pkg", &self.pkg)
.field("target", &self.target)
.field("profile", &self.profile)
.field("kind", &self.kind)
.field("mode", &self.mode)
.field("features", &self.features)
.finish()
}
}
pub struct UnitInterner<'a> {
state: RefCell<InternerState<'a>>,
}
struct InternerState<'a> {
cache: HashSet<Box<UnitInner<'a>>>,
}
impl<'a> UnitInterner<'a> {
pub fn new() -> UnitInterner<'a> {
UnitInterner {
state: RefCell::new(InternerState {
cache: HashSet::new(),
}),
}
}
pub fn intern(
&'a self,
pkg: &'a Package,
target: &'a Target,
profile: Profile,
kind: CompileKind,
mode: CompileMode,
features: Vec<InternedString>,
is_std: bool,
) -> Unit<'a> {
let inner = self.intern_inner(&UnitInner {
pkg,
target,
profile,
kind,
mode,
features,
is_std,
});
Unit { inner }
}
fn intern_inner(&'a self, item: &UnitInner<'a>) -> &'a UnitInner<'a> {
let mut me = self.state.borrow_mut();
if let Some(item) = me.cache.get(item) {
return unsafe { &*(&**item as *const UnitInner<'a>) };
}
me.cache.insert(Box::new(item.clone()));
let item = me.cache.get(item).unwrap();
unsafe { &*(&**item as *const UnitInner<'a>) }
}
}