kyren / piccolo

An experimental stackless Lua VM implemented in pure Rust
Creative Commons Zero v1.0 Universal
1.68k stars 63 forks source link

Async callbacks #19

Closed Ekleog closed 4 months ago

Ekleog commented 5 years ago

Hello,

I have just been pointed to this repository, as I'm currently investigating scripting languages accessible from rust that would support builtins that return -> impl Future<Output = TheActualResult> (and thus have all lua functions when accessed from rust that would implicitly return -> impl Future<Output = TheActualResult>) in a way that would be transparent to the scripted language, for the configuration file of a server I'm writing.

Until now, the only language I had found that matched this property was gluon, but going with a brand new scripting language makes me uneasy, as users would have to learn it in addition to understanding how my server works.

So I wonder, is async builtins / callbacks being transparently “async'd” through the lua call stack until the initial rust caller something you are considering for luster?

Cheers, and good luck with this rewrite! Leo

kyren commented 5 years ago

Hm, maaaaybe, but using luster for anything serious is probably a ways off. I dunno, I'd have to think about exactly how to do it.

I think after luster is more usable and has a working userdata story, you could kind of do this without specific support in luster by taking advantage of the stackless nature. You'd need to have callbacks call something that sets up some state in a userdata, then the Sequence would pause, and on every sequence step you'd have to check for that waiting state to be set. Once it is set, you could wait on the condition to be fulfilled before resuming stepping the sequence?

This works because there's a whole lot of overlap between Sequences and Futures, so they give you some of the same abilities, they just have to be different due to lifetimes and threading the garbage collector context.

Is that the sort of thing you were thinking? I know that definitely isn't automatic, but you could maybe build something automatic off of that.

Ekleog commented 5 years ago

Hmm so I'm not sure what Sequences exactly describe in luster (I haven't actually tried to read the implementation yet, still being in the exploratory phase). If I understand correctly, the process would be similar to:

If that is indeed approximately what you mean, then I think it'd be possible to wrap a library over this model so that it could be transparently be used as async, and thus that this issue will solve itself then!

Thank you for your answer, and sorry if I'm misunderstanding something for lack of knowledge of luster's internals. As for luster not being ready, don't worry, my project is very far from being ready too! hopefully we'll manage to get to something usable approximately simultaneously :)

kyren commented 4 months ago

This is an extremely old issue, but I never responded to the question because this was about when I stopped working on the project for four years. I'm going through old PRs / issues right now.

When wanting to call a Lua function asynchronously:

  • “Call” the function on the Lua VM, this gives back a Sequence to be executed
  • Step-forward the Sequence, this processes the Lua code until the first builtin call
  • Try to asynchronously perform the builtin call, if it isn't ready, keep the paused Sequence and propagate not-readiness upwards to the (rust) caller
  • When it is ready, step-forward the Sequence again with the result of the builtin call, and go back to above point

This is actually exactly how you would do it. Nowadays, you would specifically use Fuel::interrupt to cause the Executor::step driving Lua code to immediately return to Rust, (after registering some waker somewhere, or in some other way propagating unreadiness). I should make an example of this and put it somewhere...