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

Create an arena for package names #29

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
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
40 changes: 40 additions & 0 deletions .github/workflows/permaref.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Automatically creates a tag for each commit to `main` so when we rebase
# changes on top of the upstream, we retain permanent references to each
# previous commit so they are not orphaned and eventually deleted.
name: Create permanent reference

on:
push:
branches:
- "main"

jobs:
create-permaref:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Get the permanent ref number
id: get_version
run: |
# Enable pipefail so git command failures do not result in null versions downstream
set -x

echo "LAST_PERMA_NUMBER=$(\
git ls-remote --tags --refs --sort="v:refname" \
https://github.com/zanieb/pubgrub.git | grep "tags/perma-" | tail -n1 | sed 's/.*\/perma-//' \
)" >> $GITHUB_OUTPUT

- name: Configure Git
run: |
git config user.name "$GITHUB_ACTOR"
git config user.email "[email protected]"

- name: Create and push the new tag
run: |
TAG="perma-$((LAST_PERMA_NUMBER + 1))"
git tag -a "$TAG" -m 'Automatically created on push to `main`'
git push origin "$TAG"
env:
LAST_PERMA_NUMBER: ${{ steps.get_version.outputs.LAST_PERMA_NUMBER }}
10 changes: 5 additions & 5 deletions benches/large_case.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ use std::time::Duration;
extern crate criterion;
use self::criterion::*;

use pubgrub::package::Package;
use pubgrub::range::Range;
use pubgrub::solver::{resolve, OfflineDependencyProvider};
use pubgrub::version::SemanticVersion;
use pubgrub::version_set::VersionSet;
use pubgrub::Package;
use pubgrub::Range;
use pubgrub::SemanticVersion;
use pubgrub::VersionSet;
use pubgrub::{resolve, OfflineDependencyProvider};
use serde::de::Deserialize;

fn bench<'a, P: Package + Deserialize<'a>, VS: VersionSet + Deserialize<'a>>(
Expand Down
22 changes: 16 additions & 6 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,19 @@ use thiserror::Error;
use crate::report::DerivationTree;
use crate::solver::DependencyProvider;

/// There is no solution for this set of dependencies.
pub type NoSolutionError<DP> = DerivationTree<
<DP as DependencyProvider>::P,
<DP as DependencyProvider>::VS,
<DP as DependencyProvider>::M,
>;

/// Errors that may occur while solving dependencies.
#[derive(Error)]
pub enum PubGrubError<DP>
where
DP: DependencyProvider,
{
pub enum PubGrubError<DP: DependencyProvider> {
/// There is no solution for this set of dependencies.
#[error("No solution")]
NoSolution(DerivationTree<DP::P, DP::VS, DP::M>),
NoSolution(NoSolutionError<DP>),

/// Error arising when the implementer of
/// [DependencyProvider]
Expand Down Expand Up @@ -62,13 +66,19 @@ where
Failure(String),
}

impl<DP: DependencyProvider> From<NoSolutionError<DP>> for PubGrubError<DP> {
fn from(err: NoSolutionError<DP>) -> Self {
Self::NoSolution(err)
}
}

impl<DP> std::fmt::Debug for PubGrubError<DP>
where
DP: DependencyProvider,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::NoSolution(arg0) => f.debug_tuple("NoSolution").field(arg0).finish(),
Self::NoSolution(err) => f.debug_tuple("NoSolution").field(&err).finish(),
Self::ErrorRetrievingDependencies {
package,
version,
Expand Down
59 changes: 53 additions & 6 deletions src/internal/arena.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::{
fmt,
hash::{Hash, Hasher},
marker::PhantomData,
ops::{Index, Range},
};
use std::fmt;
use std::hash::{BuildHasherDefault, Hash, Hasher};
use std::marker::PhantomData;
use std::ops::{Index, Range};

type FnvIndexSet<K> = indexmap::IndexSet<K, BuildHasherDefault<rustc_hash::FxHasher>>;

/// The index of a value allocated in an arena that holds `T`s.
///
Expand Down Expand Up @@ -49,6 +49,12 @@ impl<T> fmt::Debug for Id<T> {
}
}

impl<T> fmt::Display for Id<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.raw)
}
}

impl<T> Id<T> {
pub fn into_raw(self) -> usize {
self.raw as usize
Expand Down Expand Up @@ -126,3 +132,44 @@ impl<T> Index<Range<Id<T>>> for Arena<T> {
&self.data[(id.start.raw as usize)..(id.end.raw as usize)]
}
}

/// Yet another index-based arena. This one de-duplicates entries by hashing.
///
/// An arena is a kind of simple grow-only allocator, backed by a `Vec`
/// where all items have the same lifetime, making it easier
/// to have references between those items.
/// In this case the `Vec` is inside a `IndexSet` allowing fast lookup by value not just index.
/// They are all dropped at once when the arena is dropped.
#[derive(Clone, PartialEq, Eq)]
pub struct HashArena<T: Hash + Eq> {
data: FnvIndexSet<T>,
}

impl<T: Hash + Eq + fmt::Debug> fmt::Debug for HashArena<T> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Arena")
.field("len", &self.data.len())
.field("data", &self.data)
.finish()
}
}

impl<T: Hash + Eq> HashArena<T> {
pub fn new() -> Self {
HashArena {
data: FnvIndexSet::default(),
}
}

pub fn alloc(&mut self, value: T) -> Id<T> {
let (raw, _) = self.data.insert_full(value);
Id::from(raw as u32)
}
}

impl<T: Hash + Eq> Index<Id<T>> for HashArena<T> {
type Output = T;
fn index(&self, id: Id<T>) -> &T {
&self.data[id.raw as usize]
}
}
Loading
Loading