Skip to content

Commit

Permalink
Remove a few other dyn Goal usages
Browse files Browse the repository at this point in the history
  • Loading branch information
tgecho committed Dec 29, 2023
1 parent 48dda87 commit eb000a4
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 26 deletions.
15 changes: 6 additions & 9 deletions canrun/src/goals/both.rs
Expand Up @@ -5,9 +5,9 @@ use crate::core::State;
A [Goal](crate::goals::Goal) that only succeeds if both sub-goals succeed. Create with [`both`].
*/
#[derive(Debug)]
pub struct Both {
a: Box<dyn Goal>,
b: Box<dyn Goal>,
pub struct Both<A: Goal, B: Goal> {
a: A,
b: B,
}

/**
Expand Down Expand Up @@ -41,14 +41,11 @@ let result: Vec<_> = goal.query(x).collect();
assert_eq!(result, vec![]) // Empty result
```
*/
pub fn both(a: impl Goal, b: impl Goal) -> Both {
Both {
a: Box::new(a),
b: Box::new(b),
}
pub fn both<A: Goal, B: Goal>(a: A, b: B) -> Both<A, B> {
Both { a, b }
}

impl Goal for Both {
impl<A: Goal, B: Goal> Goal for Both<A, B> {
fn apply(&self, state: State) -> Option<State> {
self.a.apply(state).and_then(|s| self.b.apply(s))
}
Expand Down
17 changes: 8 additions & 9 deletions canrun/src/goals/lazy.rs
Expand Up @@ -5,20 +5,18 @@ use crate::core::State;

use super::Goal;

type LazyFun = dyn Fn() -> Box<dyn Goal>;

/**
A [Goal](crate::goals::Goal) that is generated via callback just as
it is about to be evaluated. Create with [`lazy`].
*/
pub struct Lazy {
fun: Rc<LazyFun>,
pub struct Lazy<G: Goal> {
fun: Rc<dyn Fn() -> G>,
}

impl Debug for Lazy {
impl<G: Goal> Debug for Lazy<G> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Lazy")
.field("fun", &"Rc<dyn Fn() -> Box<dyn Goal>>")
.field("fun", &"Rc<dyn Fn() -> impl Goal>")
.finish()
}
}
Expand All @@ -44,14 +42,15 @@ let result: Vec<_> = goal.query(x).collect();
assert_eq!(result, vec![1])
```
*/
pub fn lazy<F>(fun: F) -> Lazy
pub fn lazy<F, G>(fun: F) -> Lazy<G>
where
F: (Fn() -> Box<dyn Goal>) + 'static,
G: Goal,
F: (Fn() -> G) + 'static,
{
Lazy { fun: Rc::new(fun) }
}

impl Goal for Lazy {
impl<G: Goal> Goal for Lazy<G> {
fn apply(&self, state: State) -> Option<State> {
let fun = &self.fun;
let goal = fun();
Expand Down
12 changes: 12 additions & 0 deletions canrun/src/goals/mod.rs
Expand Up @@ -82,3 +82,15 @@ impl Goal for Rc<dyn Goal> {
self.as_ref().apply(state)
}
}

impl<G: Goal> Goal for Rc<G> {
fn apply(&self, state: State) -> Option<State> {
self.as_ref().apply(state)
}
}

impl<G: Goal> Goal for Box<G> {
fn apply(&self, state: State) -> Option<State> {
self.as_ref().apply(state)
}
}
17 changes: 9 additions & 8 deletions canrun/src/goals/not.rs
Expand Up @@ -12,11 +12,11 @@ A [Goal](crate::goals::Goal) that only succeeds if the sub-goal is proved to alw
See [`not()`] for more details.
*/
#[derive(Debug)]
pub enum Not {
pub enum Not<G: Goal> {
/// A `Not` with a sub-goal that failed quickly at creation time
Fail,
/// A `Not` goal that needs further evaluation to see if it will succeed.
Maybe(Rc<NotConstraint>),
Maybe(Rc<NotConstraint<G>>),
}

/**
Expand Down Expand Up @@ -61,7 +61,7 @@ is able to conclusively prove or disprove the sub-goal.
All of this is not to discourage usage, but just to say that you should try to keep them
relatively simple and as precise as possible.
*/
pub fn not(goal: impl Goal) -> Not {
pub fn not<G: Goal>(goal: G) -> Not<G> {
// We run the subgoal in isolation right up front for two reasons...
let mut inner_states = goal.apply(State::new()).into_states().peekable();
if inner_states.peek().is_none() {
Expand All @@ -81,7 +81,7 @@ pub fn not(goal: impl Goal) -> Not {
}
}

impl Goal for Not {
impl<G: Goal> Goal for Not<G> {
fn apply(&self, state: State) -> Option<State> {
match self {
Not::Fail => Some(state),
Expand All @@ -96,18 +96,19 @@ impl Goal for Not {
}
}

/** A [`Not`] goal that needs to keep evaluating the state as variables are resolved. */
/** A [`Not`] goal that needs to keep evaluating the state as variables are
* resolved. */
#[derive(Debug)]
pub struct NotConstraint {
goal: Rc<dyn Goal>,
pub struct NotConstraint<G: Goal> {
goal: Rc<G>,
vars: LVarList,
}

fn any_succeed(state: Option<State>) -> bool {
state.into_states().next().is_some()
}

impl Constraint for NotConstraint {
impl<G: Goal> Constraint for NotConstraint<G> {
fn attempt(&self, state: &State) -> Result<ResolveFn, LVarList> {
// If the internal goal succeeded...
if any_succeed(self.goal.apply(state.clone())) {
Expand Down

0 comments on commit eb000a4

Please sign in to comment.