profile
viewpoint

pubgrub-rs/pubgrub 7

PubGrub version solving algorithm implemented in Rust

aleksator/arch-cursor-complete 5

Cursor theme for X11

aleksator/book 0

The Rust Programming Language

aleksator/cache 0

Cache dependencies and build outputs in GitHub Actions

aleksator/cargo 0

The Rust package manager

aleksator/edition-guide 0

A guide to changes between various editions of Rust

aleksator/elm-pubgrub 0

PubGrub version solving algorithm in elm

aleksator/Kaleidoscope 0

Firmware for the Keyboardio Model 01 and other keyboards with AVR or ARM MCUs.

aleksator/Kaleidoscope-Bundle-Keyboardio 0

A Kaleidoscope distribution for the Keyboardio Model 01 and other keyboards.

aleksator/llvm-project 0

Rust-specific fork of LLVM.

PR opened pubgrub-rs/pubgrub

ci: add clippy

CI for this PR should pass once #46 and #48 are merged.

+17 -0

0 comment

1 changed file

pr created time in 8 hours

push eventpubgrub-rs/pubgrub

push time in 8 hours

create barnchpubgrub-rs/pubgrub

branch : change_ci_job_names

created branch time in 8 hours

create barnchpubgrub-rs/pubgrub

branch : add_clippy_to_ci

created branch time in 8 hours

pull request commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

Summary:

AssignmentDepth could be named better:

  • AssignmentWithDecisionLevel
  • DecidedAssignment
  • AppliedAssignment

AssignmentHistory - alright name, but questionable grouping.

aleksator

comment created time in 10 hours

pull request commentpubgrub-rs/pubgrub

refactor!: define Dependencies type

TLDR: @Eh2406 @Dylan-DPC Please :+1: / :-1: new public types :smile:

Summary of the current state:

This PR focuses on public API of our library, namely return types of resolve and DependencyProvider.get_dependencies functions.

Several new public types are defined (Let me know if the intended purpose is unclear from the docs):

/// An enum used by [DependencyProvider] that holds information about package dependencies.
/// For each [Package] there is a [Range] of concrete versions it allows as a dependency.
pub enum Dependencies<P: Package, V: Version> {
    /// Package dependencies are unavailable.
    Unknown,
    /// Container for all available package versions.
    Known(DependencyConstraints<P, V>),
}
/// Subtype of [Dependencies] which holds information about
/// all possible versions a given package can accept.
/// There is a difference in semantics between an empty [Map<P, Range<V>>](crate::type_aliases::Map)
/// inside [DependencyConstraints] and [Dependencies::Unknown]:
/// the former means the package has no dependencies and it is a known fact,
/// while the latter means they could not be fetched by [DependencyProvider].
pub struct DependencyConstraints<P: Package, V: Version>(Map<P, Range<V>>);
/// Concrete dependencies picked by the library during [resolve](crate::solver::resolve)
/// from [DependencyConstraints](crate::solver::DependencyConstraints)
pub type SelectedDependencies<P, V> = Map<P, V>;

This is a type alias for now, but I'd like to see if we could make it a struct and hide currently exposed Map alias in a separate PR.

As a result function signatures now look like this:

