Work around for "cycle used when collecting item types"

I'm trying to write some code that I'll use in both with std and with no_std and I'm having a big of trouble with cycle used when collecting item types

Basically, I'm creating a scheduler. I want a trait Eval here, to identify an object that can be scheduled and can potentially schedule new objects when it is called. I'll also have a trait Scheudule that schedules an object that impl's Eval.

I'm trying to abstract the container that these objects are in, so that I can use Box with std and something else with no_std but I'm having trouble because I want to use a cyclic type to identify my container and I'm not sure how to design around this:
type Concrete = Box<dyn Eval<Concrete>>;

Any ideas?

My initial, failing attempt is here:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=bb64d2f5b2f2a1c852688be0cf01300b

... which is a generalization of something I can do if i just went with Box:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2429c281259ec427f45b1f768612a3b8

You could model it as such:

trait Task {
    type Callchain: Task = ();
    fn assign_task(&mut self, task_handler: ...);
}

impl Task for () {
    fn assign_task(&mut self, _: ...) {
        //Noop
    }
}

impl Task for Widget {
    type Callchain = Prompt;
    fn assign_task(&mut self, task_handler: ...) {
        task_handler.draw_widget_or_something();
        self.prompts.assign_task(task_handler);
    }
}

impl Task for Prompt {
    fn assign_task(&mut self, task_handler: ...) {
        task_handler.prompt_user();
        // ().assign_task(); //This is a noop
    }
}

So that then your "concrete" type can become something like so:

type Concrete = Box<dyn Task>; //Note that bounds on type aliases are ignored

Hmm, I'm not sure if that works here. Looks like a DAG and my design is more flat, generic container and a two cyclic traits built around that.

trait A<Container> {
  fn ex(&mut self, &dyn B<Container>);
}

trait B<Container>
where
    Container: DerefMut<Target = dyn A<Container>>,
{
  fn sched(&mut self, item: Container);
}

but either way I think i'll probably just use type aliases and change the alias based on the feature.

type Container<T> = Box<T>;

then i can just do something like:

trait A {
  fn ex(&mut self, &dyn B);
}

trait B {
  fn sched(&mut self, item: Container<dyn A>);
}

It doesn't work because you wrote it as a type alias. It works fine as a struct.

struct Concrete(Box<dyn Eval<Concrete>>);
1 Like