Skip to content

Commit

Permalink
use enums and not boxes
Browse files Browse the repository at this point in the history
  • Loading branch information
rfuzzo committed Dec 8, 2023
1 parent ef93e6a commit 908b7a0
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 60 deletions.
62 changes: 54 additions & 8 deletions src/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,33 @@
/// EXPRESSIONS
////////////////////////////////////////////////////////////////////////

/// An expression such as EXISTS, ALL, ANY, NOT
pub trait Expression {
fn eval(&self, items: &[String]) -> bool;
fn as_expr(&self) -> EExpression;
}

#[derive(Clone)]
pub enum EExpression {
Atomic(Atomic),
ALL(ALL),
ANY(ANY),
NOT(NOT),
}

impl EExpression {
pub fn eval(&self, items: &[String]) -> bool {
match self {
EExpression::Atomic(atomic) => atomic.eval(items),
EExpression::ALL(all) => all.eval(items),
EExpression::ANY(any) => any.eval(items),
EExpression::NOT(not) => not.eval(items),
}
}
}

/// The atomic expression (EXISTS)
/// atomics evaluate as true if the input list contains the item
#[derive(Clone)]
pub struct Atomic {
pub item: String,
}
Expand All @@ -18,6 +38,10 @@ impl Expression for Atomic {
// TODO wildcards
items.contains(&self.item)
}

fn as_expr(&self) -> EExpression {
EExpression::Atomic(self.clone())
}
}
impl From<&str> for Atomic {
fn from(value: &str) -> Self {
Expand All @@ -32,11 +56,12 @@ impl From<String> for Atomic {

/// The ALL expression
/// ALL evaluates as true if all expressions evaluate as true
#[derive(Clone)]
pub struct ALL {
pub expressions: Vec<Box<dyn Expression>>,
pub expressions: Vec<EExpression>,
}
impl ALL {
pub fn new(expressions: Vec<Box<dyn Expression>>) -> Self {
pub fn new(expressions: Vec<EExpression>) -> Self {
Self { expressions }
}
}
Expand All @@ -52,15 +77,19 @@ impl Expression for ALL {
});
r
}
fn as_expr(&self) -> EExpression {
EExpression::ALL(self.clone())
}
}

/// The ANY expression
/// ANY evaluates as true if any expressions evaluates as true
#[derive(Clone)]
pub struct ANY {
pub expressions: Vec<Box<dyn Expression>>,
pub expressions: Vec<EExpression>,
}
impl ANY {
pub fn new(expressions: Vec<Box<dyn Expression>>) -> Self {
pub fn new(expressions: Vec<EExpression>) -> Self {
Self { expressions }
}
}
Expand All @@ -76,21 +105,38 @@ impl Expression for ANY {
});
r
}

fn as_expr(&self) -> EExpression {
EExpression::ANY(self.clone())
}
}

/// The NOT expression
/// NOT evaluates as true if the wrapped expression evaluates as true
pub struct NOT {
pub expression: Box<dyn Expression>,
pub expression: Box<EExpression>,
}

