Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add DependencySnapshot #44

Merged
merged 4 commits into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[workspace]
members = ["tools/solve-snapshot"]

[package]
name = "resolvo"
version = "0.6.0"
Expand Down Expand Up @@ -33,3 +36,4 @@ proptest = "1.2"
tracing-test = { version = "0.2.4", features = ["no-env-filter"] }
tokio = { version = "1.35.1", features = ["time", "rt"] }
resolvo = { path = ".", features = ["tokio"] }
serde_json = "1.0"
8 changes: 8 additions & 0 deletions src/internal/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use crate::{internal::arena::ArenaId, Interner};
/// The id associated to a package name
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct NameId(u32);

impl ArenaId for NameId {
Expand All @@ -20,6 +22,8 @@ impl ArenaId for NameId {
/// The id associated with a generic string
#[repr(transparent)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Ord, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct StringId(u32);

impl ArenaId for StringId {
Expand All @@ -35,6 +39,8 @@ impl ArenaId for StringId {
/// The id associated with a VersionSet.
#[repr(transparent)]
#[derive(Clone, Default, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct VersionSetId(u32);

impl ArenaId for VersionSetId {
Expand All @@ -50,6 +56,8 @@ impl ArenaId for VersionSetId {
/// The id associated to a solvable
#[repr(transparent)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Ord, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct SolvableId(u32);

/// Internally used id for solvables that can also represent root and null.
Expand Down
60 changes: 51 additions & 9 deletions src/internal/mapping.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
use std::{cmp, iter::FusedIterator, marker::PhantomData};

use crate::internal::arena::ArenaId;
use std::cmp;
use std::iter::FusedIterator;
use std::marker::PhantomData;

const VALUES_PER_CHUNK: usize = 128;

/// A `Mapping<TValue>` holds a collection of `TValue`s that can be addressed by `TId`s. You can
/// think of it as a HashMap<TId, TValue>, optimized for the case in which we know the `TId`s are
/// contiguous.
/// A `Mapping<TValue>` holds a collection of `TValue`s that can be addressed by
/// `TId`s. You can think of it as a HashMap<TId, TValue>, optimized for the
/// case in which we know the `TId`s are contiguous.
#[derive(Clone)]
pub struct Mapping<TId, TValue> {
chunks: Vec<[Option<TValue>; VALUES_PER_CHUNK]>,
len: usize,
max: usize,
_phantom: PhantomData<TId>,
}

Expand All @@ -35,6 +36,7 @@ impl<TId: ArenaId, TValue> Mapping<TId, TValue> {
Self {
chunks,
len: 0,
max: 0,
_phantom: Default::default(),
}
}
Expand All @@ -49,7 +51,8 @@ impl<TId: ArenaId, TValue> Mapping<TId, TValue> {

/// Insert into the mapping with the specific value
pub fn insert(&mut self, id: TId, value: TValue) {
let (chunk, offset) = Self::chunk_and_offset(id.to_usize());
let idx = id.to_usize();
let (chunk, offset) = Self::chunk_and_offset(idx);

// Resize to fit if needed
if chunk >= self.chunks.len() {
Expand All @@ -58,6 +61,7 @@ impl<TId: ArenaId, TValue> Mapping<TId, TValue> {
}
self.chunks[chunk][offset] = Some(value);
self.len += 1;
self.max = self.max.max(idx);
}

/// Get a specific value in the mapping with bound checks
Expand Down Expand Up @@ -95,7 +99,9 @@ impl<TId: ArenaId, TValue> Mapping<TId, TValue> {
/// Get a specific value in the mapping without bound checks
///
/// # Safety
/// The caller must uphold most of the safety requirements for `get_unchecked`. i.e. the id having been inserted into the Mapping before.
/// The caller must uphold most of the safety requirements for
/// `get_unchecked`. i.e. the id having been inserted into the Mapping
/// before.
pub unsafe fn get_unchecked(&self, id: TId) -> &TValue {
let (chunk, offset) = Self::chunk_and_offset(id.to_usize());
self.chunks
Expand All @@ -108,7 +114,9 @@ impl<TId: ArenaId, TValue> Mapping<TId, TValue> {
/// Get a specific value in the mapping without bound checks
///
/// # Safety
/// The caller must uphold most of the safety requirements for `get_unchecked_mut`. i.e. the id having been inserted into the Mapping before.
/// The caller must uphold most of the safety requirements for
/// `get_unchecked_mut`. i.e. the id having been inserted into the Mapping
/// before.
pub unsafe fn get_unchecked_mut(&mut self, id: TId) -> &mut TValue {
let (chunk, offset) = Self::chunk_and_offset(id.to_usize());
self.chunks
Expand All @@ -128,6 +136,11 @@ impl<TId: ArenaId, TValue> Mapping<TId, TValue> {
self.len == 0
}

/// Returns the maximum id that has been inserted
pub(crate) fn max(&self) -> usize {
self.max
}

/// Defines the number of slots that can be used
/// theses slots are not initialized
pub fn slots(&self) -> usize {
Expand Down Expand Up @@ -177,6 +190,35 @@ impl<'a, TId: ArenaId, TValue> Iterator for MappingIter<'a, TId, TValue> {

impl<'a, TId: ArenaId, TValue> FusedIterator for MappingIter<'a, TId, TValue> {}

#[cfg(feature = "serde")]
impl<K: ArenaId, V: serde::Serialize> serde::Serialize for Mapping<K, V> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.chunks
.iter()
.flatten()
.take(self.max())
.collect::<Vec<_>>()
.serialize(serializer)
}
}

#[cfg(feature = "serde")]
impl<'de, K: ArenaId, V: serde::Deserialize<'de>> serde::Deserialize<'de> for Mapping<K, V> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let values = Vec::<Option<V>>::deserialize(deserializer)?;
let mut mapping = Mapping::with_capacity(values.len());
for (i, value) in values.into_iter().enumerate() {
if let Some(value) = value {
mapping.insert(K::from_usize(i), value);
}
}
Ok(mapping)
}
}

#[cfg(test)]
mod tests {
use crate::internal::arena::ArenaId;
Expand Down
12 changes: 12 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
pub(crate) mod internal;
pub mod problem;
pub mod runtime;
pub mod snapshot;
mod solver;
pub mod utils;

Expand Down Expand Up @@ -171,6 +172,8 @@ pub struct Candidates {

/// Holds information about the dependencies of a package.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(untagged))]
pub enum Dependencies {
/// The dependencies are known.
Known(KnownDependencies),
Expand All @@ -184,9 +187,14 @@ pub enum Dependencies {

/// Holds information about the dependencies of a package when they are known.
#[derive(Default, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct KnownDependencies {
/// Defines which packages should be installed alongside the depending
/// package and the constraints applied to the package.
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Vec::is_empty")
)]
pub requirements: Vec<VersionSetId>,

/// Defines additional constraints on packages that may or may not be part
Expand All @@ -196,5 +204,9 @@ pub struct KnownDependencies {
/// package also added to the solution.
///
/// This is often useful to use for optional dependencies.
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Vec::is_empty")
)]
pub constrains: Vec<VersionSetId>,
}
Loading