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 support for conditional dependencies #101

Open
wants to merge 42 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
0586e74
initial commit for conditional dependencies support
prsabahrami Jan 17, 2025
0383bfc
Add the watched literals for conditional requirements
prsabahrami Jan 21, 2025
2e6d57b
move conditional requirements to a separate struct
prsabahrami Jan 21, 2025
995a2c3
minor fix
prsabahrami Jan 21, 2025
dd636d2
remove deprecated conditional requirement function from resolvo.h
prsabahrami Jan 21, 2025
eb4d253
add a map of conditional clauses to the DependencyProvider struct
prsabahrami Jan 22, 2025
451536e
add the conditional clauses to the DependencyProvider
prsabahrami Jan 22, 2025
a9fdad2
update decide function to iterate over the conditional clauses.
prsabahrami Jan 22, 2025
e62b91c
add new node types and labels for conditional edges int he conflict g…
prsabahrami Jan 22, 2025
db7ac8b
Fix the issues with current tests
prsabahrami Jan 22, 2025
766a1a6
fix cpp bindings and tests
prsabahrami Jan 22, 2025
69042a1
remove extra file
prsabahrami Jan 22, 2025
220fed0
lint fix
prsabahrami Jan 22, 2025
0426ba3
minor fix
prsabahrami Jan 24, 2025
b95b789
Revert "minor fix"
prsabahrami Jan 24, 2025
a63278a
minor fix
prsabahrami Jan 24, 2025
190cd8a
update tests in `tests/solver.rs`
prsabahrami Jan 24, 2025
9323767
remove extra snap
prsabahrami Jan 24, 2025
a13facf
update the tests
prsabahrami Jan 24, 2025
286801b
fix tests and added tracing to conditional operations
prsabahrami Jan 24, 2025
2155d6b
rename `Dependencies::conditional_requirement to `Dependencies::requi…
prsabahrami Jan 24, 2025
eaeaf42
implement conditions in `from_provider_async` function
prsabahrami Jan 24, 2025
43a0b6b
update `fn conditional` in `clause.rs`
prsabahrami Jan 24, 2025
7e0e1c6
Add a map from version sets to variable ids which hold the variables…
prsabahrami Jan 24, 2025
3ddb16c
Add the `version_sets_to_variables` map
prsabahrami Jan 24, 2025
07e13e3
add the parser for conditional reqs
prsabahrami Jan 27, 2025
6b441f9
rn fmt
prsabahrami Jan 27, 2025
6dd7455
run fmt
prsabahrami Jan 27, 2025
057989b
fix bug in the solver
prsabahrami Jan 27, 2025
ed14321
run fmt
prsabahrami Jan 27, 2025
28210b9
add tests and minor fixes in the conditional parser
prsabahrami Jan 28, 2025
f65436b
assert when no conditional candidates where found
prsabahrami Jan 28, 2025
dbb9843
update conditional clause generation
prsabahrami Jan 28, 2025
8cd35a9
use peekable on the iterator in conditional clause generation
prsabahrami Jan 28, 2025
997ae4d
switch from version set id to variable id in in conditional clauses t…
prsabahrami Jan 28, 2025
83770fb
fix clippy issue
prsabahrami Jan 28, 2025
c8687d8
add tests with more versions and to confirm the behaviour of the reso…
prsabahrami Jan 28, 2025
4f297cc
run fmt
prsabahrami Jan 28, 2025
7e1bd18
remove extra snapshot
prsabahrami Jan 28, 2025
bd787d5
Add tests to show the conflict graph
prsabahrami Jan 30, 2025
cd3c9a3
fix the conditionals' text printing
prsabahrami Jan 31, 2025
3d055c8
add the basic setup for having multiple conditionals in a clause
prsabahrami Feb 3, 2025
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
18 changes: 18 additions & 0 deletions cpp/include/resolvo.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "resolvo_internal.h"

