use std::{
fmt::{Display, Formatter},
hash::Hash,
};
use crate::{
Condition, ConditionId,
internal::{
arena::Arena,
frozen_copy_map::FrozenCopyMap,
id::{NameId, SolvableId, StringId, VersionSetId, VersionSetUnionId},
small_vec::SmallVec,
},
};
pub struct Solvable<V> {
pub name: NameId,
pub record: V,
}
pub struct Pool<VS: VersionSet, N: PackageName = String> {
pub(crate) solvables: Arena<SolvableId, Solvable<VS::V>>,
package_names: Arena<NameId, N>,
pub(crate) names_to_ids: FrozenCopyMap<N, NameId, ahash::RandomState>,
strings: Arena<StringId, String>,
pub(crate) string_to_ids: FrozenCopyMap<String, StringId, ahash::RandomState>,
pub(crate) version_sets: Arena<VersionSetId, (NameId, VS)>,
version_set_to_id: FrozenCopyMap<(NameId, VS), VersionSetId, ahash::RandomState>,
version_set_unions: Arena<VersionSetUnionId, SmallVec<VersionSetId>>,
conditions: Arena<ConditionId, Condition>,
condition_to_id: FrozenCopyMap<Condition, ConditionId, ahash::RandomState>,
}
impl<VS: VersionSet, N: PackageName> Default for Pool<VS, N> {
fn default() -> Self {
let solvables = Arena::new();
Self {
solvables,
names_to_ids: Default::default(),
package_names: Arena::new(),
strings: Arena::new(),
string_to_ids: Default::default(),
version_set_to_id: Default::default(),
version_sets: Arena::new(),
version_set_unions: Arena::new(),
conditions: Arena::new(),
condition_to_id: Default::default(),
}
}
}
impl<VS: VersionSet, N: PackageName> Pool<VS, N> {
pub fn new() -> Self {
Self::default()
}
pub fn intern_string(&self, name: impl Into<String> + AsRef<str>) -> StringId {
if let Some(id) = self.string_to_ids.get_copy(name.as_ref()) {
return id;
}
let string = name.into();
let id = self.strings.alloc(string.clone());
self.string_to_ids.insert_copy(string, id);
id
}
pub fn resolve_string(&self, string_id: StringId) -> &str {
&self.strings[string_id]
}
pub fn intern_package_name<NValue>(&self, name: NValue) -> NameId
where
NValue: Into<N>,
N: Clone,
{
let name = name.into();
if let Some(id) = self.names_to_ids.get_copy(&name) {
return id;
}
let next_id = self.package_names.alloc(name.clone());
self.names_to_ids.insert_copy(name, next_id);
next_id
}
pub fn resolve_package_name(&self, name_id: NameId) -> &N {
&self.package_names[name_id]
}
pub fn lookup_package_name(&self, name: &N) -> Option<NameId> {
self.names_to_ids.get_copy(name)
}
pub fn intern_solvable(&self, name_id: NameId, record: VS::V) -> SolvableId {
self.solvables.alloc(Solvable {
name: name_id,
record,
})
}
pub fn resolve_solvable(&self, id: SolvableId) -> &Solvable<VS::V> {
&self.solvables[id]
}
pub fn intern_version_set(&self, package_name: NameId, version_set: VS) -> VersionSetId {
if let Some(entry) = self
.version_set_to_id
.get_copy(&(package_name, version_set.clone()))
{
entry
} else {
let id = self.version_sets.alloc((package_name, version_set.clone()));
self.version_set_to_id
.insert_copy((package_name, version_set), id);
id
}
}
pub fn resolve_version_set(&self, id: VersionSetId) -> &VS {
&self.version_sets[id].1
}
pub fn resolve_version_set_package_name(&self, id: VersionSetId) -> NameId {
self.version_sets[id].0
}
pub fn intern_version_set_union(
&self,
first: VersionSetId,
others: impl Iterator<Item = VersionSetId>,
) -> VersionSetUnionId {
self.version_set_unions
.alloc(others.fold(SmallVec::one(first), |mut vec, version_set| {
vec.push(version_set);
vec
}))
}
pub fn resolve_version_set_union(
&self,
id: VersionSetUnionId,
) -> impl Iterator<Item = VersionSetId> + '_ {
self.version_set_unions[id].iter().copied()
}
pub fn resolve_condition(&self, id: ConditionId) -> &Condition {
&self.conditions[id]
}
pub fn intern_condition(&self, condition: Condition) -> ConditionId {
if let Some(id) = self.condition_to_id.get_copy(&condition) {
return id;
}
let id = self.conditions.alloc(condition.clone());
self.condition_to_id.insert_copy(condition, id);
id
}
}
pub(crate) struct NameDisplay<'pool, VS: VersionSet, N: PackageName> {
id: NameId,
pool: &'pool Pool<VS, N>,
}
impl<VS: VersionSet, N: PackageName + Display> Display for NameDisplay<'_, VS, N> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let name = self.pool.resolve_package_name(self.id);
write!(f, "{}", name)
}
}
impl NameId {
pub fn display<VS: VersionSet, N: PackageName + Display>(
self,
pool: &Pool<VS, N>,
) -> impl Display {
NameDisplay { id: self, pool }
}
}
pub trait PackageName: Eq + Hash {}
impl<N: Eq + Hash> PackageName for N {}
pub trait VersionSet: Clone + Eq + Hash {
type V: Display;
}
#[cfg(feature = "version-ranges")]
impl<R: Clone + Eq + Hash + Display> VersionSet for version_ranges::Ranges<R> {
type V = R;
}