Code Monkey home page Code Monkey logo

Comments (6)

veniamin-ilmer avatar veniamin-ilmer commented on May 22, 2024 1

Thank you for your response. After much thought, and testing with your examples, I am going ahead and rebuilding my emulator to use your framework.
Your functions/macros seem to magically make the Rust finally do what I have been trying to get it to do for the past week.
I will continue to treat the macros as magical and will try to expand and use them to the best of my ability. I will let you know if anything comes up.
Thank you.

from stakker.

veniamin-ilmer avatar veniamin-ilmer commented on May 22, 2024

After some reflection, I realized a way you could use FnOnce as a message.

In the timer example, the timer chip could have an FnOnce which calls a motherboard's function TimerElapsed(timer_id). Doing it this indeed sounds more efficient because you can avoid matching on an enum message.

However I recognize a problem with this design: It requires the motherboard's functions to be defined consistently.

Just like I want the chips to be replaceable, I want the Motherboard to be replaceable too. Not all messages need to be read. Some motherboards will route the timer chip. Some won't. I can't think of a way to handle this situation with FnOnce. I might be forced to revert to using enum.

from stakker.

uazu avatar uazu commented on May 22, 2024

The approach used by Stakker is instead of having enums to express the messages, the messages are actually just methods on the actor structure. So instead of having Msg::GetMemoryByte, you'd have fn get_memory_byte(&mut self, cx: CX![], addr: usize, ret: Ret<u8>) {...}. Then you could call it with call!([motherboard], get_memory_byte(0x100, ret_some_to!(...)));. The ret_some_to! macro (or other ret_* macro) expresses what should happen when you get a response back (since it is asynchronous).

I think it is okay to hard-code the method names, since you are also hard-coding the enum names -- so it is about the same. If you need to switch out the Motherboard, you could do that with compile-time #[cfg(...)] switches, e.g. based on features.

However if you really don't want everything fixed at compile-time (e.g. if you want to switch between different motherboards at runtime rather than compile-time), then you could do it all with Fwd references. Alternatively you could use traits instead. There is a page on using traits or Fwd for this in the guide.

The business with FnOnce is that all messages are handled with FnOnce internally, but in user code, it looks like function calls on the destination object (although with slightly different syntax and wrapped in a macro like call! or whatever). So the macro and the methods it calls take care of creating the FnOnce. However if you're using Fwd, you have complete flexibility to point calls at anything you like. For example the motherboard could give some other chip a direct link to the timer chip, e.g. the Fwd doesn't need to send the message via the motherboard at all. And alternatively when the timer chip is not implemented, that could be a fwd_nop!.

Let me know if this makes sense. I'm happy to answer more questions.

from stakker.

veniamin-ilmer avatar veniamin-ilmer commented on May 22, 2024

Do you have any suggestions how to best declare actors which have a circular reference?

For example, the Motherboard saves a reference to all of the chips, but all of the chips also have a reference to the motherboard. If I declare all of the chips first, then I might have to have an Optional field in all of the chips for the motherboard originally set to None. After motherboard gets declared, then all chips would need to be change their reference to Some(motherboard). Please let me know if there is a better way for me to handle cyclical references within the Actors.

from stakker.

uazu avatar uazu commented on May 22, 2024

This can be done using actor_new!. It is designed exactly for this situation. So you create all your actors using actor_new!, which gives you actor references, then you initialise all your actors with explicit calls to their init methods, passing in cloned references to the other actors (or Fwd instances referring to the other actors, or whatever). See the docs for actor_new!.

I'm just about to travel away for a couple of days. I'll be back online on Sunday if you have any more questions.

from stakker.

veniamin-ilmer avatar veniamin-ilmer commented on May 22, 2024

Thank you very much, and please don't feel obliged to answer my questions quickly!

from stakker.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.