namespace resolvo {
using cbindgen_private::ConditionalRequirement;
using cbindgen_private::Problem;
using cbindgen_private::Requirement;

Expand All @@ -24,6 +25,23 @@ inline Requirement requirement_union(VersionSetUnionId id) {
return cbindgen_private::resolvo_requirement_union(id);
}

/**
* Specifies a conditional requirement (dependency) of a single version set.
* A solvable belonging to the version set satisfies the requirement if the condition is true.
*/
inline ConditionalRequirement conditional_requirement_single(VersionSetId id) {
return cbindgen_private::resolvo_conditional_requirement_single(id);
}

/**
* Specifies a conditional requirement (dependency) of the union (logical OR) of multiple version
* sets. A solvable belonging to any of the version sets contained in the union satisfies the
* requirement if the condition is true.
*/
inline ConditionalRequirement conditional_requirement_union(VersionSetUnionId id) {
return cbindgen_private::resolvo_conditional_requirement_union(id);
}

/**
* Called to solve a package problem.
*
Expand Down
115 changes: 113 additions & 2 deletions cpp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,95 @@ impl From<SolvableId> for resolvo::SolvableId {
}
}

/// A wrapper around an optional version set id.
/// cbindgen:derive-eq
/// cbindgen:derive-neq
#[repr(C)]
#[derive(Copy, Clone)]
pub struct FfiOptionVersionSetId {
pub is_some: bool,
pub value: VersionSetId,
}

impl From<Option<resolvo::VersionSetId>> for FfiOptionVersionSetId {
fn from(opt: Option<resolvo::VersionSetId>) -> Self {
match opt {
Some(v) => Self {
is_some: true,
value: v.into(),
},
None => Self {
is_some: false,
value: VersionSetId { id: 0 },
},
}
}
}

impl From<FfiOptionVersionSetId> for Option<resolvo::VersionSetId> {
fn from(ffi: FfiOptionVersionSetId) -> Self {
if ffi.is_some {
Some(ffi.value.into())
} else {
None
}
}
}

impl From<Option<VersionSetId>> for FfiOptionVersionSetId {
fn from(opt: Option<VersionSetId>) -> Self {
match opt {
Some(v) => Self {
is_some: true,
value: v,
},
None => Self {
is_some: false,
value: VersionSetId { id: 0 },
},
}
}
}

impl From<FfiOptionVersionSetId> for Option<VersionSetId> {
fn from(ffi: FfiOptionVersionSetId) -> Self {
if ffi.is_some {
Some(ffi.value)
} else {
None
}
}
}

/// Specifies a conditional requirement, where the requirement is only active when the condition is met.
/// First VersionSetId is the condition, second is the requirement.
/// cbindgen:derive-eq
/// cbindgen:derive-neq
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ConditionalRequirement {
pub condition: FfiOptionVersionSetId,
pub requirement: Requirement,
}

impl From<resolvo::ConditionalRequirement> for ConditionalRequirement {
fn from(value: resolvo::ConditionalRequirement) -> Self {
Self {
condition: value.condition.into(),
requirement: value.requirement.into(),
}
}
}

impl From<ConditionalRequirement> for resolvo::ConditionalRequirement {
fn from(value: ConditionalRequirement) -> Self {
Self {
condition: value.condition.into(),
requirement: value.requirement.into(),
}
}
}

/// Specifies the dependency of a solvable on a set of version sets.
/// cbindgen:derive-eq
/// cbindgen:derive-neq
Expand Down Expand Up @@ -162,7 +251,7 @@ pub struct Dependencies {
/// A pointer to the first element of a list of requirements. Requirements
/// defines which packages should be installed alongside the depending
/// package and the constraints applied to the package.
pub requirements: Vector<Requirement>,
pub requirements: Vector<ConditionalRequirement>,

/// Defines additional constraints on packages that may or may not be part
/// of the solution. Different from `requirements`, packages in this set
Expand Down Expand Up @@ -475,7 +564,7 @@ impl<'d> resolvo::DependencyProvider for &'d DependencyProvider {

#[repr(C)]
pub struct Problem<'a> {
pub requirements: Slice<'a, Requirement>,
pub requirements: Slice<'a, ConditionalRequirement>,
pub constraints: Slice<'a, VersionSetId>,
pub soft_requirements: Slice<'a, SolvableId>,
}
Expand Down Expand Up @@ -525,6 +614,28 @@ pub extern "C" fn resolvo_solve(
}
}

#[no_mangle]
#[allow(unused)]
pub extern "C" fn resolvo_conditional_requirement_single(
version_set_id: VersionSetId,
) -> ConditionalRequirement {
ConditionalRequirement {
condition: Option::<VersionSetId>::None.into(),
requirement: Requirement::Single(version_set_id),
}
}

#[no_mangle]
#[allow(unused)]
pub extern "C" fn resolvo_conditional_requirement_union(
version_set_union_id: VersionSetUnionId,
) -> ConditionalRequirement {
ConditionalRequirement {
condition: Option::<VersionSetId>::None.into(),
requirement: Requirement::Union(version_set_union_id),
}
}

#[no_mangle]
#[allow(unused)]
pub extern "C" fn resolvo_requirement_single(version_set_id: VersionSetId) -> Requirement {
Expand Down
16 changes: 9 additions & 7 deletions cpp/tests/solve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,17 @@ struct PackageDatabase : public resolvo::DependencyProvider {
/**
* Allocates a new requirement for a single version set.
*/
resolvo::Requirement alloc_requirement(std::string_view package, uint32_t version_start,
uint32_t version_end) {
resolvo::ConditionalRequirement alloc_requirement(std::string_view package,
uint32_t version_start,
uint32_t version_end) {
auto id = alloc_version_set(package, version_start, version_end);
return resolvo::requirement_single(id);
return resolvo::conditional_requirement_single(id);
}

/**
* Allocates a new requirement for a version set union.
*/
resolvo::Requirement alloc_requirement_union(
resolvo::ConditionalRequirement alloc_requirement_union(
std::initializer_list<std::tuple<std::string_view, uint32_t, uint32_t>> version_sets) {
std::vector<resolvo::VersionSetId> version_set_union{version_sets.size()};

Expand All @@ -69,7 +70,7 @@ struct PackageDatabase : public resolvo::DependencyProvider {

auto id = resolvo::VersionSetUnionId{static_cast<uint32_t>(version_set_unions.size())};
version_set_unions.push_back(std::move(version_set_union));
return resolvo::requirement_union(id);
return resolvo::conditional_requirement_union(id);
}

/**
Expand Down Expand Up @@ -219,7 +220,8 @@ SCENARIO("Solve") {
const auto d_1 = db.alloc_candidate("d", 1, {});

// Construct a problem to be solved by the solver
resolvo::Vector<resolvo::Requirement> requirements = {db.alloc_requirement("a", 1, 3)};
resolvo::Vector<resolvo::ConditionalRequirement> requirements = {
db.alloc_requirement("a", 1, 3)};
resolvo::Vector<resolvo::VersionSetId> constraints = {
db.alloc_version_set("b", 1, 3),
db.alloc_version_set("c", 1, 3),
Expand Down Expand Up @@ -263,7 +265,7 @@ SCENARIO("Solve Union") {
"f", 1, {{db.alloc_requirement("b", 1, 10)}, {db.alloc_version_set("a", 10, 20)}});

// Construct a problem to be solved by the solver
resolvo::Vector<resolvo::Requirement> requirements = {
resolvo::Vector<resolvo::ConditionalRequirement> requirements = {
db.alloc_requirement_union({{"c", 1, 10}, {"d", 1, 10}}),
db.alloc_requirement("e", 1, 10),
db.alloc_requirement("f", 1, 10),
Expand Down
Loading
Loading