idanarye / woab

Widgets on Actors Bridge - a GUI microframework for combining GTK with Actix
https://crates.io/crates/woab
MIT License
14 stars 1 forks source link

Refactor the closure&context style to a builder style - Actix actor context into the #9

Closed idanarye closed 3 years ago

idanarye commented 3 years ago

See #4 for background. Tl;DR: we want to support this style:

fn main() {
    let builder = BuilderUtilizer::default();

    builder
        .actor()
        .connect_signals(Signal1::connector())
        .connect_signals(Signal2::connector())
        .run(Actor1 {
            widgets: builder.widgets().unwrap(),
        });

    builder
        .actor()
        .connect_signals(Signal3::connector())
        .connect_signals(Signal4::connector())
        .run(Actor2 {
            widgets: builder.widgets().unwrap(),
        });

    BuilderUtilizer::default()
        .actor::<Actor3>()
        .connect_signals(Signal1::connector())
        .connect_signals(Signal4::connector())
        .create(|ctx| Actor3 {
            my_own_address: ctx.address(),
            widgets: ctx.widgets().unwrap(),
        });
}
idanarye commented 3 years ago

Consider three actors, each holding the addresses of the other two. With the closure&context style creating them can get quite unsightly:

let builder = factory.instantiate();
builder.new_actor(|ctx1| {
    ctx1.connect_signals::<Signal1>();
    let mut addr3_ = None;
    let addr2 = builder.new_actor(|ctx2| {
        ctx2.connect_signals::<Signal2>();
        let addr3 = builder.new_actor(|ctx3| {
            ctx3.connect_signals::<Signal3>();
            Actor3 {
                actor1: ctx1.address(),
                actor2: ctx2.address(),
            }
        })
        addr3_ = Some(addr3.clone())
        Actor2 {
            actor1: ctx1.address(),
            actor3: addr3,
        }
    });
    Actor1 {
        actor2: addr2
        actor3: addr3_.unwrap(),
    }
});

But with the style I'm proposing here we can have this:

let builder = factory.instantiate();

let actor1 = builder.actor().connect_signals(Signal1::conector());
let actor2 = builder.actor().connect_signals(Signal2::conector());
let actor3 = builder.actor().connect_signals(Signal3::conector());

// actorN are actor builders, but they contain the actor contexts so we can easily get the
// addresses from them.
let addr1 = actor1.address();
let addr2 = actor2.address();
let addr3 = actor3.address();

actor1.run(Actor1 {
    actor2: addr2.clone(),
    actor3: addr3.clone(),
});
actor2.run(Actor2 {
    actor1: addr1.clone(),
    actor3: addr3,
});
actor3.run(Actor3 {
    actor1: addr1,
    actor2: addr2,
});
piegamesde commented 3 years ago

Is this a common use case? (I haven't built any actix actors that interact with each other yet.) But I see the point.

piegamesde commented 3 years ago

I don't think one can realize two actors that cross-reference each other using the current situation. I added a fn context(&self) -> &A::Context to ActorBuilder to get it working but I'm not sure if that is a good solution API wise.