impl Clone for NOT {
fn clone(&self) -> Self {
Self {
expression: self.expression.clone(),
}
}
}
impl NOT {
pub fn new(expression: Box<dyn Expression>) -> Self {
Self { expression }
pub fn new(expression: EExpression) -> Self {
Self {
expression: Box::new(expression),
}
}
}
impl Expression for NOT {
// NOT evaluates as true if the wrapped expression evaluates as true
fn eval(&self, items: &[String]) -> bool {
!self.expression.eval(items)
}
fn as_expr(&self) -> EExpression {
EExpression::NOT(self.clone())
}
}
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub fn stable_topo_sort_inner(
let x = index_dict[result[i].as_str()];
let y = index_dict[result[j].as_str()];
if edges.contains(&(x, y)) {
let t = result[i].clone();
let t = result[i].to_owned();
result.remove(i);
result.insert(j, t);
return true;
Expand Down Expand Up @@ -58,7 +58,7 @@ pub fn topo_sort(mods: &Vec<String>, rules: &Rules) -> Result<Vec<String>, &'sta
}

// sort
let mut result: Vec<String> = mods.clone().iter().map(|e| (*e).to_owned()).collect();
let mut result: Vec<String> = mods.iter().map(|e| (*e).to_owned()).collect();
println!("{result:?}");
loop {
if !stable_topo_sort_inner(mods.len(), &edges, &index_dict, &mut result) {
Expand Down
12 changes: 6 additions & 6 deletions src/rules.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////
/// RULES
////////////////////////////////////////////////////////////////////////
use crate::expressions::Expression;
use crate::expressions::*;

#[derive(Default)]
pub struct Rules {
Expand Down Expand Up @@ -30,7 +30,7 @@ pub trait Rule {
/// Notes simply check the expression and notify the user if eval is true
pub struct Note {
pub comment: String,
pub expression: Box<dyn Expression>,
pub expression: EExpression,
}
impl Rule for Note {
fn get_kind(&self) -> RuleKind {
Expand All @@ -50,8 +50,8 @@ impl Rule for Note {
pub struct Conflict {
pub comment: String,
// todo: make first atomic?
pub expression_a: Box<dyn Expression>,
pub expression_b: Box<dyn Expression>,
pub expression_a: EExpression,
pub expression_b: EExpression,
}
impl Rule for Conflict {
fn get_kind(&self) -> RuleKind {
Expand All @@ -71,8 +71,8 @@ impl Rule for Conflict {
pub struct Require {
pub comment: String,
// todo: make first atomic?
pub expression_a: Box<dyn Expression>,
pub expression_b: Box<dyn Expression>,
pub expression_a: EExpression,
pub expression_b: EExpression,
}
impl Rule for Require {
fn get_kind(&self) -> RuleKind {
Expand Down
59 changes: 31 additions & 28 deletions tests/unit_expression_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ mod unit_expressions_tests {

// check that a and b exist in my load order
let mut expr = ALL::new(vec![
Box::new(Atomic::from("a")),
Box::new(Atomic::from("b")),
EExpression::Atomic(Atomic::from("a")),
EExpression::Atomic(Atomic::from("b")),
]);
assert!(expr.eval(&mods));

// check that a and x exist in my load order
expr = ALL::new(vec![
Box::new(Atomic::from("a")),
Box::new(Atomic::from("x")),
EExpression::Atomic(Atomic::from("a")),
EExpression::Atomic(Atomic::from("x")),
]);
assert!(!expr.eval(&mods)); // should fail
}
Expand All @@ -33,15 +33,15 @@ mod unit_expressions_tests {

// check that a or x exist in my load order
let mut expr = ANY::new(vec![
Box::new(Atomic::from("a")),
Box::new(Atomic::from("x")),
EExpression::Atomic(Atomic::from("a")),
EExpression::Atomic(Atomic::from("x")),
]);
assert!(expr.eval(&mods));

// check that x or y exist in my load order
expr = ANY::new(vec![
Box::new(Atomic::from("y")),
Box::new(Atomic::from("x")),
EExpression::Atomic(Atomic::from("y")),
EExpression::Atomic(Atomic::from("x")),
]);
assert!(!expr.eval(&mods)); // should fail
}
Expand All @@ -54,11 +54,11 @@ mod unit_expressions_tests {
.collect();

// check that x is not present in my load order
let mut expr = NOT::new(Box::new(Atomic::from("x")));
let mut expr = NOT::new(EExpression::Atomic(Atomic::from("x")));
assert!(expr.eval(&mods));

// check that a is not present in my load order
expr = NOT::new(Box::new(Atomic::from("a")));
expr = NOT::new(EExpression::Atomic(Atomic::from("a")));
assert!(!expr.eval(&mods)); // should fail
}

Expand All @@ -72,47 +72,50 @@ mod unit_expressions_tests {
// check that (a and x) are not present in the modlist
{
let nested = ALL::new(vec![
Box::new(Atomic::from("a")),
Box::new(Atomic::from("x")),
EExpression::Atomic(Atomic::from("a")),
EExpression::Atomic(Atomic::from("x")),
]);
let expr = NOT::new(Box::new(nested));
let expr = NOT::new(nested.as_expr());
assert!(expr.eval(&mods));
}
// check that (a and b) are not present in the modlist
{
let nested = ALL::new(vec![
Box::new(Atomic::from("a")),
Box::new(Atomic::from("b")),
EExpression::Atomic(Atomic::from("a")),
EExpression::Atomic(Atomic::from("b")),
]);
let expr = NOT::new(Box::new(nested));
let expr = NOT::new(nested.as_expr());
assert!(!expr.eval(&mods)); // should fail
}

// check that (a and b) are present and that either (x and y) are not present
{
let nested1 = ALL::new(vec![
Box::new(Atomic::from("a")),
Box::new(Atomic::from("b")),
EExpression::Atomic(Atomic::from("a")),
EExpression::Atomic(Atomic::from("b")),
]);
let nested2 = NOT::new(Box::new(ANY::new(vec![
Box::new(Atomic::from("x")),
Box::new(Atomic::from("y")),
])));
let expr = ALL::new(vec![Box::new(nested1), Box::new(nested2)]);
let nested2 = NOT::new(
ANY::new(vec![
EExpression::Atomic(Atomic::from("x")),
EExpression::Atomic(Atomic::from("y")),
])
.as_expr(),
);
let expr = ALL::new(vec![nested1.as_expr(), nested2.as_expr()]);
assert!(expr.eval(&mods));
}

// check that (a and b) are present and that either (f and y) are present
{
let nested1 = ALL::new(vec![
Box::new(Atomic::from("a")),
Box::new(Atomic::from("b")),
EExpression::Atomic(Atomic::from("a")),
EExpression::Atomic(Atomic::from("b")),
]);
let nested2 = ANY::new(vec![
Box::new(Atomic::from("f")),
Box::new(Atomic::from("y")),
EExpression::Atomic(Atomic::from("f")),
EExpression::Atomic(Atomic::from("y")),
]);
let expr = ALL::new(vec![Box::new(nested1), Box::new(nested2)]);
let expr = ALL::new(vec![nested1.as_expr(), nested2.as_expr()]);
assert!(expr.eval(&mods));
}
}
Expand Down
22 changes: 11 additions & 11 deletions tests/unit_rules_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mod unit_rules_tests {
.iter()
.map(|e| Note {
comment: e.1.into(),
expression: Box::new(Atomic { item: e.0.into() }),
expression: EExpression::Atomic(Atomic { item: e.0.into() }),
})
.collect();

Expand All @@ -36,13 +36,13 @@ mod unit_rules_tests {

let rule1 = Conflict {
comment: "a conflicts with b".into(),
expression_a: Box::new(Atomic { item: "a".into() }),
expression_b: Box::new(Atomic { item: "b".into() }),
expression_a: EExpression::Atomic(Atomic { item: "a".into() }),
expression_b: EExpression::Atomic(Atomic { item: "b".into() }),
};
let rule2 = Conflict {
comment: "b conflicts with x".into(),
expression_a: Box::new(Atomic { item: "b".into() }),
expression_b: Box::new(Atomic { item: "x".into() }),
expression_a: EExpression::Atomic(Atomic { item: "b".into() }),
expression_b: EExpression::Atomic(Atomic { item: "x".into() }),
};
let rules: Vec<Conflict> = vec![
rule1, // a conflicts with a
Expand Down Expand Up @@ -70,20 +70,20 @@ mod unit_rules_tests {
// a requires b
Require {
comment: "a requires b".into(),
expression_a: Box::new(Atomic { item: "a".into() }),
expression_b: Box::new(Atomic { item: "b".into() }),
expression_a: EExpression::Atomic(Atomic { item: "a".into() }),
expression_b: EExpression::Atomic(Atomic { item: "b".into() }),
},
// b requires x
Require {
comment: "b requires x".into(),
expression_a: Box::new(Atomic { item: "b".into() }),
expression_b: Box::new(Atomic { item: "x".into() }),
expression_a: EExpression::Atomic(Atomic { item: "b".into() }),
expression_b: EExpression::Atomic(Atomic { item: "x".into() }),
},
// x requires y
Require {
comment: "x requires y".into(),
expression_a: Box::new(Atomic { item: "x".into() }),
expression_b: Box::new(Atomic { item: "y".into() }),
expression_a: EExpression::Atomic(Atomic { item: "x".into() }),
expression_b: EExpression::Atomic(Atomic { item: "y".into() }),
},
];

Expand Down
10 changes: 5 additions & 5 deletions tests/unit_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ mod unit_tests {
.iter()
.map(|e| Note {
comment: e.1.into(),
expression: Box::new(Atomic { item: e.0.into() }),
expression: EExpression::Atomic(Atomic { item: e.0.into() }),
})
.collect();

Expand All @@ -104,13 +104,13 @@ mod unit_tests {
let rules: Vec<Conflict> = vec![
Conflict {
comment: "some a".into(),
expression_a: Box::new(Atomic { item: "a".into() }),
expression_b: Box::new(Atomic { item: "b".into() }),
expression_a: EExpression::Atomic(Atomic { item: "a".into() }),
expression_b: EExpression::Atomic(Atomic { item: "b".into() }),
},
Conflict {
comment: "some b".into(),
expression_a: Box::new(Atomic { item: "b".into() }),
expression_b: Box::new(Atomic { item: "x".into() }),
expression_a: EExpression::Atomic(Atomic { item: "b".into() }),
expression_b: EExpression::Atomic(Atomic { item: "x".into() }),
},
];

Expand Down

0 comments on commit 908b7a0

Please sign in to comment.