use std::{
borrow::Borrow,
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: IntoPackageName<N>,
N: Borrow<NValue::Borrowed> + Clone,
{
if let Some(id) = self.names_to_ids.get_copy(name.as_borrowed()) {
return id;
}
let name = name.into_owned();
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 iter_solvables(&self) -> impl Iterator<Item = (SolvableId, &Solvable<VS::V>)> {
self.solvables.iter()
}
pub fn intern_version_set(&self, package_name: NameId, version_set: VS) -> VersionSetId {
let key = (package_name, version_set);
if let Some(entry) = self.version_set_to_id.get_copy(&key) {
entry
} else {
let id = self.version_sets.alloc(key.clone());
self.version_set_to_id.insert_copy(key, 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 IntoPackageName<N: PackageName> {
type Borrowed: ?Sized + Hash + Eq;
fn as_borrowed(&self) -> &Self::Borrowed;
fn into_owned(self) -> N;
}
impl<N: PackageName> IntoPackageName<N> for N {
type Borrowed = N;
fn as_borrowed(&self) -> &N {
self
}
fn into_owned(self) -> N {
self
}
}
impl<N: PackageName + Clone> IntoPackageName<N> for &N {
type Borrowed = N;
fn as_borrowed(&self) -> &N {
self
}
fn into_owned(self) -> N {
self.clone()
}
}
impl IntoPackageName<String> for &str {
type Borrowed = str;
fn as_borrowed(&self) -> &str {
self
}
fn into_owned(self) -> String {
self.to_string()
}
}
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;
}