pub fn resolve<P: Package, V: Version>(
    dependency_provider: &impl DependencyProvider<P, V>,
    package: P,
    version: impl Into<V>,
) -> Result<SelectedDependencies<P, V>, PubGrubError<P, V>> {
    fn get_dependencies(
        &self,
        package: &P,
        version: &V,
    ) -> Result<Dependencies<P, V>, Box<dyn Error>>;

If you have any comments about the ergonomics - let me know.


We also need to decide the exact names for these public types, feel free to add suggestions. The only suggestion left that diverges from the latest commit is:

@mpizenberg suggested to rename Dependencies to Response and change get_dependencies signature to:

    fn get_dependencies(
        &self,
        package: &P,
        version: &V,
    ) -> Result<Response<DependencyConstraints<P, V>>, Box<dyn Error>>;

The resulting method signature is pretty clear. I have a concern when doing matching on this type though: Response::Unknown makes it look like we didn't expect this from a DependencyProvider.

aleksator

comment created time in 11 hours

push eventpubgrub-rs/pubgrub

Alex Tokarev

commit sha 809ea1fa042d3c00fd46c2a755c7950e04a500da

docs: fix return type of a private function

view details

push time in 11 hours

push eventpubgrub-rs/pubgrub

Alex Tokarev

commit sha cbc6d4d4d1ecf8f3200569282b6f4c81135a4db2

refactor: apply Clippy suggestions (#52) * refactor: apply trivial Clippy suggestions * refactor: cargo clippy --fix * refactor: rewrite if chain using cmp() and match * feat: derive Default for OfflineDependencyProvider

view details

Alex Tokarev

commit sha 3ea7afeefbb9a6168c619e007a73bfe4d7631b38

refactor!: define Dependencies type

view details

Alex Tokarev

commit sha 3b3a9b3e567474854c165b0fd37137eb0cafd18a

refactor!: rename AvailableVersions to DependencyConstraints

view details

Alex Tokarev

commit sha 9851387862d1b0fc77da5777262affb499ee5976

refactor: define SelectedDependencies type alias

view details

push time in 12 hours

pull request commentpubgrub-rs/pubgrub

refactor!: define Dependencies type

@aleksator would you mind summarize the different options and ask here and on our zulip thread what people think?

Sure. I'll implement what we agreed to so far and we'll be able to discuss that directly using Github review tools.

aleksator

comment created time in 13 hours

pull request commentpubgrub-rs/pubgrub

refactor!: define Dependencies type

Reads very well. But the result should also be easily handled by the caller code. Defining the type alias type SelectedDependencies<P, V> = Map<P, V> would do it. If using a struct instead, usage depends on how it is exposed, but would require at least one level of indirection.

Yeah there are some design considerations if we want to do a newtype for that. I have some ideas (we can hide inner Map type and leave it as implementation detail for example) and would like to discuss them in a separate issue.

For now let's just do a type alias here. I'll do it shortly.

aleksator

comment created time in 13 hours

pull request commentpubgrub-rs/pubgrub

refactor!: define Dependencies type

Maybe Response is quite fitting.

enum Response<T> {
   Unknown,
   Known(T),
}

Response does sounds fitting, but now Response::Unknown gives a wrong impression that we didn't anticipate it.

What if we leave it as just Dependencies?

    fn get_dependencies(
        &self,
        package: &P,
        version: &V,
    ) -> Result<Dependencies<P, V>, Box<dyn Error>>;

Dependencies::Unknown and Dependencies::Known(DependencyConstraints) are read just like English sentences :)

In type_aliases.rs we could define:

Should the module be renamed to something? enum is not a type alias after all.

aleksator

comment created time in 13 hours

pull request commentpubgrub-rs/pubgrub

refactor!: define Dependencies type

The DependencyConstraints vs DependencyVersions was for your question about difference between Map<P, Range<V>> and Map<P, V>.

Regarding DependencyVersions: I very much like the idea of returning a struct instead of Map<P, V> directly in our resolve function. Great suggestion! I suggest naming it SelectedDependencies to emphasize that it's our library's output. Let's see:

pub fn resolve<P: Package, V: Version>(
    dependency_provider: &impl DependencyProvider<P, V>,
    package: P,
    version: impl Into<V>,
) -> Result<SelectedDepedencies<P, V>, PubGrubError<P, V>> {

I like it!

aleksator

comment created time in 13 hours

delete branch pubgrub-rs/pubgrub

delete branch : approved_clippy_fixes

delete time in a day

push eventpubgrub-rs/pubgrub

Alex Tokarev

commit sha cbc6d4d4d1ecf8f3200569282b6f4c81135a4db2

refactor: apply Clippy suggestions (#52) * refactor: apply trivial Clippy suggestions * refactor: cargo clippy --fix * refactor: rewrite if chain using cmp() and match * feat: derive Default for OfflineDependencyProvider

view details

push time in a day

PR merged pubgrub-rs/pubgrub

refactor: apply Clippy suggestions

This is part of #48 that had no controversial changes.

+49 -42

2 comments

6 changed files

aleksator

pr closed time in a day

pull request commentpubgrub-rs/pubgrub

refactor!: define Dependencies type

And since it's my "hey here is a great talk about it" time tonight, I highly recommend "Spec-ulation" by Rich Hickey: https://youtu.be/oyLBGkS5ICk

Great talk btw, still awake because I couldn't stop watching it. I wonder if cargo makes his point moot with its auto namespace for conflicting versions.

Maybe one could be DependencyConstraints and the other DependencyVersions? Like this there is nothing just called Dependencies.

Hm, not sure if DependencyConstraints::Unavailable sounds right. Does DependencyConstraints::Unknown sound better? As for DependencyVersions, I think both that and just Dependencies fit nicely here.

I'll compose all the combinations in this message and have a look at them again in the morning:

pub enum DependencyConstraints<P: Package, V: Version> {
    Unavailable,
    Known(DependencyVersions<P, V>),
}
pub enum DependencyConstraints<P: Package, V: Version> {
    Unknown,
    Known(DependencyVersions<P, V>),
}
pub enum DependencyConstraints<P: Package, V: Version> {
    Unavailable,
    Known(Dependencies<P, V>),
}
pub enum DependencyConstraints<P: Package, V: Version> {
    Unknown,
    Known(Dependencies<P, V>),
}
aleksator

comment created time in a day

pull request commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

Do you want to maybe add clippy to CI in that PR?

We need this, #46 and #48 all merged in order for Clippy to pass, that's why I thought of adding it separately. I can add it to the last one standing if you want.

All good!

Thanks! :+1: Your choice of squash/rebase

aleksator

comment created time in a day

Pull request review commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

 enum Kind<P: Package, V: Version> {     DerivedFrom(usize, usize), } +/// A type alias for a pair of [Package] and a corresponding [Term].+pub type PackageTerm<P, V> = (P, Term<V>);

Thanks. Let's keep a type alias then :)

aleksator

comment created time in a day

PullRequestReviewEvent

Pull request review commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

 use crate::{     solver::DependencyProvider, }; +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]+pub struct DecisionLevel(u32);

Ah, and I misunderstood that you were arguing against adding a newtype or type alias for decision_level and wanted to keep a plain integer type. Got it now :+1:

aleksator

comment created time in a day

PullRequestReviewEvent

push eventpubgrub-rs/pubgrub

Jacob Finkelman

commit sha 25a1c8d63196d6ebbbf7cd0cf4a1eb291f5a94b1

test: switch to criterion (#47)

view details

Alex Tokarev

commit sha 25b865187ecc71e8089b3f3f280caf897deb602e

ci: allow ! in commits to indicate breaking changes (#51) This change works around a bug in `commitlint`: https://github.com/conventional-changelog/commitlint/issues/2226

view details

Alex Tokarev

commit sha 89d79cb38b7a308e4e96c311248801e5dd79eff7

refactor!: define Dependencies type

view details

push time in a day

issue commentconventional-changelog/commitlint

Messages with an exclamation mark after type ("feat!") fail with Angular config

I am getting the same error even when extending @commitlint/config-conventional

@evanstoddard23 You can see the exact workaround that worked for us here: https://github.com/pubgrub-rs/pubgrub/pull/51. Maybe it will help you troubleshoot the differences.

aleksator

comment created time in a day

PR opened pubgrub-rs/pubgrub

Extracted approved clippy fixes

This is part of #48 that had no controversial changes.

+49 -42

0 comment

6 changed files

pr created time in a day

create barnchpubgrub-rs/pubgrub

branch : approved_clippy_fixes

created branch time in a day

push eventpubgrub-rs/pubgrub

Jacob Finkelman

commit sha 25a1c8d63196d6ebbbf7cd0cf4a1eb291f5a94b1

test: switch to criterion (#47)

view details

Alex Tokarev

commit sha 25b865187ecc71e8089b3f3f280caf897deb602e

ci: allow ! in commits to indicate breaking changes (#51) This change works around a bug in `commitlint`: https://github.com/conventional-changelog/commitlint/issues/2226

view details

Alex Tokarev

commit sha 4c00ce7b52826d60bdaea14ff9d3be02167ab2cc

refactor: extract AssignmentDepth struct

view details

Alex Tokarev

commit sha 932b0065a301a4ab8c46f1036d3da19652840b9b

refactor: define newtype DecisionLevel(u32)

view details

Alex Tokarev

commit sha 9c713c9a6df028b2d93e1f9a677dd7604b48f07d

refactor: define AssignmentHistory

view details

Alex Tokarev

commit sha 7356b8c19ec86cc56e6a29651055595516c91917

refactor: define PackageTerm type alias

view details

push time in a day

pull request commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

We could merge a few uncontroversial changes. There are a lot of discussion points though, and I don't know how to move them to another PR. Gitlab has "resolve in another issue" button, but I don't see anything similar here. Does anyone know?

Just realized I could do the opposite: extract approved parts into a separate PR and leave all the questionable items here. Let me do just that.

aleksator

comment created time in a day

pull request commentpubgrub-rs/pubgrub

refactor!: define Dependencies type

And since it's my "hey here is a great talk about it" time tonight, I highly recommend "Spec-ulation" by Rich Hickey: https://youtu.be/oyLBGkS5ICk

Thank you, that's going to be a talk for my evening today :)

Interesting, for me it's the opposite, I picture it as the range of possible versions

I don't mind renaming it in this PR to Dependencies. Just curious, what would you call a concrete picked dependency version?

aleksator

comment created time in a day

delete branch pubgrub-rs/pubgrub

delete branch : fix_exclamation_mark_in_commits

delete time in a day

push eventpubgrub-rs/pubgrub

Alex Tokarev

commit sha 25b865187ecc71e8089b3f3f280caf897deb602e

ci: allow ! in commits to indicate breaking changes (#51) This change works around a bug in `commitlint`: https://github.com/conventional-changelog/commitlint/issues/2226

view details

push time in a day

PR merged pubgrub-rs/pubgrub

ci: allow exclamation mark after commit message type

Extracted out of #46 since there are more PRs depended on this fix.

+20 -2

0 comment

1 changed file

aleksator

pr closed time in a day

PR opened pubgrub-rs/pubgrub

ci: allow exclamation mark after commit message type

Extracted out of #46 since there are more PRs depended on this fix.

+20 -2

0 comment

1 changed file

pr created time in a day

create barnchpubgrub-rs/pubgrub

branch : fix_exclamation_mark_in_commits

created branch time in a day

delete branch pubgrub-rs/pubgrub

delete branch : criterion

delete time in a day

push eventpubgrub-rs/pubgrub

Jacob Finkelman

commit sha 25a1c8d63196d6ebbbf7cd0cf4a1eb291f5a94b1

test: switch to criterion (#47)

view details

push time in a day

PR merged pubgrub-rs/pubgrub

test: switch to criterion

This switches our benchmark(s) to use criterion. Newer versions of criterion works better with slower tests, so it works out pretty well.

This automatically adds a benchmark for each file in test-examples/, removing the duplicated code pointed out in https://github.com/pubgrub-rs/pubgrub/pull/34#issuecomment-708426561. This also allows decoupling between the code and the ron files. For example if in #43 we decide not to store all the ron files in tree, this will run the benchmarks on only what is in the file system.

+38 -16

6 comments

2 changed files

Eh2406

pr closed time in a day

PullRequestReviewEvent

Pull request review commentpubgrub-rs/pubgrub

test: switch to criterion

 // SPDX-License-Identifier: MPL-2.0+use std::time::Duration; -#![feature(test)]-extern crate test;-use test::Bencher;+extern crate criterion;+use self::criterion::*; -use pubgrub::solver::{resolve, OfflineDependencyProvider};+use pubgrub::solver::{resolve, DependencyProvider, OfflineDependencyProvider}; use pubgrub::version::NumberVersion; -#[cfg(feature = "serde")]-#[bench]-/// This is an entirely synthetic benchmark. It may not be realistic.-fn large_case(b: &mut Bencher) {-    let s = std::fs::read_to_string("test-examples/large_case_u16_NumberVersion.ron").unwrap();-    let dependency_provider: OfflineDependencyProvider<u16, NumberVersion> =-        ron::de::from_str(&s).unwrap();--    // bench-    b.iter(|| {-        let _ = resolve(&dependency_provider, 0, 0);-    });+fn bench_nested(c: &mut Criterion) {+    let mut group = c.benchmark_group("large_cases");+    group.measurement_time(Duration::from_secs(10));

Thank you for the change :+1:

Unfortunately, confidence_interval does not affect the measurement time only the amount of difference that is declared regressed.

Yeah, that's unfortunate. Since we don't know any better options other than time, let's go with that.

Eh2406

comment created time in a day

PullRequestReviewEvent

pull request commentpubgrub-rs/pubgrub

test: switch to criterion

Eh2406 requested a review from aleksator 18 hours ago

Sorry for the delay. Seemed fine at a glance, but I need to dive into the docs before I could comment meaningfully. I will do so today or tomorrow. The only question I had was about 10 seconds, left a review comment above.

Alternatively, since the change is quite simple, we could merge as is and submit changes later. I don't want to hold this PR hostage :smile:

Eh2406

comment created time in a day

Pull request review commentpubgrub-rs/pubgrub

test: switch to criterion

 // SPDX-License-Identifier: MPL-2.0+use std::time::Duration; -#![feature(test)]-extern crate test;-use test::Bencher;+extern crate criterion;+use self::criterion::*; -use pubgrub::solver::{resolve, OfflineDependencyProvider};+use pubgrub::solver::{resolve, DependencyProvider, OfflineDependencyProvider}; use pubgrub::version::NumberVersion; -#[cfg(feature = "serde")]-#[bench]-/// This is an entirely synthetic benchmark. It may not be realistic.-fn large_case(b: &mut Bencher) {-    let s = std::fs::read_to_string("test-examples/large_case_u16_NumberVersion.ron").unwrap();-    let dependency_provider: OfflineDependencyProvider<u16, NumberVersion> =-        ron::de::from_str(&s).unwrap();--    // bench-    b.iter(|| {-        let _ = resolve(&dependency_provider, 0, 0);-    });+fn bench_nested(c: &mut Criterion) {+    let mut group = c.benchmark_group("large_cases");+    group.measurement_time(Duration::from_secs(10));

If I assume correctly, the time here is very machine dependent. Criterion suggests adding a couple seconds here on my laptop. It would be best if we all were able to run benchmarks without changes.

Are there any other options we could use instead of the time? Hard to suggest anything concrete without diving into the API myself, will do so later.

When I looked through the API, I saw group.confidence_interval (or similar), where you set up a desirable level. Maybe that or some other option would do the trick.

Eh2406

comment created time in a day

PullRequestReviewEvent
PullRequestReviewEvent
CommitCommentEvent

push eventpubgrub-rs/pubgrub

Alex Tokarev

commit sha 99132d0470f800a1db37bab294b94ea6502fad16

fix: make structs public after reverting "pub changes"

view details

push time in a day

Pull request review commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

 use crate::{     solver::DependencyProvider, }; +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]+pub struct DecisionLevel(u32);

Alright just in the following commit +1

Sorry, I don't follow what you mean here :)

aleksator

comment created time in a day

PullRequestReviewEvent

Pull request review commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

 impl<P: Package, V: Version> PartialSolution<P, V> {         let pos = self             .history             .iter()-            .rposition(|(l, _)| *l == decision_level)+            .rposition(+                |AssignmentDepth {+                     decision_level: l,+                     assignment: _,+                 }| *l == decision_level,+            )             .unwrap_or(self.history.len() - 1);         *self = Self::from_assignments(             std::mem::take(&mut self.history)                 .into_iter()                 .take(pos + 1)-                .map(|(_, a)| a),+                .map(+                    |AssignmentDepth {+                         decision_level: _,+                         assignment,+                     }| assignment,

Changed both in the latest commit "refactor: shorten AssignmentDepth matching".

aleksator

comment created time in a day

PullRequestReviewEvent

push eventpubgrub-rs/pubgrub

Alex Tokarev

commit sha 3c1dd6269c6601900e068c019592c3177a05afc1

revert: "refactor: remove unneeded "pub" modifiers" This reverts commit 01351c20

view details

Alex Tokarev

commit sha 9fc34f8cd85a5ec5615a799b45e3b17a07167554

refactor: shorten AssignmentDepth matching

view details

push time in 2 days

Pull request review commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

 use crate::version::Version; pub struct State<P: Package, V: Version> {     root_package: P,     root_version: V,--    /// TODO: remove pub.-    pub incompatibilities: Rc<Vec<Incompatibility<P, V>>>,-+    incompatibilities: Rc<Vec<Incompatibility<P, V>>>,     /// Partial solution.-    /// TODO: remove pub.-    pub partial_solution: PartialSolution<P, V>,-+    pub(crate) partial_solution: PartialSolution<P, V>,

Will revert.

aleksator

comment created time in 2 days

PullRequestReviewEvent

pull request commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

If there are a few lintes that are holding this PR back, then we should split them out and merge the clear cut parts.

I think what was holding this PR back was me not working through the comments until today :)

We could merge a few uncontroversial changes. There are a lot of discussion points though, and I don't know how to move them to another PR. Gitlab has "resolve in another issue" button, but I don't see anything similar here. Does anyone know?

Alternatively, we could fix everything in this PR since I have time this weekend to correct everything.

aleksator

comment created time in 2 days

Pull request review commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

 enum Kind<P: Package, V: Version> {     DerivedFrom(usize, usize), } +/// A type alias for a pair of [Package] and a corresponding [Term].+pub type PackageTerm<P, V> = (P, Term<V>);

I admit this was just to fix a clippy lint, both before and after are quite easy to read IMO. I weighted the options of adding a suppress for the lint, and defining a type alias for PackageTerm and went with the latter.

The reason was we already have this meaning implicitly defined in our library: we have package_terms map that we iterate over, and the iterator returns this tuple. So it didn't feel like a new thing you have to look up a definition of.

If you disagree with the reasoning, let me know and I will change it to a lint suppression instead.

aleksator

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

 impl<P: Package, V: Version> PartialSolution<P, V> {         &self,         incompat: &Incompatibility<P, V>,     ) -> (Assignment<P, V>, DecisionLevel, DecisionLevel) {-        let (-            AssignmentDepth {-                decision_level: satisfier_level,-                assignment: satisfier,-            },-            previous_assignments,-        ) = Self::find_satisfier(incompat, self.history.as_slice())+        let AssignmentHistory {

The logic inside the satisfier isn't something very stable either. so having the flexibility of easily changing the return types there is important.

Doesn't having a grouping type make it more easily changeable? You could extend the struct/change inner fields without touching type signature.

These really should not be put together though in my opinion. They have no other reason to be together than being two outputs of a function.

True, the purpose of the change was to provide some context on those return types. Before:

 ) -> Option<(AssignmentDepth<P, V>, &'a [AssignmentDepth<P, V>])>

After:

 ) -> Option<AssignmentHistory<'a, P, V>>

I think looking at type signature of "before" version does not make it clear why those are separate and why AssignmentDepth is not inside the slice, and what that slice means.

Would you be okay with making this a type alias if you think a struct definition doesn't pull it's weight here? I would like having one of those as a return type.

aleksator

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

 use crate::{     solver::DependencyProvider, }; +#[derive(Clone)]+struct AssignmentDepth<P: Package, V: Version> {

DecidedAssignment

AppliedAssignment as another option.

Maybe a type alias would be enough here?

Wait, I see another thread talking about type alias/newtype for DecisionLevel. Were you asking about the whole AssignmentDepth here? If so, I got confused by "Is it the fact that usize does not convey a lot of meaning that bothers you?" question.

Let's see... It keeps return types in functions the same as newtype, quite readable. I'm only concerned about matching on it: you'd have to look up the type definition and do tuple destructuring in that case, while newtype allows field access by name.

aleksator

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

 use crate::{     solver::DependencyProvider, }; +#[derive(Clone)]+struct AssignmentDepth<P: Package, V: Version> {

Maybe AssignmentWithDecisionLevel would be more adequate even though a bit redundant with its content.

I can rename that no problem. A bit verbose, but can't come up with anything better. DecidedAssignment? :smile:

Is it the fact that usize does not convey a lot of meaning that bothers you?

I like using type system to indicate meaning and make it easily greppable. Allows for easy type changes as well: say we want to reduce u32 to u16, it would simplify doing such refactoring a lot.

Maybe a type alias would be enough here?

Let's see, type alias also provides some of those benefits. There is a problem that you could forget to use it, so searching usages becomes less reliable. Even if you never forget new instance creation becomes hidden (just 0/1 in code). It also can not guard against adding that and something else. As for benefits... Hm... Both are fully optimized away, so I don't know. Why do you like it more?

aleksator

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

 impl<P: Package, V: Version> PartialSolution<P, V> {         let pos = self             .history             .iter()-            .rposition(|(l, _)| *l == decision_level)+            .rposition(+                |AssignmentDepth {+                     decision_level: l,+                     assignment: _,+                 }| *l == decision_level,+            )             .unwrap_or(self.history.len() - 1);         *self = Self::from_assignments(             std::mem::take(&mut self.history)                 .into_iter()                 .take(pos + 1)-                .map(|(_, a)| a),+                .map(+                    |AssignmentDepth {+                         decision_level: _,+                         assignment,+                     }| assignment,

Or even better, we can just do .map(|assignment_depth| assignment_depth.assignment). Thanks for bringing my attention to these lines.

aleksator

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

 impl<V: Version> Range<V> {                 }                  // Right contains an infinite interval:-                (Some((l1, Some(l2))), Some((r1, None))) => {-                    if l2 < r1 {+                (Some((l1, Some(l2))), Some((r1, None))) => match l2.cmp(r1) {+                    Ordering::Less => {

I like it because it shows the intent, you are performing a comparison over all possible values.

There's a principle I use while coding that can be formulated as "use the least powerful construct that does that job".

Like when you are iterating over values in a list, foreach is preferred over for (int i = 0; i < len; ++i) since the latter is more powerful construct, using that indicates that you probably want to manipulate indexes somehow. If you aren't doing that, foreach says "simple iteration".

Same deal here: match over possible comparison values says exactly that. If chain is more powerful, you would use it if you wanted to do something additional in the conditions and you have to check whether that is the case. It is not the case here, hence we can use less powerful tool and save ourselves condition checking.

aleksator

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

 impl<V: Version> Range<V> {                 }                  // Right contains an infinite interval:-                (Some((l1, Some(l2))), Some((r1, None))) => {-                    if l2 < r1 {+                (Some((l1, Some(l2))), Some((r1, None))) => match l2.cmp(r1) {+                    Ordering::Less => {

warning: if chain can be rewritten with match --> src/range.rs:202:21 | 202 | / if r2 < l1 { 203 | | right = right_iter.next(); 204 | | } else if r2 == l1 { 205 | | segments.extend(right_iter.cloned()); ... | 211 | | break; 212 | | } | |_____________________^ | = help: Consider rewriting the if chain to use cmp and match. = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain

aleksator

comment created time in 2 days

PullRequestReviewEvent

Pull request review commentpubgrub-rs/pubgrub

refactor!: define Dependencies type

 pub fn resolve<P: Package, V: Version>(     } } +/// An enum used by [DependencyProvider] that holds information about package dependencies.+/// For each [Package] there is a [Range] of concrete versions it allows as a dependency.+#[derive(Clone)]+pub enum Dependencies<P: Package, V: Version> {+    /// Package dependencies are unavailable.+    Unavailable,+    /// Container for all available package versions.+    Known(AllowedVersions<P, V>),+}++/// Subtype of [Dependencies] which holds information about+/// all possible versions a given package can accept.+/// There is a difference in semantics between an empty [Map<P, Range<V>>](crate::type_aliases::Map)+/// inside [AllowedVersions] and [Dependencies::Unavailable]:+/// the former means the package has no dependencies and it is a known fact,+/// while the latter means they could not be fetched by [DependencyProvider].+#[derive(Debug, Clone)]+#[cfg_attr(+    feature = "serde",+    derive(serde::Serialize, serde::Deserialize),+    serde(transparent)+)]+pub struct AllowedVersions<P: Package, V: Version>(Map<P, Range<V>>);

I'll sleep on the naming.

aleksator

comment created time in 4 days

PullRequestReviewEvent

pull request commentpubgrub-rs/pubgrub

refactor!: define Dependencies type

I globally like the refactor I think but not as much the names. I feel like AllowedVersions should in fact be Dependencies and Dependencies should be something else. I'll let you know if I think of a better name

Thanks! Naming is of course a subject for discussion, feel free to start a Zulip thread if you have any suggestions.

There reason why named it AllowedVersions rather than Dependencies was because the word "dependency" brings a picture of (package, exact_version) in my mind, and I wanted to indicate that it's not a final dependency, but a range of possible solutions.

aleksator

comment created time in 4 days

Pull request review commentpubgrub-rs/pubgrub

refactor!: define Dependencies type

 pub fn resolve<P: Package, V: Version>(                 version: v.clone(),                 source: err,             })? {-            None => {+            Unavailable => {

Agree, will change.

aleksator

comment created time in 4 days

PullRequestReviewEvent

Pull request review commentpubgrub-rs/pubgrub

refactor!: define Dependencies type

 use std::collections::BTreeSet as Set; use std::error::Error; use std::hash::Hash;+use std::iter::FromIterator;  use crate::error::PubGrubError; use crate::internal::core::State; use crate::internal::incompatibility::Incompatibility; use crate::internal::partial_solution::PartialSolution; use crate::package::Package; use crate::range::Range;+use crate::solver::Dependencies::{Known, Unavailable};

Yeah I made the same mistake in a sister PR, defining a type where I wanted to use it and not thinking more about general structure.

Where would you prefer it to be placed? Maybe a new dependency module, where we could move this and DependencyProvider?

aleksator

comment created time in 4 days

PullRequestReviewEvent
PullRequestReviewEvent

Pull request review commentpubgrub-rs/pubgrub

refactor!: define Dependencies type

 pub trait DependencyProvider<P: Package, V: Version> { #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", serde(transparent))] pub struct OfflineDependencyProvider<P: Package, V: Version + Hash> {-    dependencies: Map<P, Map<V, Map<P, Range<V>>>>,+    dependencies: Map<P, Map<V, AllowedVersions<P, V>>>,

This exact change wasn't due to type_complexity lint, but because it was a bit hard for me to keep that triple map structure in mind. Using newly introduced type here made it easier for me to understand at a glance.

But that may be just me.

aleksator

comment created time in 4 days

pull request commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

I've changed the last commit (moved PackageTerm to incompatibility.rs).

Would you prefer to have all of them squashed or kept separate? (squash merge vs rebase merge)

aleksator

comment created time in 4 days

Pull request review commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

 pub struct PartialSolution<P: Package, V: Version> {     memory: Memory<P, V>, } +pub type PackageTerm<P, V> = (P, Term<V>);

Alright. Thank you spotting this! I changed the last commit.

aleksator

comment created time in 4 days

PullRequestReviewEvent

push eventpubgrub-rs/pubgrub

Alex Tokarev

commit sha 3b0bb2e96cb2ecc4c12fe6d64ac7552f96567ab2

refactor: define PackageTerm type alias

view details

push time in 4 days

Pull request review commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

 pub struct PartialSolution<P: Package, V: Version> {     memory: Memory<P, V>, } +pub type PackageTerm<P, V> = (P, Term<V>);

No reason besides the return type of functions I was trying to simplify was in partial_solution.rs. I will move it to incompatibility.rs, it does make more sense there since it's used in Relation enum.

Are you fine with it being a type alias rather than a separate type? I have a commit where I had it extracted into a struct, let me know if you would prefer that :smile:

aleksator

comment created time in 4 days

PullRequestReviewEvent

pull request commentpubgrub-rs/pubgrub

refactor: apply Clippy suggestions

Lots of little things that each look good. This overall looks very good. I will try to revue one commit at time to ensure I like each thing.

Yeah they are all atomic. Let me know if this is too much and I should pull some things out of this PR like I did with #46.

aleksator

comment created time in 4 days

PR opened pubgrub-rs/pubgrub

refactor: apply Clippy suggestions

This PR alongside with https://github.com/pubgrub-rs/pubgrub/pull/46 fixes all Clippy suggestions in the current state of the repo. After both are merged, Clippy can be added to CI.

I've also took a liberty to clean up small TODOs.

+162 -106

0 comment

10 changed files

pr created time in 4 days

push eventpubgrub-rs/pubgrub

Alex Tokarev

commit sha 05e3d965f826e5e1bdd4326670d6cb0467526e00

refactor: apply trivial Clippy suggestions

view details

Alex Tokarev

commit sha 01351c20a1fabd730ad74178e2186a7679a14ca7

refactor: remove unneeded "pub" modifiers

view details

Alex Tokarev

commit sha c713e18245461b5a7223409e408503688beda904

refactor: cargo clippy --fix

view details

Alex Tokarev

commit sha 88c094df1834b4c057b8438d3790c0ec196bece3

refactor: rewrite if chain using cmp() and match

view details

Alex Tokarev

commit sha 298959dccebfed04b86bd3f404df9f29687fe1dc

feat: derive Default for OfflineDependencyProvider

view details

Alex Tokarev

commit sha 77209481d44e16d8481703b4c6e434c1d66c39ab

refactor: move imports into bench function Since imports in benches are only needed when compiled under "serde" feature flag, cargo does not recognize those as used if they are at module level when running "cargo fix".

view details

Alex Tokarev

commit sha 44e33ce9f154ecd5af1129a3fc89a8c043a9488d

refactor: extract AssignmentDepth struct

view details

Alex Tokarev

commit sha 5df8a4a3bed2f7f98d1932def80337034ff82661

refactor: define newtype DecisionLevel(u32)

view details

Alex Tokarev

commit sha 52a46756e0bb6e63f544924f875004497877f8d5

refactor: define AssignmentHistory

view details

Alex Tokarev

commit sha ae8d8ccc56b12b73532ddc37104d93197d17e6c0

refactor: define PackageTerm type alias

view details

push time in 4 days

push eventpubgrub-rs/pubgrub

Alex Tokarev

commit sha f8ad9385089b0419133672598261c602f14012bc

ci: check formatting and documentation (#31) * style: reformat CI files * ci: deduplicate CI workflows * style: rename CI workflows * ci: cache explicit cargo directories https://doc.rust-lang.org/cargo/guide/cargo-home.html recommends to cache only these directories from ~/.cargo: bin/ registry/index/ registry/cache/ git/db/ * ci: add Cargo version to the cache key * ci: use the latest stable Rust for testing * ci: check formatting * ci: check documentation builds without warnings * ci: use nightly compiler for generating docs * ci: cache documentation files * ci: run CI on master push * ci: run CI on schedule once a week * ci: remove ~/.cargo/bin from cache Since we don't use `cargo install` in our CI pipeline, this directory is going to be empty, so we might as well remove it from the cache.

view details

Jacob Finkelman

commit sha 055fbecd250a6f1b10a0d95f8c1a4efed342545c

test: port property tests from Cargo (#28) * test: add a mostly direct proptest port from Cargo * style: clean up * test: return OfflineDependencyProvider directly * test: add a first prop test * test: use ints instead of Strings to avoid expensive clones * test: check that algorithm is deterministic * test: port over prop_minimum_version_errors_the_same * test: port prop_removing_a_dep_cant_break * test: port prop_limited_independence_of_irrelevant_alternatives * test: port meta_test_deep_trees_from_strategy * ci: don't shrink on ci * feat: add a timeout * style: apply review suggestions * style: change license header to SPDX * docs: link to DependencyProvider.callback * style: proofread naming and comments * style: rename ReversedDependencyProvider * rename `callback` to `should_cancel` Co-authored-by: Alex Tokarev <aleksator@gmail.com>

view details

Eh2406

commit sha ec93c71ac290b977d82bd723990690b2b0ac094f

test: compare with a sat solver (#38)

view details

Matthieu Pizenberg

commit sha bf9d2872ec212e68bdec7bf6b2ba9b683b90f836

docs(readme): remove link to API docs of the dev branch (#42)

view details

Alex Tokarev

commit sha ad4f48e52af40e9d695b43907eede564465f4409

ci: check that commit messages follow project guidelines (#41)

view details

Jacob Finkelman

commit sha 0f5c913e1590a9cc48a622e98baf46a8087d8280

perf: precompute intersections (2x speedup) (#37) * perf: precompute intersections (2x speedup) * style: fix grammar in function names Co-authored-by: Alex Tokarev <aleksator@gmail.com>

view details

Alex Tokarev

commit sha 177e2df146c4bdd5816eb942749256d8993feb7b

refactor: apply small Clippy suggestions

view details

Alex Tokarev

commit sha f46c8361d5cf67b295c0dbc8ef560c2a2dfc4a56

refactor: remove unneeded "pub" modifiers

view details

Alex Tokarev

commit sha 959619a76969cfaa47fff7930c90a376662ba914

refactor: cargo clippy --fix

view details

Alex Tokarev

commit sha 7751dfb5faf2b25f4214c2a28324ee43e371228a

refactor: rewrite if chain using cmp() and match

view details

Alex Tokarev

commit sha c7e0901acfca583e8477278801b102f15f3146f1

feat: derive Default for OfflineDependencyProvider

view details

Alex Tokarev

commit sha 56037c5db6fc49cf463113bc17745cc2aead9b44

refactor: move imports into bench function Since imports in benches are only needed when compiled under "serde" feature flag, cargo does not recognize those as used if they are at module level when running "cargo fix".

view details

Alex Tokarev

commit sha 6b489f9949d1331f1cc45087dbd8b43c9e97fec5

refactor: extract AssignmentDepth struct

view details

Alex Tokarev

commit sha 50a713d3b3c35a00994f702ab27e044358597b4f

refactor: define newtype DecisionLevel(u32)

view details

Alex Tokarev

commit sha 3e2f53f34485e0762fd9f82d4a357061d00f3b2f

refactor: define AssignmentHistory

view details

Alex Tokarev

commit sha ceec95325103a099f768f3f1f2bb17110fcdc6d7

refactor: define PackageTerm type alias

view details

push time in 4 days

push eventpubgrub-rs/pubgrub

Alex Tokarev

commit sha c492803392d0dfed027857be8fbae8896a9d527b

refactor!: define Dependencies type

view details

Alex Tokarev

commit sha 9a27d0fc3800ec295c4eb224214d43db8c929114

ci: allow ! in commits to indicate breaking changes

view details

push time in 4 days

pull request commentpubgrub-rs/pubgrub

test: switch to criterion

I'll study criterion docs to give a proper review. They seem to have a book on the subject.

Just running the benchmark I was getting warnings that 10 seconds is not enough to collect enough samples, increasing the amount in this line fixed the problem:

    group.measurement_time(Duration::from_secs(10));

So far the benchmark seemed unstable, resulting in reports like -12% performance, +5%, etc from run to run without doing changes to the code. I wonder if we are measuring something else in addition to the algorithm, or is it that unstable on its own. I need to learn more about criterion before being able to answer that.

Another thought: We are disabling default test harness with the line harness = false as the docs recommend, noting that we should provide our own harness and disabling default one is required to avoid conflicts. I also need to check how it is defined and whether we do that in this PR.

Eh2406

comment created time in 4 days

pull request commentpubgrub-rs/pubgrub

test: switch to criterion

You are reading my mind! I wanted to suggest migration to criterion after reading more about its use cases (seems to be right for us). And here you are with an awesome pull request! :smile:

Eh2406

comment created time in 4 days

pull request commentpubgrub-rs/pubgrub

feat!: define Dependencies type

commitlint was failing the pipeline, because the the first commit had an exclamation mark to indicate a breaking change.
I found a workaround of extending config-conventional and pulling relevant parts from config-angular that we were using before, and used it in the second commit.

I have created an issue in their repository.

aleksator

comment created time in 4 days

issue openedconventional-changelog/commitlint

Messages with an exclamation mark after type ("feat!") fail with Angular config

Indicating breaking changes with ! after type does not work when extending Angular config, but should be possible according to Conventional Commits 1.0.0.

I'm using this project through the Github Action, which currently uses commitlint 9.0.1 under the hood.

Expected Behavior

Commit message like feat!: the message has an exclamation mark should pass the lint.

Current Behavior

Lint does not pass with the following error message:

⧗ input: feat!: the message has an exclamation mark ✖ subject may not be empty [subject-empty] ✖ type may not be empty [type-empty]

Affected packages

  • [ ] cli
  • [ ] core
  • [ ] prompt
  • [x] config-angular

Possible Solution

A workaround is to extend config-conventional instead. .commitlintrc.yml:

extends:
  - '@commitlint/config-conventional'

Since they are different, desired rules from config-angular have to also be defined below, but they are not relevant to this bug so they have been omitted.

A proper solution would be to fix this in commitlint.

Steps to Reproduce (for bugs)

  1. In the repository root create file: .commitlintrc.yml:
extends:
  - '@commitlint/config-angular'
  1. Enable Github Actions with the following configuration: .github/workflows/ci.yml:
name: CI
on:
  pull_request:
  push:

jobs:
  check_commit_conventions:
    name: Check commit conventions
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - name: Check commit conventions
        uses: wagoid/commitlint-github-action@v2
        with:
          configFile: .commitlintrc.yml
          failOnWarnings: true
  1. Push a commit with an exclamation mark and check CI pipeline.

A commenter from another issue faced problems with the version 9.0.1 as well, although he had them with config-conventional, so it might be a separate problem.

created time in 4 days

push eventpubgrub-rs/pubgrub

Alex Tokarev

commit sha 9e0be101779f679c28787b2780e439db508de78a

ci: allow ! in commits to indicate breaking changes

view details

push time in 4 days

push eventpubgrub-rs/pubgrub

Alex Tokarev

commit sha a839cf5d0be90e759a17c6f9647455a991addf53

feat!: define Dependencies type

view details

Alex Tokarev

commit sha 32b02a42af61e3cb8d50943082742435207b316a

ci: allow ! in commits to indicate breaking changes

view details

push time in 4 days

push eventpubgrub-rs/pubgrub

Alex Tokarev

commit sha 9e15534bd40093941f19d92cddc398b32da3c671

ci!: test if ! works

view details

push time in 4 days

push eventpubgrub-rs/pubgrub

Alex Tokarev

commit sha 3c64aae8ccd4c705708b7536a7570c76a2fad687

ci!: test if ! works with default config

view details

push time in 4 days

create barnchpubgrub-rs/pubgrub

branch : test_ci

created branch time in 4 days

delete branch pubgrub-rs/pubgrub

delete branch : test_ci

delete time in 4 days

push eventpubgrub-rs/pubgrub

Alex Tokarev

commit sha e3c7440eb39bfc42e8b5f2585e89b8eb775d49ea

feat: define Dependencies type

view details

push time in 4 days

PR opened pubgrub-rs/pubgrub

feat!: define Dependencies type

This is a work I started doing while working on Clippy suggestions. I've extracted it into a separate PR since this affects the public API and is rather large on its own.

What I've done here was to extract a separate Dependencies type that is now returned from DependencyProvider. Before:

fn get_dependencies(...) -> Result<Option<Map<P, Range<V>>>, Box<dyn Error>>

After:

fn get_dependencies(...) -> Result<Dependencies<P, V>, Box<dyn Error>>

Doing this was suggested by type_complexity lint, which my first reaction was to just disable. After thinking more about it though, it actually did make sense for me to

  • Define our own enum here instead of Option. This encodes our intent in the type system and clarifies that the difference between None and an empty Map. It was mentioned in the docs, but I think it could be more easy glanced over while actually coding.
  • Clarify what this Map should contain using a newtype AllowedVersions with it's own documentation.

That's the substance, other changes just piled on to make the tests pass.

I see this as an ergonomics improvement and can't wait to hear your thoughts about it!

+128 -49

0 comment

6 changed files

pr created time in 5 days

more